Problem
GetRecordFromTypeId (src/reflection.cc:36) looks up the record with operator[]:
auto& meta_struct = instance.records[type_id];
return meta_struct;
std::map::operator[] default-inserts an empty Reflection when the key is absent, so an unregistered or misspelled type returns a record with an empty name and no members instead of signalling an error.
Impact
Operating on an unknown type produces nonsense SQL (empty table name, no columns) that fails downstream with an opaque message, instead of a clear "type not registered" error. This is also inconsistent with Database::GetRecord (src/database.cc), which uses records.at(type_id) and throws on a miss.
Correction — GetRecordFromTypeId is dual-use; do NOT simply make it throw
The original suggested direction ("use .at() in GetRecordFromTypeId") is incomplete and would break registration. That function is called on TWO paths:
- Lookup (the buggy path) —
QueryPredicate constructor, include/query_predicates.h:83:
auto record = GetRecordFromTypeId(typeid(T).name()); — here a miss should FAIL.
- Create-on-registration — the generated
Register<REFLECTABLE>() in include/reflection.h:198
relies on operator[]'s default-insert to CREATE the entry before populating it:
auto isRecordRegisterd = instance.records.find(type_id) != instance.records.end();
if (!isRecordRegisterd) {
auto& reflectable = GetRecordFromTypeId(type_id); // must create the entry
reflectable.name = name;
... DEFINE_MEMBER ...
}
If GetRecordFromTypeId throws on miss, every registration throws and nothing works.
Corrected direction (two parts)
- Give registration its own explicit create path instead of leaning on
GetRecordFromTypeId's
side effect — e.g. in Register<REFLECTABLE>() use the in-scope instance.records[type_id]
directly (the surrounding find guard already scopes the create-on-miss to registration).
- Then make
GetRecordFromTypeId a pure lookup that fails fast: find + throw a clear
std::runtime_error naming the type when absent (<stdexcept> in src/reflection.cc).
After that, the only remaining caller of GetRecordFromTypeId is the query/lookup path, so an
unregistered type raises a clear error at the point of use. Confirm there are no other callers that
depend on the create-on-miss behavior (currently only Database::GetRecord looks up records, and it
already uses .at()).
Suggested direction (superseded — see Correction above)
Make the lookup consistent and fail-fast: use .at() (or an explicit find + throw) in
GetRecordFromTypeId. Correct in spirit, but must be paired with moving registration off that
function first, per the Correction section.
Problem
GetRecordFromTypeId(src/reflection.cc:36) looks up the record withoperator[]:std::map::operator[]default-inserts an emptyReflectionwhen the key is absent, so an unregistered or misspelled type returns a record with an empty name and no members instead of signalling an error.Impact
Operating on an unknown type produces nonsense SQL (empty table name, no columns) that fails downstream with an opaque message, instead of a clear "type not registered" error. This is also inconsistent with
Database::GetRecord(src/database.cc), which usesrecords.at(type_id)and throws on a miss.Correction —
GetRecordFromTypeIdis dual-use; do NOT simply make it throwThe original suggested direction ("use
.at()inGetRecordFromTypeId") is incomplete and would break registration. That function is called on TWO paths:QueryPredicateconstructor,include/query_predicates.h:83:auto record = GetRecordFromTypeId(typeid(T).name());— here a miss should FAIL.Register<REFLECTABLE>()ininclude/reflection.h:198relies on
operator[]'s default-insert to CREATE the entry before populating it:GetRecordFromTypeIdthrows on miss, every registration throws and nothing works.Corrected direction (two parts)
GetRecordFromTypeId'sside effect — e.g. in
Register<REFLECTABLE>()use the in-scopeinstance.records[type_id]directly (the surrounding
findguard already scopes the create-on-miss to registration).GetRecordFromTypeIda pure lookup that fails fast:find+ throw a clearstd::runtime_errornaming the type when absent (<stdexcept>insrc/reflection.cc).After that, the only remaining caller of
GetRecordFromTypeIdis the query/lookup path, so anunregistered type raises a clear error at the point of use. Confirm there are no other callers that
depend on the create-on-miss behavior (currently only
Database::GetRecordlooks up records, and italready uses
.at()).Suggested direction (superseded — see Correction above)
Make the lookup consistent and fail-fast: use
Correct in spirit, but must be paired with moving registration off that.at()(or an explicitfind+ throw) inGetRecordFromTypeId.function first, per the Correction section.