Skip to main content

Interface to the Datomic REST API

Project description

datomic-py
==========

A Python library for the Datomic REST API.

While nothing will ever match the speed or power of Datomic's Clojure interface, this library will work well for the basics.


```shell
pip install datomic
```

Connect
=======

To connect to database "test" in store "mem" on localhost at port 8888:

```python
from datomic import *

db = DB('localhost', 8888, 'mem', 'test')

# create the database
db.create()
True

# get the state
db.info()
{'basis-t': 62, 'db/alias': 'mem/test'}
```


Schema
======

You do not need to define a schema. If you want to, it is just a bunch of nested tuples.

Unless specified otherwise, each attribute is assumed to be a string with a cardinality of one.

```python

S=(
('person',
('name', FULL, "A Persons name"),
('email', FULL, "A Person's email"),
('age', LONG, "A Person's age"),
('likes', REF, MANY, ISCOMP, "A Persons likes"),
),
('item',
('name', FULL),
('sku', UNIQ),
('active', BOOL),
('cat', MANY, ENUM('cat','dog','pony','horse','gerbil','sloth')),
),
('review',
('person', REF),
('item', REF),
('stars', LONG),
),
)
```

You can pass the schema to DB when connecting.

```python

db = DB(host, port, store, dbname, schema=S)


# get the schema data

db.schema.schema

['{:db/id #db/id[:db.part/db]
:db/ident :person/name
:db/fulltext true
:db/doc "A Persons name"
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}',
'...',
]

# transact the schema

db.tx_schema()


```

For a more comprehensive schema example, see [datomic/datomic_test.py](datomic/datomic_test.py)




Transact
========

```python

# start a new transaction

tx = db.tx()

# `person` will hold a tempid and resolve to an entity after the tx is executed

person = tx.add("person/", {
'name': "John Doe" ,
'age': 25,
})

# using "ns/" followed by saves some typing

item = tx.add("item/", {
'name': 'Item 1',
'sku': 'item-1-sku',
'active': True,
'cat': ['cat','dog'],
})

# another new entity, with a ref to our `person`

review = tx.add("review/", {
'item': item,
'stars': 4,
'person': person,
})

# we can nest a new entity in another entity

review2 = tx.add("review/", {
'item': item,
'stars': 5,
'person': tx.add("person/", {
'name': 'Nested Person',
'age': 22,
}),
})


# add another datum to `person`

tx.add(person, 'person/likes', item)

# does exactly the same thing as the previous example

person.add('person/likes', item)

# see our tempids so far

print person, item, review, review2
{'db/id': -1} {'db/id': -2} {'db/id': -4} {'db/id': -6}

# send the tx to datomic

tx.execute()

{'db-after': {'basis-t': 1042, 'db/alias': 'mem/test'},
'db-before': {'basis-t': 1040, 'db/alias': 'mem/test'},
'tx-data': [{'a': 50, 'added': True, 'e': 13194139534354, 'tx': 13194139534354, 'v': datetime.datetime(2013, 11, 9, 18, 55, 56, 657000, tzinfo=<UTC>)}, {'....'}]
}

# all entity ids are automatically resolved

print person, item, review, review2

{'db/id': 17592186045459} {'db/id': 17592186045460} {'db/id': 17592186045462} {'db/id': 17592186045464}

# access to the entity ids

print person.eid, item.eid, review.eid, review2.eid

17592186045459 17592186045460 17592186045462 17592186045464

# edn format

print unicode(person)

#db/id[:db.part/user 17592186045459]

```





Entity
======

```python

# fetch an entity

db.e(person)

{'person/age': 25, 'person/likes': ({'item/name': 'Item 1', 'item/sku': 'item-1-sku', 'item/cat': set(['dog', 'cat']), 'item/active': True, 'db/id': 17592186045460},), 'db/id': 17592186045459, 'person/name': 'John Doe'}

db.e(item.eid)

{'item/name': 'Item 1', 'item/sku': 'item-1-sku', 'item/cat': set(['dog', 'cat']), 'item/active': True, 'db/id': 17592186045460}

db.e(17592186045462)

{'review/person': {'db/id': 17592186045459}, 'review/stars': 4, 'db/id': 17592186045462, 'review/item': {'db/id': 17592186045460}}

# add datums to an entity

tx2 = db.tx()
person2 = tx2.add(person, 'person/email', 'jdoe@gmail.com')
tx2.execute()

person == person2

False

db.e(person2)

{'person/age': 25, 'person/email': 'jdoe@gmail.com', 'db/id': 17592186045440, 'person/name': 'John Doe', 'person/likes': ({'item/name': 'Item 1', 'item/sku': 'item-1-sku', 'item/cat': set(['dog', 'cat']), 'item/active': True, 'db/id': 17592186045441},)}


```



Query
=====

```python
p_name = '?e :person/name ?n'
p_age = '?e :person/age ?a'
p_email = '?e :person/email ?m'


# get one

db.find('?e ?n').where(p_name).one()

[17592186045457, 'John Doe']


# one to dict

p = db.find('?e ?n').where(p_name,p_age).hashone()
p.items()

[('e', 17592186045457), ('n', 'John Doe')]


# OR input param

qa = db.find('?e ?n ?a').where(p_name, p_age)\
.param('?n', ['Nested Person', 'John Doe'])
qa.all()

[[17592186045463, 'Nested Person', 22], [17592186045459, 'John Doe', 25]]

qa.limit(1).all()

[[17592186045463, 'Nested Person', 22]]


# AND input param

qb = db.find('?e ?n ?a').where(p_name, p_age)\
.param('?n ?a', ('John Doe', 25))
qb.all()

[17592186045459, 'John Doe', 25]]


# unify external data
qc = db.find('?e ?n ?external').where(p_name, p_age)\
.param('?n ?external',
[ ['John Doe', 123.23], ['Nested Person', 456.00]])
qc.all()

[[17592186045459, 'John Doe', 123.23], [17592186045463, 'Nested Person', 456.0]]

```



Retract
=======

```python
db.e(review2).get('review/stars')

5

db.retract(review2, 'review/stars', 5)

db.e(review2)

{'review/person': {'db/id': 17592186045463}, 'db/id': 17592186045464, 'review/item': {'db/id': 17592186045460}}

```



Datums
======

db.datums() lazily fetches datums in the chunk size you specify.

```python

for r in db.datoms('aevt', a='person/name', limit=100, chunk=100):
print r

{'a': 62, 'added': True, 'e': 17592186045459, 'tx': 13194139534354, 'v': 'John Doe'}
{'a': 62, 'added': True, 'e': 17592186045463, 'tx': 13194139534354, 'v': 'Nested Person'}
```

```python
for r in db.datoms('avet', a='item/sku', v='item-1-sku', limit=100):
print r

{'a': 67, 'added': True, 'e': 17592186045460, 'tx': 13194139534354, 'v': 'item-1-sku'}
```




TODO
====

* A python library for the C++ edn parser is in progress and should be more performant is in the works.

* More test coverage

* Better support for traversing the graph

* Eager loading of entities

* Materialized Views

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

datomic-0.1dev.tar.gz (11.8 kB view hashes)

Uploaded Source

Built Distribution

datomic-0.1dev.macosx-10.8-intel.exe (82.0 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page