-
Notifications
You must be signed in to change notification settings - Fork 28
Seattle Example
Datomic distribution has a great sample maintained by Seattle user group. This document explains how to run the Seattle example on Diametric gem. This document assumes Peer-based API on JRuby. REST-API is a subset of Peer API and some of methods using here are not supported.
-
Schema definition
class Seattle # Organization Definition include Diametric::Entity include Diametric::Persistence::Peer attribute :name, String, :cardinality => :one, :fulltext => true, :doc => "A community's name" attribute :url, String, :cardinality => :one, :doc => "A community's url" attribute :neighborhood, Ref, :cardinality => :one, :doc => "A community's neighborhood" attribute :category, String, :cardinality => :many, :fulltext => true, :doc => "All community categories" attribute :orgtype, Ref, :cardinality => :one, :doc => "A community orgtype enum value" attribute :type, Ref, :cardinality => :one, :doc => "A community type enum value" enum :orgtype, [:community, :commercial, :nonprofit, :personal] enum :type, [:email_list, :twitter, :facebook_page, :blog, :website, :wiki, :myspace, :ning] end class Neighborhood include Diametric::Entity include Diametric::Persistence::Peer attribute :name, String, :cardinality => :one, :unique => :identity, :doc => "A unique neighborhood name(upsertable)" attribute :district, Ref, :cardinality => :one, :doc => "A neighborhood's district" end class District include Diametric::Entity include Diametric::Persistence::Peer attribute :name, String, :cardinality => :one, :unique => :identity, :doc => "A unique district name (upsertable)" attribute :region, Ref, :cardinality => :one, :doc => "A district region enum value" enum :region, [:n, :ne, :e, :se, :s, :sw, :w, :nw] end
This definitions is equivalent to Datomic schema below:
[ ;; seattle {:db/id #db/id[:db.part/db] :db/ident :seattle/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/fulltext true :db/doc "A community's name" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :seattle/url :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/doc "A community's url" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :seattle/neighborhood :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "A community's neighborhood" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :seattle/category :db/valueType :db.type/string :db/cardinality :db.cardinality/many :db/fulltext true :db/doc "All community categories" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :seattle/orgtype :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "A community orgtype enum value" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :seattle/type :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "A community type enum value" :db.install/_attribute :db.part/db} ;; community/org-type enum values [:db/add #db/id[:db.part/user] :db/ident :seattle.orgtype/community] [:db/add #db/id[:db.part/user] :db/ident :seattle.orgtype/commercial] [:db/add #db/id[:db.part/user] :db/ident :seattle.orgtype/nonprofit] [:db/add #db/id[:db.part/user] :db/ident :seattle.orgtype/personal] ;; community/type enum values [:db/add #db/id[:db.part/user] :db/ident :seattle.type/email-list] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/twitter] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/facebook-page] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/blog] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/website] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/wiki] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/myspace] [:db/add #db/id[:db.part/user] :db/ident :seattle.type/ning] ;; neighborhood {:db/id #db/id[:db.part/db] :db/ident :neighborhood/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/unique :db.unique/identity :db/doc "A unique neighborhood name (upsertable)" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :neighborhood/district :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "A neighborhood's district" :db.install/_attribute :db.part/db} ;; district {:db/id #db/id[:db.part/db] :db/ident :district/name :db/valueType :db.type/string :db/cardinality :db.cardinality/one :db/unique :db.unique/identity :db/doc "A unique district name (upsertable)" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/db] :db/ident :district/region :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "A district region enum value" :db.install/_attribute :db.part/db} ;; district/region enum values [:db/add #db/id[:db.part/user] :db/ident :district.region/n] [:db/add #db/id[:db.part/user] :db/ident :district.region/ne] [:db/add #db/id[:db.part/user] :db/ident :district.region/e] [:db/add #db/id[:db.part/user] :db/ident :district.region/se] [:db/add #db/id[:db.part/user] :db/ident :district.region/s] [:db/add #db/id[:db.part/user] :db/ident :district.region/sw] [:db/add #db/id[:db.part/user] :db/ident :district.region/w] [:db/add #db/id[:db.part/user] :db/ident :district.region/nw] ]
-
Basic Usage
The basic usage is:
- Create a connection
- Create schemas
- Create model instances
- Save model data
datomic_uri = "datomic:mem://seattle-#{SecureRandom.uuid}" @s_conn2 = Diametric::Persistence::Peer.connect(datomic_uri) Neighborhood.create_schema(@s_conn2).get District.create_schema(@s_conn2).get Seattle.create_schema(@s_conn2).get district = District.new district.name = "East" district.region = District::Region::E neighborhood = Neighborhood.new neighborhood.name = "Capitol Hill" neighborhood.district = district seattle = Seattle.new seattle.name = "15th Ave Community" seattle.url = "http://groups.yahoo.com/group/15thAve_Community/" seattle.neighborhood = neighborhood seattle.category = ["15th avenue residents"] seattle.orgtype = Seattle::Orgtype::COMMUNITY seattle.type = Seattle::Type::EMAIL_LIST seattle.save(@n_conn2)
- In this example, saving
district
andneighborhood
model individually is an option. The lastseattle.save
will do at the same time. - Enum type has a format
<module name>::(<module name>::)<constant name>
. Thus, enum value ofe
inDistrict
model schema isDistrict::Region::E
. Also, enum value ofcommunity
inSeattle
model schema isSeattle::Orgtype::COMMUNITY
.
-
Query
Query class constructor has three arguments:
query = Diametric::Query.new(model, connection_or_database=nil, resolve=false)
- First argument: model class
- Second argument: connection or database (connection.db)
If the value is not given, the default connection will be applied. - Third argument: resolve association recursively or not.
By default, the association won't be resolved, so the reference value is a dbid of the instance.
Example:
query = Diametric::Query.new(Seattle, @s_conn2, true) seattle = query.where(:name => "15th Ave Community").first seattle.name #=> "15th Ave Community" seattle.url #=> "http://groups.yahoo.com/group/15thAve_Community/" seattle.neighborhood.name #=> "Capitol Hill" seattle.neighborhood.district.name #=> "East" seattle.neighborhood.district.region #=> ":district.region/e" seattle.category #=> #<Set: {"15th avenue residents"}> seattle.orgtype #=> ":seattle.orgtype/community" seattle.type #=> ":seattle.type/email-list"
-
Reading Seattle example data
Seattle example has two sets of relatively big data, seattle-data0.dtm and seattle-data1.dtm. Creating each model instances like in the basic usage is not practical. Diametric gem supports Datomic's readAll method.
filename = File.join("<path to>", "seattle-data0.dtm") list = Diametric::Persistence::Utils.read_all(filename) @s_conn2.transact(list.first).get
Now, we can make queries to the data.
-
Navigating up query
On Datomic, the associations are bi-directional. As for seattle example, the association is "Seattle has a Neighborhood". From Seattle model instance, we can find an instance of Neighborhood model. Also, from Neighborhood model instance, we can find what Seattle instances have the neighborhood whose name is ...
Example:
neighborhood = Diametric::Query.new(Neighborhood, @s_conn2).where(:name => "Capitol Hill").first seattles = neighborhood.seattle_from_this_neighborhood(@s_conn2) seattles.collect(&:name) #=> ["15th Ave Community", "15th Ave Community", "Capitol Hill Community Council", "Capitol Hill Housing", "Capitol Hill Triangle", "CHS Capitol Hill Seattle Blog", "KOMO Communities - Captol Hill"]
-
Going back to the past database state
Datomic's database has an idea of "time". We can pull out a state of the database at some time in the past.
Example:
datomic_uri = "datomic:mem://seattle-#{SecureRandom.uuid}" conn = Diametric::Persistence::Peer.connect(datomic_uri) Neighborhood.create_schema(conn).get District.create_schema(conn).get Seattle.create_schema(conn).get filename = File.join("<path to>", "seattle-data0.dtm") list = Diametric::Persistence::Utils.read_all(filename) conn.transact(list.first).get query = Diametric::Query.new(Seattle, conn) query.all.size #=> 362 # at this moment, 362 seattle instances are saved past = Time.now filename1 = File.join("<path to>", "seattle-data1.dtm") list1 = Diametric::Persistence::Utils.read_all(filename1) conn.transact(list1.first).get query = Diametric::Query.new(Seattle, conn) query.all.size #=> 571 past_db = conn.db.as_of(past) query_to_past = Diametric::Query.new(Seattle, past_db) query_to_past.all.size #=> 362 # before the "past", it was 362.