Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions impl/query_where.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1184,18 +1184,21 @@ end) = struct
then
None
else
let value_var_patterns, constant_patterns, required_patterns =
let* value_var_patterns, constant_patterns, required_patterns =
patterns
|> List.fold_left
(fun (value_vars, constants, required) (_, attr, value_term) ->
match value_term with
| QVar value_var when value_var <> e_var ->
((value_var, attr) :: value_vars, constants, required)
| QValue value -> (value_vars, (attr, value) :: constants, required)
| QWildcard -> (value_vars, constants, attr :: required)
| QVar _ | QEntity _ | QAttr _ | QIdent _ | QLookupRef _ | QSource _ ->
(value_vars, constants, required))
([], [], [])
(fun acc (_, attr, value_term) ->
match acc, value_term with
| Some (value_vars, constants, required), QVar value_var when value_var <> e_var ->
Some ((value_var, attr) :: value_vars, constants, required)
| Some (value_vars, constants, required), QValue value ->
Some (value_vars, (attr, value) :: constants, required)
| Some (value_vars, constants, required), QWildcard ->
Some (value_vars, constants, attr :: required)
| None, _
| Some _, (QVar _ | QEntity _ | QAttr _ | QIdent _ | QLookupRef _ | QSource _) ->
None)
(Some ([], [], []))
in
let duplicate_value_var =
let seen = Hashtbl.create (List.length value_var_patterns) in
Expand Down
31 changes: 31 additions & 0 deletions test/test_query_engine_fixes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,36 @@ let test_collection_in_binding () =
(q_string ~inputs:[ Arg_collection [ Result_value (Int64 1L); Result_value (Int64 3L) ] ] db
"[:find ?e :in $ [?x ...] :where [?e :attr ?x]]")

let test_singleton_ref_collection_keeps_pattern_constraints () =
let schema =
schema_of_edn_string
"{:block/tags {:db/valueType :db.type/ref :db/cardinality :db.cardinality/many}}"
in
let db =
empty_db ~schema ()
|> db_with_string
"[{:db/id 1 :block/uuid \"untagged\"}
{:db/id 2 :block/uuid \"other-tag\" :block/tags [100]}
{:db/id 3 :block/uuid \"card\" :block/tags [200]}]"
in
List.iter
(fun (label, tags, expected) ->
assert_rows label expected
(q_string db
"[:find [?b ...] :in $ [?t ...] ?now-inst-ms %
:where [?b :block/tags ?t] [?b :block/uuid]]"
~inputs:
[ Arg_collection tags
; Arg_scalar (Result_value (Int64 0L))
; Arg_rules []
]))
[ "singleton ref keeps the tag constraint", [ Result_entity 200 ], [ [ Result_entity 3 ] ]
; "missing ref returns no entities", [ Result_entity 201 ], []
; "multiple refs keep the tag constraint", [ Result_entity 200; Result_entity 201 ], [ [ Result_entity 3 ] ]
; "ref values preserve the same result", [ Result_value (Ref 200) ], [ [ Result_entity 3 ] ]
; "empty input returns no entities", [], []
]

(* Bug 2 extended: comparison predicates over :in-bound vars *)
let test_comparison_predicates_over_in () =
let db =
Expand Down Expand Up @@ -1068,6 +1098,7 @@ let () =
; "rule_joined_with_clauses", test_rule_joined_with_clauses
; "predicate_over_in_scalar", test_predicate_over_in_scalar
; "collection_in_binding", test_collection_in_binding
; "singleton_ref_collection_keeps_pattern_constraints", test_singleton_ref_collection_keeps_pattern_constraints
; "comparison_predicates_over_in", test_comparison_predicates_over_in
; "predicate_over_collection_in", test_predicate_over_collection_in
; "entity_map_lookup_ref_earlier_tx_entity", test_entity_map_lookup_ref_earlier_tx_entity
Expand Down
Loading