[2.x] Using `:xt/table` to retain 1.x triple behaviour

(from @theronic on Slack - thanks!)

Would it have been possible to retain v1 semantics and add v2 capabilities by adding an [?e :xt/table :table-name] where clause to v1 queries?

Hey @theronic, great question :slightly_smiling_face:

We did initially go with this when we introduced the tables to v2, but unfortunately the semantics of the ?e variable became less clear when we considered the possibilities of across-time queries. In v1, because we only have point-in-time queries, it’s well-defined that ?e represents the value of the entity id (eid), s.t. if it’s repeated in queries (either in entity position, to essentially group triples for that entity, or value position, to use the PK to join another entity) we know to unify on that value, and it unambiguously refers to one version of one document.

Once we introduced both tables and across-time queries, though, we needed a way to refer to this document version, rather than the eid value (the SQL spec calls this the ‘correlation name’ - the f in SELECT f.a, f.b FROM foo f FOR SYSTEM_TIME AS OF ...).

With tables, documents from different tables can share an eid - i.e. it would have been reasonable to request something like the following:

;; not valid XT syntax
{:find ...
 :where [[?e :xt/table :foo]
         [?e :a ?a]
         [?e :b ?b]

         ;; but now say I also want to reference 
         ;; another table that shares the eid
         [?e :xt/table :bar]
         [?e :c ?c]]}

Similarly, for across time queries, if I want to represent a question like ‘who was here in both 2018 and 2023?’:

;; also not valid XT syntax
{:find ...
 :where [[?e :xt/table :people]
         [?e :valid-at #inst "2018"]

         ;; but now say I also want to reference
         ;; the same table at a different valid-time
         [?e :xt/table :people]
         [?e :valid-at #inst "2023"]]}

We could have changed the semantics of ?e to refer to the row instead (and require [?e :xt/id ?eid] to unify on the eid) - but this would be a much more subtle breaking change for people used to either v1 or other EDN Datalog databases - generally speaking, we particularly try to avoid things looking the same but behaving differently (even if it’s not from our database!) - so instead we opted for something much more obviously different, at a tradeoff of requiring a bigger migration for v1 users.

for comparison, the two above queries look like these in v2:

{:find [a b c]
 :where [($ :foo [{:xt/id eid} a b])
         ($ :bar [{:xt/id eid} c])]}
{:find [...]
 :where [($ :people [{:xt/id eid}]
            {:for-valid-time [:at #inst "2018"]})
         ($ :people [{:xt/id eid}]
            {:for-valid-time [:at #inst "2023"]})]}

we needed a way to refer to this document version

so the $/‘match’ syntax is exactly this - one clause refers to one version of one document in one table

(of course, if we’ve missed a trick, please let us know - it’s not too late for us to do something about it :slightly_smiling_face:)