Code Monkey home page Code Monkey logo

pathom-datomic's Introduction

Pathom Datomic

This package includes functions to integrate Datomic with Pathom Connect.

⚠️
Project in alpha state, need volunteers to try it out!

Also, this project uses the reader3 from Pathom, which also still needs production grade testing. I recommend this project for people trying to experiment and help the development of these new pieces, if you need production tested implementations its better to avoid pathom-datomic at this time.

Setup

Currently supported only with deps:

{:deps {com.wsscode/pathom-datomic {:git/url "https://github.com/wilkerlucio/pathom-datomic.git"
                                    :sha     "d1ebb8447342a7b1279dc23bc4ab9942a4d8171b"}}

Integration

Using this integration, you provide the Datomic connection to Pathom, then it loads your Datomic schema and delegates sub queries to Datomic automatically.

The examples in this documentation will be using the Datomic mbrainz sample database.

Example setup:

(ns com.wsscode.pathom.connect.datomic-test
  (:require [clojure.test :refer :all]
            [com.wsscode.pathom.connect :as pc]
            [com.wsscode.pathom.connect.datomic :as pcd]
            [com.wsscode.pathom.connect.datomic.on-prem :refer [on-prem-config]]
            [com.wsscode.pathom.core :as p]))

(def whitelist-attributes
  #{:artist/country
    :artist/gid
    :artist/name
    :artist/sortName
    :artist/type
    :country/name
    :medium/format
    :medium/name
    :medium/position
    :medium/trackCount
    :medium/tracks
    :release/artists
    :release/country
    :release/day
    :release/gid
    :release/labels
    :release/language
    :release/media
    :release/month
    :release/name
    :release/packaging
    :release/script
    :release/status
    :release/year
    :track/artists
    :track/duration
    :track/name
    :track/position})

(def parser
  (p/parser
    {::p/env     {::p/reader               [p/map-reader
                                            pc/reader3
                                            pc/open-ident-reader
                                            p/env-placeholder-reader]
                  ::p/placeholder-prefixes #{">"}}
     ::p/mutate  pc/mutate
     ::p/plugins [(pc/connect-plugin {::pc/register []})
                  ; (1)
                  (pcd/datomic-connect-plugin (assoc on-prem-config
                                                ::pcd/conn conn
                                                ::pcd/whitelist whitelist-attributes}))
                  p/error-handler-plugin
                  p/trace-plugin]}))
  1. Datomic connect integration plugin. The whilelist part is where you decide which attribute are going to be automatically available.

ℹ️
We are using the on-prem config for this tutorial, if you wanna connect using the client api, get the config from com.wsscode.pathom.connect.datomic.client/client-config

This setup will automatically provides entry points for every Datomic attribute marked with :unique true.

🔥
If you add :db/id to the whitelist, you can allow referencing using it, but be careful, if nothing else is done (via plugin or other way) to secure access, this means any user of the API could see any entity.

Example queries we can run:

(parser {}
  [{[:db/id 637716744120508]
    [:artist/name]}])
; => {[:db/id 637716744120508] {:artist/name "Janis Joplin"}}

(parser {}
    [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
      [:artist/name
       {:artist/country [:country/name]}]}])
; => {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
;     #:artist{:name "Janis Joplin"
;              :country #:country{:name "United States"}}}

When Pathom sees a Datomic attribute, it will compute the sub-query that should be delegated to Datomic, issue a single pull to fulfil the data, and them walk the results to fulfil any extra data that need to come from other resolvers.

To illustrate this point, let’s add a new resolver to the game and play with it in the query, this resolver will count the number of years that some artist was active, considering the start and end year data points:

(pc/defresolver years-active [env {:artist/keys [startYear endYear]}]
  {::pc/input  #{:artist/startYear :artist/endYear}
   ::pc/output [:artist/active-years-count]}
  {:artist/active-years-count (- endYear startYear)})

; then add it to the connect-plugin definition, as:
; (pc/connect-plugin {::pc/register [years-active]})

Time to play:

(parser {}
  [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
    [:artist/active-years-count]}])
; {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"] #:artist{:active-years-count 27}}

Notice that Pathom was able to automatically figure out the dependencies and compute the appropriated pull request, which in this case was [:artist/startYear :artist/endYear].

Datomic ident values

If you used the Datomic pull syntax, you know this kind of result:

(parser {}
  [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
    [:artist/type]}])
=>
; => {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"] #:artist{:type #:db{:id 17592186045423}}}

; if you are familiar with pull, you know the drill:
(parser {}
  [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
    [{:artist/type [:db/ident]}])
=>
; => {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"] #:artist{:type #:db{:ident :artist.type/person}}}

Not so good, even with the version we get the actual value :artist.type/person, we still have to unwrap that.

To facilitate this common scenario, you can configure the integration and tell Pathom which attributes should behave as ident attributes, this means if you don’t do a sub query on them, Pathom will request the :db/ident and unwrap automatically:

; just the changes to the datomic connect plugin:
(pcd/datomic-connect-plugin (assoc on-prem-config
                              ::pcd/conn conn
                              ::pcd/ident-attributes #{:artist/type}))

; now a different result
(parser {}
  [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
    [:artist/type]}])
=>
; => {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
       #:artist{:type :artist.type/person}}

; you can still get the entity data using a sub query:
(parser {}
  [{[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"]
    [{:artist/type [:db/id]}]}])
=>
; => {[:artist/gid #uuid"76c9a186-75bd-436a-85c0-823e3efddb7f"] #:artist{:type #:db{:id 17592186045423}}}

Custom queries

To handle custom sets of entities, we recommend using the helpers query-entity and query-entities, provided by this library, examples:

(pc/defresolver artists-before-1600 [env _]
  {::pc/output [{:artist/artists-before-1600 [:db/id]}]}
  {:artist/artists-before-1600
   (pcd/query-entities env
     '{:where [[?e :artist/name ?name]
               [?e :artist/startYear ?year]
               [(< ?year 1600)]]})})

; using the resolver
(parser {}
  [{:artist/artist-before-1600
    [:artist/name
     :artist/active-years-count
     {:artist/country
      [:country/name]}]}])
=>
; #:artist{:artist-before-1600 #:artist{:name "Heinrich Schütz",
;                                       :active-years-count 87,
;                                       :country #:country{:name "Germany"}}}

Note the Datalog query must use the map format. The :find part will be automatically fulfilled by Pathom, considering the sub query requested in the process, this way you don’t need to care ahead of time.

Opening all data

You can enable the integration to pull everything from Datomic, this can be useful on initial development, but be aware this opens the entire Datomic to the external world.

To do this, use ::pcd/whitelist ::pcd/DANGER_ALLOW_ALL!.

Next steps

We need to figure a way to handle security, currently this integration opens too much for most use cases, if you have ideas please let’s talk at #pathom on Clojurians!

pathom-datomic's People

Contributors

wilkerlucio avatar rafaeldff avatar cjsauer avatar souenzzo avatar eneroth avatar solussd avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.