Allow sets of attributes in fulltext expressions. Fixes #54. r=nalexander

This commit is contained in:
Richard Newman 2016-09-26 14:19:41 -07:00
parent 32cd08ba13
commit 1296b8090f
3 changed files with 129 additions and 16 deletions

View file

@ -97,12 +97,36 @@
;; [(fulltext $ _ "foo") [[?x]]]
;;
;; so we instead have a placeholder attribute. Sigh.
attr-constant (or
(and (instance? Constant attr)
(not (= :any (:value attr)))
(source/attribute-in-source (:source cc) (:value attr)))
(and (instance? Variable attr)
(cc/binding-for-symbol-or-throw cc (:symbol attr))))
;; We also support sets of attributes, so you can write
;;
;; [(fulltext $ #{:foo/bar :foo/baz} "Noo") [[?x]]]
;;
;; which involves some tomfoolery here.
;;
;; TODO: exclude any non-fulltext attributes. If the set shrinks to nothing,
;; fail the entire pattern.
;; https://github.com/mozilla/datomish/issues/56
attr-constants (or
(and (instance? Constant attr)
(let [attr (:value attr)
intern (partial source/attribute-in-source (:source cc))]
(when-not (= :any attr)
(cond
(set? attr)
(map intern attr)
(or (keyword? attr)
(integer? attr))
(list (intern attr))
:else
(raise-str "Unknown fulltext attribute " attr {:attr attr})))))
(and (instance? Variable attr)
(cc/binding-for-symbol-or-throw cc (:symbol attr)))
;; nil, so it's seqable.
nil)
;; Pull out the symbols for the binding array.
[entity value tx score]
@ -127,16 +151,19 @@
wheres (concat
[[:match match-column match-value] ; The FTS match.
;; The fulltext rowid-to-datom correspondence.
[:=
(sql/qualify datom-alias :v)
(sql/qualify fulltext-alias :rowid)]]
;; The fulltext rowid-to-datom correspondence.
[:=
(sql/qualify datom-alias :v)
(sql/qualify fulltext-alias :rowid)]]
(when attr-constant
;; If known, the attribute itself must match.
[[:=
(sql/qualify datom-alias :a)
attr-constant]]))
;; If known, the attribute itself must match.
(when (seq attr-constants)
(let [a (sql/qualify datom-alias :a)
fragments (map (fn [v] [:= a v])
attr-constants)]
(if (seq (rest fragments))
[(cons :or fragments)]
fragments))))
;; Now compose any bindings for entity, value, tx, and score.
;; TODO: do we need to examine existing bindings to capture

View file

@ -109,6 +109,26 @@
:db/valueType :db.type/instant
:db/cardinality :db.cardinality/many}])
(def save-schema
[{:db/id (d/id-literal :db.part/user)
:db.install/_attribute :db.part/db
:db/cardinality :db.cardinality/one
:db/valueType :db.type/string
:db/fulltext true
:db/ident :save/title}
{:db/id (d/id-literal :db.part/user)
:db.install/_attribute :db.part/db
:db/cardinality :db.cardinality/one
:db/valueType :db.type/string
:db/fulltext true
:db/ident :save/excerpt}
{:db/id (d/id-literal :db.part/user)
:db.install/_attribute :db.part/db
:db/cardinality :db.cardinality/one
:db/valueType :db.type/string
:db/fulltext true
:db/ident :save/content}])
(def schema-with-page
(concat
simple-schema
@ -567,3 +587,40 @@
(query/options-into-context context 10 [[:date :asc]]))
[:order-by :limit]
)))))
(deftest-db test-parsing-fulltext conn
(let [attrs (<? (<initialize-with-schema conn save-schema))]
(is (= {:select (list [:datoms1.e :save]),
:modifiers [:distinct],
:from (list [:fulltext_values 'fulltext_values0]
[:datoms 'datoms1]),
:where (list :and
[:match :fulltext_values0.fulltext_values "something"]
[:= :datoms1.v :fulltext_values0.rowid]
[:= :datoms1.a (:save/title attrs)])}
(expand {:find '[?save]
:in '[$]
:where [[(list 'fulltext
'$
:save/title
"something")
'[[?save]]]]}
conn)))
(is (= {:select (list [:datoms1.e :save]),
:modifiers [:distinct],
:from (list [:fulltext_values 'fulltext_values0]
[:datoms 'datoms1]),
:where (list :and
[:match :fulltext_values0.fulltext_values "something"]
[:= :datoms1.v :fulltext_values0.rowid]
(list :or
[:= :datoms1.a (:save/title attrs)]
[:= :datoms1.a (:save/excerpt attrs)]))}
(expand {:find '[?save]
:in '[$]
:where [[(list 'fulltext
'$
#{:save/title :save/excerpt}
"something")
'[[?save]]]]}
conn)))))

View file

@ -127,7 +127,13 @@
:db/cardinality :db.cardinality/one
:db/valueType :db.type/string
:db/fulltext true
:db/ident :save/content}])
:db/ident :save/content}
{:db/id (d/id-literal :db.part/user)
:db.install/_attribute :db.part/db
:db/cardinality :db.cardinality/many
:db/valueType :db.type/string
:db/fulltext false
:db/ident :save/unindexed}])
(def tofino-schema (concat page-schema visit-schema session-schema save-schema))
@ -460,3 +466,26 @@
(is (= apricot-url "http://example.com/apricots/1"))
(is (= apricot-title "A page about apricots."))
(is (= apricot-excerpt "")))))))
(deftest-db test-fulltext-set-attribute conn
(<? (d/<transact! conn tofino-schema))
(<? (d/<transact! conn
[{:db/id 999
:save/title "Whenever you want something"}
{:db/id 998
:save/excerpt "If there is something…"}
{:db/id 997
:save/unindexed "What something means…"}
{:db/id 996
:save/title "This is anything but."}
{:db/id 995
:save/content "There's something here that would match."}]))
(let [results
(<?
(d/<q (d/db conn)
{:find '[?save]
:in '[$]
:where [[(list 'fulltext '$ #{:save/title :save/excerpt} "something")
'[[?save]]]]}))]
(is (= (set (map first results))
#{999 998}))))