From a13caec31ff7ed58e9944edefc79ddeb390d6746 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 1 Nov 2024 11:21:15 -0700 Subject: [PATCH] don't allow nested preloads to attempt to relations that return non-table types --- lapis/db/model/relations.lua | 38 ++++++++++++++++++++++++++++------- lapis/db/model/relations.moon | 11 +++++++--- spec/relations_spec.moon | 30 +++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/lapis/db/model/relations.lua b/lapis/db/model/relations.lua index 7060a128..29a0ae5d 100644 --- a/lapis/db/model/relations.lua +++ b/lapis/db/model/relations.lua @@ -106,9 +106,7 @@ preload_homogeneous = function(sub_relations, model, objects, preload_spec, ...) preload_relation(model, objects, relation_name, preload_opts) if not (val_type == "boolean" or val_type == "function") then sub_relations = sub_relations or { } - local _update_0 = val - sub_relations[_update_0] = sub_relations[_update_0] or { } - local loaded_objects = sub_relations[val] + local loaded_objects = sub_relations[val] or { } if r.has_many or r.fetch and r.many then for _index_0 = 1, #objects do local _continue_1 = false @@ -120,8 +118,19 @@ preload_homogeneous = function(sub_relations, model, objects, preload_spec, ...) end local _list_0 = obj[relation_name] for _index_1 = 1, #_list_0 do - local fetched = _list_0[_index_1] - table.insert(loaded_objects, fetched) + local _continue_2 = false + repeat + local fetched = _list_0[_index_1] + if not (type(fetched) == "table") then + _continue_2 = true + break + end + table.insert(loaded_objects, fetched) + _continue_2 = true + until true + if not _continue_2 then + break + end end _continue_1 = true until true @@ -131,10 +140,25 @@ preload_homogeneous = function(sub_relations, model, objects, preload_spec, ...) end else for _index_0 = 1, #objects do - local obj = objects[_index_0] - table.insert(loaded_objects, obj[relation_name]) + local _continue_1 = false + repeat + local obj = objects[_index_0] + local fetched = obj[relation_name] + if not (type(fetched) == "table") then + _continue_1 = true + break + end + table.insert(loaded_objects, fetched) + _continue_1 = true + until true + if not _continue_1 then + break + end end end + if next(loaded_objects) and not sub_relations[val] then + sub_relations[val] = loaded_objects + end end end _continue_0 = true diff --git a/lapis/db/model/relations.moon b/lapis/db/model/relations.moon index 34acd37b..62e139e3 100644 --- a/lapis/db/model/relations.moon +++ b/lapis/db/model/relations.moon @@ -107,18 +107,23 @@ preload_homogeneous = (sub_relations, model, objects, preload_spec, ...) -> -- Ignore the val_types that we know can not contain nested relations unless val_type == "boolean" or val_type == "function" sub_relations or= {} - sub_relations[val] or= {} - loaded_objects = sub_relations[val] + loaded_objects = sub_relations[val] or {} -- grab all the loaded objects to process if r.has_many or r.fetch and r.many for obj in *objects continue unless obj[relation_name] -- if the preloader didn't insert array then just skip for fetched in *obj[relation_name] + continue unless type(fetched) == "table" table.insert loaded_objects, fetched else for obj in *objects - table.insert loaded_objects, obj[relation_name] + fetched = obj[relation_name] + continue unless type(fetched) == "table" + table.insert loaded_objects, fetched + + if next(loaded_objects) and not sub_relations[val] + sub_relations[val] = loaded_objects when "string" -- preload_spec is simply the name of the relation to preload diff --git a/spec/relations_spec.moon b/spec/relations_spec.moon index 9b04e411..3489e9bc 100644 --- a/spec/relations_spec.moon +++ b/spec/relations_spec.moon @@ -1816,6 +1816,32 @@ describe "lapis.db.model.relations", -> [[SELECT * FROM "user_data" WHERE "user_id" IN (11, 12)]] }, sorted: true + it "preloads a fetch that returns basic value", -> + class Items extends Model + @relations: { + {"things", + many: true + fetch: => error "should not be called" + preload: (items, ...) -> + for item in *items + item.things = {true, true, false} + } + + + {"thing", + fetch: => error "should not be called" + preload: (items, ...) -> + for item in *items + item.thing = true -- store a boolean + } + } + + items = {Items!} + preload items, things: {}, thing: {} + assert.same {true, true, false}, items[1].things + assert.same true, items[1].thing + + it "passes preload opts to fetch relation", -> local preload_objects, preload_opts @@ -1823,7 +1849,7 @@ describe "lapis.db.model.relations", -> @relations: { {"things", many: true - fetch: => error "no fetch me" + fetch: => error "should not be called" preload: (...) -> preload_objects, preload_opts = ... } @@ -1846,7 +1872,7 @@ describe "lapis.db.model.relations", -> random: "option" }, preload_opts - it "with skip_included preload option", -> + it "with skip_included preload option #ddd", -> models.Items = class Items extends Model @relations: { {"parents", has_many: "Items", key: "parent_id"}