Git Product home page Git Product logo

datomic-type-extensions's Introduction

Datomic type extensions

This Clojure library provides custom types for your Datomic attributes. It does this by wrapping a leaky abstraction around your regular Datomic API.

  • Add custom types by implementing the serialize, deserialize and get-backing-datomic-type multimethods in the datomic-type-extensions.types namespace.

  • Require [datomic-type-extensions.api :as d] instead of [datomic.api :as d].

  • When you d/connect the first time, a :dte/valueType attribute will be installed.

  • Assert :dte/valueType for your typed attributes. When transacting attribute definitions, the original :db/valueType will be added by looking it up in get-backing-datomic-type.

  • When using d/transact, d/transact-async or d/with, your typed attributes will be serialized before being passed to Datomic.

  • When using d/q, d/query, d/pull or d/pull-many, your typed attributes will be deserialized on the way out of Datomic.

  • Entities returned by d/entity will lazily deserialize their types.

Oh, the convenience!

Did you say leaky abstraction?

Oh yes. Let's look at some ways this abstraction leaks:

  • Database functions see serialized values.

  • Where-clauses in queries see serialized values.

  • Params to queries are not serialized for you.

  • Datoms (as returned by :tx-data, indexes, and the log) are not deserialized.

There might be more, but during several years of production use, these are the ones we have encountered.

Usage

Define a custom type:

(require '[datomic-type-extensions.types :as types])

(defmethod types/get-backing-datomic-type
  :java.time/instant [_]
  :db.type/instant)

(defmethod types/serialize
  :java.time/instant [_ ^Instant instant]
  (java.util.Date/from instant))

(defmethod types/deserialize
  :java.time/instant [_ ^java.util.Date inst]
  (Instant/ofEpochMilli (.getTime inst)))

If you're interested in storing java.time types in Datomic, use java-time-dte.

Then use the custom type:

(require '[datomic-type-extensions.api :as d])

(defn create-conn []
  (let [url (str "datomic:mem://" (d/squuid))]
    (d/create-database url)
    (d/connect url)))

(def conn (create-conn))

@(d/transact
  conn
  [{:db/ident :user/email
    :db/valueType :db.type/string
    :db/unique :db.unique/identity
    :db/cardinality :db.cardinality/one}
   {:db/ident :user/created-at
    :dte/valueType :java.time/instant ;; here's the typed attribute
    :db/cardinality :db.cardinality/one}])

@(d/transact
  conn
  [{:user/email "[email protected]"
    :user/created-at (java.time.Instant/parse "2017-01-01T00:00:00Z")}])

(d/pull (d/db conn)
        [:user/created-at]
        [:user/email "[email protected]"]) ;; :user/created-at is a java.time.Instant

(:user/created-at (d/entity (d/db conn) [:user/email "[email protected]"]))
;; => returns a java.time.Instant

(d/q '[:find ?inst . :where [_ :user/created-at ?inst]]
     (d/db conn)) ;; so does this

(let [[[e a v]]
      (seq (d/datoms (d/db conn) :eavt [:user/email "[email protected]"] :user/created-at))]
  v) ;; this leaks: it returns a java.util.Date (the serialized backing type)

So now what?

Feel free to use it. It's been used for years in several projects. Just be aware that it is leaky. For me, I hope that one day this entire library will be made redundant by the Datomic team.

How can I use it with Conformity?

Since Conformity's ensure-conforms transacts for you using the non-wrapped Datomic API, you can add the backing types like so:

(d/add-backing-types tx-data)

before sending the migrations to Conformity.

If you are also migrating in data that needs to be serialized, you might have to do the attribute migrations first, and then do:

(d/prepare-tx-data db tx-data)

on the data migration.

Install

Add [datomic-type-extensions "2020-05-26"] to :dependencies in your project.clj.

Changes

From 2019-09-04 to 2020-05-26

  • Better performance with type hints to avoid reflection.

From 2019-05-10 to 2019-09-04

  • We now wrap datomic.api/history to ensure we cache the type extended attributes before the history db makes us unable to find them.

From 2019-02-05 to 2019-05-10

  • We now wrap datomic.api/filter to ensure we cache the type extended attributes before you filter them out of the database.

From 2019-02-05 to 2019-02-18

Bugfixes:

  • Fix serialization / deserialization of multi-value attributes again

From 2019-01-23 to 2019-02-05

Bugfixes:

  • Fix lookup of missing serialized attribute.

From 2018-11-06 to 2019-01-23

Bugfixes:

  • Fix serialization / deserialization of multi-value attributes (i.e. :db.cardinality/many)

From 2018-04-18 to 2018-11-06

Bugfixes / aligning the APIs with Datomic:

  • Make TypeExtendedEntityMap behave more like Datomic wrt printing (Anders Furseth)
  • Hash EntityMap and TypeExtendedEntityMap differently
  • Cache the attr-types lookup on db gotten from entity
  • Wrap entity when emptied

License

Copyright © Anders Furseth and Magnar Sveen, since 2018

Distributed under the Eclipse Public License, the same as Clojure.

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.