validity parsing
parent
71f525e80c
commit
f1ceb27ac6
@ -1,7 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="CPP_MODULE" version="4">
|
<module type="CPP_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/cozopy/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/cozorocks/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/cozoserver/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
@ -1,141 +0,0 @@
|
|||||||
### Python template
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|
||||||
db_test_flights
|
|
@ -1,16 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "cozopy"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
[lib]
|
|
||||||
name = "cozopy"
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde_json = "1.0.81"
|
|
||||||
anyhow = "1.0.58"
|
|
||||||
env_logger = "0.9.0"
|
|
||||||
pyo3 = { version = "0.16.5", features = ["extension-module"] }
|
|
||||||
cozo = { path = ".." }
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,132 +0,0 @@
|
|||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
from cozo import *
|
|
||||||
|
|
||||||
|
|
||||||
def remove_nan(d):
|
|
||||||
return {k: v for (k, v) in d.items() if v is not None and v == v}
|
|
||||||
|
|
||||||
|
|
||||||
# put airport {
|
|
||||||
# iata: string,
|
|
||||||
# icao: string indexed,
|
|
||||||
# city: string identity,
|
|
||||||
# country: ref
|
|
||||||
# }
|
|
||||||
# put whatever: string;
|
|
||||||
# retract attr
|
|
||||||
|
|
||||||
def insert_data(destroy_on_exit):
|
|
||||||
db = CozoDb('db_test_flights', destroy_on_exit=destroy_on_exit)
|
|
||||||
try:
|
|
||||||
payload = [
|
|
||||||
*DefAttrs('country')
|
|
||||||
.code(Typing.string, index=Indexing.identity)
|
|
||||||
.desc(Typing.string)(),
|
|
||||||
|
|
||||||
*DefAttrs('continent')
|
|
||||||
.code(Typing.string, index=Indexing.identity)
|
|
||||||
.desc(Typing.string)(),
|
|
||||||
|
|
||||||
*DefAttrs('airport')
|
|
||||||
.iata(Typing.string, index=Indexing.identity)
|
|
||||||
.icao(Typing.string, index=Indexing.indexed)
|
|
||||||
.city(Typing.string, index=Indexing.indexed)
|
|
||||||
.desc(Typing.string)
|
|
||||||
.region(Typing.string, index=Indexing.indexed)
|
|
||||||
.country(Typing.ref)
|
|
||||||
.runways(Typing.int)
|
|
||||||
.longest(Typing.int)
|
|
||||||
.altitude(Typing.int)
|
|
||||||
.lat(Typing.float)
|
|
||||||
.lon(Typing.float)(),
|
|
||||||
|
|
||||||
*DefAttrs('route')
|
|
||||||
.src(Typing.ref)
|
|
||||||
.dst(Typing.ref)
|
|
||||||
.distance(Typing.int)(),
|
|
||||||
|
|
||||||
*DefAttrs('geo')
|
|
||||||
.contains(Typing.ref)(),
|
|
||||||
]
|
|
||||||
start_time = time.time()
|
|
||||||
tx_res = db.tx_attr(payload)['results']
|
|
||||||
end_time = time.time()
|
|
||||||
|
|
||||||
print(f'{len(tx_res)} attributes added in {(end_time - start_time) * 1000:.3f}ms')
|
|
||||||
|
|
||||||
insertions = []
|
|
||||||
nodes = pd.read_csv('air-routes-latest-nodes.csv', index_col=0)
|
|
||||||
|
|
||||||
continents = nodes[nodes['~label'] == 'continent']
|
|
||||||
for tuple in continents.itertuples():
|
|
||||||
put_payload = remove_nan(
|
|
||||||
{'_temp_id': str(tuple.Index), 'continent.code': tuple._3, 'continent.desc': tuple._5})
|
|
||||||
insertions.append(Put(put_payload))
|
|
||||||
|
|
||||||
country_idx = {}
|
|
||||||
countries = nodes[nodes['~label'] == 'country']
|
|
||||||
for tuple in countries.itertuples():
|
|
||||||
put_payload = remove_nan({'_temp_id': str(tuple.Index), 'country.code': tuple._3, 'country.desc': tuple._5})
|
|
||||||
country_idx[tuple._3] = str(tuple.Index)
|
|
||||||
insertions.append(Put(put_payload))
|
|
||||||
|
|
||||||
airports = nodes[nodes['~label'] == 'airport']
|
|
||||||
for tuple in airports.itertuples():
|
|
||||||
put_payload = remove_nan({
|
|
||||||
'_temp_id': str(tuple.Index),
|
|
||||||
'airport.iata': tuple._3,
|
|
||||||
'airport.icao': None if tuple._4 == 'none' else tuple._4,
|
|
||||||
'airport.desc': tuple._5,
|
|
||||||
'airport.region': tuple._6,
|
|
||||||
'airport.runways': int(tuple._7),
|
|
||||||
'airport.longest': int(tuple._8),
|
|
||||||
'airport.altitude': int(tuple._9),
|
|
||||||
'airport.country': country_idx[tuple._10],
|
|
||||||
'airport.city': tuple._11,
|
|
||||||
'airport.lat': tuple._12,
|
|
||||||
'airport.lon': tuple._13
|
|
||||||
})
|
|
||||||
insertions.append(Put(put_payload))
|
|
||||||
|
|
||||||
edges = pd.read_csv('air-routes-latest-edges.csv', index_col=0)
|
|
||||||
|
|
||||||
for tuple in edges[edges['~label'] == 'route'].itertuples():
|
|
||||||
payload = remove_nan(
|
|
||||||
{'route.src': str(tuple._1), 'route.dst': str(tuple._2), 'route.distance': int(tuple._4)})
|
|
||||||
insertions.append(Put(payload))
|
|
||||||
|
|
||||||
for tuple in edges[edges['~label'] == 'contains'].itertuples():
|
|
||||||
payload = remove_nan({'_temp_id': str(tuple._1), 'geo.contains': str(tuple._2)})
|
|
||||||
insertions.append(Put(payload))
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
d_res = db.tx(insertions)['results']
|
|
||||||
end_time = time.time()
|
|
||||||
print(f'{len(d_res)} node data added in {(end_time - start_time) * 1000:.3f}ms')
|
|
||||||
print(f'{len(d_res) / (end_time - start_time):.0f} insertions per second')
|
|
||||||
with open('air-routes-data.json', 'w', encoding='utf-8') as f:
|
|
||||||
for row in insertions:
|
|
||||||
json.dump(row['put'], f, ensure_ascii=False)
|
|
||||||
f.write('\n')
|
|
||||||
except Exception as e:
|
|
||||||
print(f'data already exists? {e}')
|
|
||||||
return db
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
db = insert_data(False)
|
|
||||||
start_time = time.time()
|
|
||||||
# res = db.run([Q(['?c', '?code', '?desc'],
|
|
||||||
# Disj(T.country.code('?c', 'CU'),
|
|
||||||
# Unify('?c', 10000239)),
|
|
||||||
# T.country.code('?c', '?code'),
|
|
||||||
# T.country.desc('?c', '?desc'))])
|
|
||||||
res = db.run([Q([Max('?n')],
|
|
||||||
T.route.distance('?a', '?n'))])
|
|
||||||
end_time = time.time()
|
|
||||||
print(json.dumps(res, indent=2))
|
|
||||||
print(f'{len(res)} results fetched in {(end_time - start_time) * 1000:.3f}ms')
|
|
@ -1,250 +0,0 @@
|
|||||||
import json
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
from cozopy import CozoDbPy
|
|
||||||
|
|
||||||
|
|
||||||
class CozoDb:
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.inner = CozoDbPy(*args, **kwargs)
|
|
||||||
|
|
||||||
def tx_attr(self, payload):
|
|
||||||
return json.loads(self.inner.transact_attributes(json.dumps({'attrs': payload}, ensure_ascii=False)))
|
|
||||||
|
|
||||||
def tx(self, payload):
|
|
||||||
return json.loads(self.inner.transact_triples(json.dumps({'tx': payload}, ensure_ascii=False)))
|
|
||||||
|
|
||||||
def run(self, q, out=None, limit=None, offset=None, sort=None):
|
|
||||||
payload = {'q': q}
|
|
||||||
if out is not None:
|
|
||||||
payload['out'] = out
|
|
||||||
if limit is not None:
|
|
||||||
payload['limit'] = limit
|
|
||||||
if offset is not None:
|
|
||||||
payload['offset'] = offset
|
|
||||||
if sort is not None:
|
|
||||||
payload['sort'] = [convert_sort_arg(arg) for arg in sort]
|
|
||||||
return json.loads(self.inner.run_query(json.dumps(payload, ensure_ascii=False)))
|
|
||||||
|
|
||||||
|
|
||||||
def convert_sort_arg(arg):
|
|
||||||
if arg.startswith('+'):
|
|
||||||
return {arg[1:]: 'asc'}
|
|
||||||
elif arg.startswith('-'):
|
|
||||||
return {arg[1:]: 'desc'}
|
|
||||||
else:
|
|
||||||
return {arg: 'asc'}
|
|
||||||
|
|
||||||
|
|
||||||
class Typing(str, Enum):
|
|
||||||
ref = 'ref'
|
|
||||||
component = 'component'
|
|
||||||
bool = 'bool'
|
|
||||||
int = 'int'
|
|
||||||
float = 'float'
|
|
||||||
string = 'string'
|
|
||||||
name = 'name'
|
|
||||||
uuid = 'uuid'
|
|
||||||
timestamp = 'timestamp'
|
|
||||||
bytes = 'bytes'
|
|
||||||
list = 'list'
|
|
||||||
|
|
||||||
|
|
||||||
class Cardinality(str, Enum):
|
|
||||||
one = 'one'
|
|
||||||
many = 'many'
|
|
||||||
|
|
||||||
|
|
||||||
class Indexing(str, Enum):
|
|
||||||
none = 'none'
|
|
||||||
indexed = 'indexed'
|
|
||||||
unique = 'unique'
|
|
||||||
identity = 'identity'
|
|
||||||
|
|
||||||
|
|
||||||
def Attribute(name, typing, id, cardinality, index, history):
|
|
||||||
ret = {
|
|
||||||
'name': name,
|
|
||||||
'type': typing,
|
|
||||||
'cardinality': cardinality,
|
|
||||||
'index': index,
|
|
||||||
'history': history
|
|
||||||
}
|
|
||||||
if id is not None:
|
|
||||||
ret['id'] = id
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def PutAttr(name, typing, id=None, cardinality=Cardinality.one, index=Indexing.none, history=False):
|
|
||||||
return {
|
|
||||||
'put': Attribute(name, typing, id, cardinality, index, history)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def RetractAttr(name, typing, id, cardinality, index, history):
|
|
||||||
return {
|
|
||||||
'retract': Attribute(name, typing, id, cardinality, index, history)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def Put(d):
|
|
||||||
return {'put': d}
|
|
||||||
|
|
||||||
|
|
||||||
def Retract(d):
|
|
||||||
return {'retract': d}
|
|
||||||
|
|
||||||
|
|
||||||
def Pull(variable, spec):
|
|
||||||
return {'pull': variable, 'spec': spec}
|
|
||||||
|
|
||||||
|
|
||||||
class DefAttrs:
|
|
||||||
def __init__(self, prefix):
|
|
||||||
self.prefix = prefix
|
|
||||||
self.attrs = []
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
return self.attrs
|
|
||||||
|
|
||||||
def __getattr__(self, item):
|
|
||||||
return DefAttributesHelper(self, item)
|
|
||||||
|
|
||||||
|
|
||||||
class DefAttributesHelper:
|
|
||||||
def __init__(self, parent, name):
|
|
||||||
self.parent = parent
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def __call__(self, typing, id=None, cardinality=Cardinality.one, index=Indexing.none, history=False):
|
|
||||||
name = f'{self.parent.prefix}.{self.name}'
|
|
||||||
self.parent.attrs.append({
|
|
||||||
'put': Attribute(name, typing, id, cardinality, index, history)
|
|
||||||
})
|
|
||||||
return self.parent
|
|
||||||
|
|
||||||
|
|
||||||
class TripleClass:
|
|
||||||
def __init__(self, attr_name):
|
|
||||||
self._attr_name = attr_name
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if self._attr_name is None:
|
|
||||||
return self.__class__(name)
|
|
||||||
else:
|
|
||||||
return self.__class__(self._attr_name + '.' + name)
|
|
||||||
|
|
||||||
def __call__(self, entity, value):
|
|
||||||
if self._attr_name is None:
|
|
||||||
raise Exception("you need to set the triple attribute first")
|
|
||||||
return [entity, self._attr_name, value]
|
|
||||||
|
|
||||||
|
|
||||||
T = TripleClass(None)
|
|
||||||
|
|
||||||
|
|
||||||
class RuleClass:
|
|
||||||
def __init__(self, rule_name):
|
|
||||||
self._rule_name = rule_name
|
|
||||||
self._at = None
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if self._rule_name is None:
|
|
||||||
return self.__class__(name)
|
|
||||||
elif name == 'at':
|
|
||||||
def closure(time):
|
|
||||||
self._at = time
|
|
||||||
return self
|
|
||||||
|
|
||||||
return closure
|
|
||||||
else:
|
|
||||||
raise Exception("cannot nest rule name")
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
if self._rule_name is None:
|
|
||||||
raise Exception("you need to set the rule name first")
|
|
||||||
ret = {'rule': self._rule_name, 'args': list(args)}
|
|
||||||
if self._at:
|
|
||||||
ret['at'] = self._at
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
R = RuleClass(None)
|
|
||||||
Q = RuleClass('?')
|
|
||||||
|
|
||||||
|
|
||||||
class OpClass:
|
|
||||||
def __init__(self, op_name):
|
|
||||||
self._op_name = op_name
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if self._op_name is None:
|
|
||||||
return self.__class__(name)
|
|
||||||
else:
|
|
||||||
raise Exception("cannot nest op name")
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
if self._op_name is None:
|
|
||||||
raise Exception("you need to set the op name first")
|
|
||||||
ret = {'op': self._op_name, 'args': list(args)}
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
Gt = OpClass('Gt')
|
|
||||||
Lt = OpClass('Lt')
|
|
||||||
Ge = OpClass('Ge')
|
|
||||||
Le = OpClass('Le')
|
|
||||||
Eq = OpClass('Eq')
|
|
||||||
Neq = OpClass('Neq')
|
|
||||||
Add = OpClass('Add')
|
|
||||||
Sub = OpClass('Sub')
|
|
||||||
Mul = OpClass('Mul')
|
|
||||||
Div = OpClass('Div')
|
|
||||||
StrCat = OpClass('StrCat')
|
|
||||||
|
|
||||||
|
|
||||||
class AggrClass:
|
|
||||||
def __init__(self, aggr_name):
|
|
||||||
self._aggr_name = aggr_name
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if self._aggr_name is None:
|
|
||||||
return self.__class__(name)
|
|
||||||
else:
|
|
||||||
raise Exception("cannot nest aggr name")
|
|
||||||
|
|
||||||
def __call__(self, symb):
|
|
||||||
if self._aggr_name is None:
|
|
||||||
raise Exception("you need to set the predicate name first")
|
|
||||||
ret = {'aggr': self._aggr_name, 'symb': symb}
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
Count = AggrClass('count')
|
|
||||||
Min = AggrClass('min')
|
|
||||||
Max = AggrClass('max')
|
|
||||||
|
|
||||||
|
|
||||||
def Const(item):
|
|
||||||
return {'const': item}
|
|
||||||
|
|
||||||
|
|
||||||
def Conj(*items):
|
|
||||||
return {'conj': items}
|
|
||||||
|
|
||||||
|
|
||||||
def Disj(*items):
|
|
||||||
return {'disj': items}
|
|
||||||
|
|
||||||
|
|
||||||
def NotExists(item):
|
|
||||||
return {'not_exists': item}
|
|
||||||
|
|
||||||
|
|
||||||
def Unify(binding, expr):
|
|
||||||
return {'unify': binding, 'expr': expr}
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['Gt', 'Lt', 'Ge', 'Le', 'Eq', 'Neq', 'Add', 'Sub', 'Mul', 'Div', 'Q', 'T', 'R', 'Const', 'Conj', 'Disj',
|
|
||||||
'NotExists', 'CozoDb', 'Typing', 'Cardinality', 'Indexing', 'PutAttr', 'RetractAttr', 'Attribute', 'Put',
|
|
||||||
'Retract', 'Pull', 'StrCat', 'Unify', 'DefAttrs', 'Count', 'Min', 'Max']
|
|
@ -1,84 +0,0 @@
|
|||||||
from cozo import *
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
db = CozoDb('_test', destroy_on_exit=True)
|
|
||||||
res = db.tx_attr(
|
|
||||||
DefAttrs('person')
|
|
||||||
.idd(Typing.string, index=Indexing.identity)
|
|
||||||
.first_name(Typing.string, index=Indexing.indexed)
|
|
||||||
.last_name(Typing.string, index=Indexing.indexed)
|
|
||||||
.age(Typing.int, index=Indexing.indexed)
|
|
||||||
.friend(Typing.ref, cardinality=Cardinality.many, index=Indexing.indexed)
|
|
||||||
.weight(Typing.float, index=Indexing.indexed)
|
|
||||||
.covid(Typing.bool)()
|
|
||||||
)
|
|
||||||
print(res)
|
|
||||||
print(db.tx_attr([
|
|
||||||
PutAttr('person.id', Typing.string, id=res['results'][0][0], cardinality=Cardinality.one,
|
|
||||||
index=Indexing.identity),
|
|
||||||
RetractAttr('person.covid', Typing.bool, id=res['results'][-1][0], cardinality=Cardinality.one, history=False,
|
|
||||||
index=Indexing.indexed),
|
|
||||||
]))
|
|
||||||
print(db.tx([
|
|
||||||
Put({'_temp_id': 'alice',
|
|
||||||
'person.first_name': 'Alice',
|
|
||||||
'person.age': 7,
|
|
||||||
'person.last_name': 'Amorist',
|
|
||||||
'person.id': 'alice_amorist',
|
|
||||||
'person.weight': 25,
|
|
||||||
'person.friend': 'eve'}),
|
|
||||||
Put({'_temp_id': 'bob',
|
|
||||||
'person.first_name': 'Bob',
|
|
||||||
'person.age': 70,
|
|
||||||
'person.last_name': 'Wonderland',
|
|
||||||
'person.id': 'bob_wonderland',
|
|
||||||
'person.weight': 100,
|
|
||||||
'person.friend': 'alice'
|
|
||||||
}),
|
|
||||||
Put({'_temp_id': 'eve',
|
|
||||||
'person.first_name': 'Eve',
|
|
||||||
'person.age': 18,
|
|
||||||
'person.last_name': 'Faking',
|
|
||||||
'person.id': 'eve_faking',
|
|
||||||
'person.weight': 50,
|
|
||||||
'person.friend': [
|
|
||||||
'alice',
|
|
||||||
'bob',
|
|
||||||
{'person.first_name': 'Charlie',
|
|
||||||
'person.age': 22,
|
|
||||||
'person.last_name': 'Goodman',
|
|
||||||
'person.id': 'charlie_goodman',
|
|
||||||
'person.weight': 120,
|
|
||||||
'person.friend': 'eve'}
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
Put({'_temp_id': 'david',
|
|
||||||
'person.first_name': 'David',
|
|
||||||
'person.age': 7,
|
|
||||||
'person.last_name': 'Dull',
|
|
||||||
'person.id': 'david_dull',
|
|
||||||
'person.weight': 25,
|
|
||||||
'person.friend': {
|
|
||||||
'_temp_id': 'george',
|
|
||||||
'person.first_name': 'George',
|
|
||||||
'person.age': 7,
|
|
||||||
'person.last_name': 'Geomancer',
|
|
||||||
'person.id': 'george_geomancer',
|
|
||||||
'person.weight': 25,
|
|
||||||
'person.friend': 'george'}
|
|
||||||
}),
|
|
||||||
]))
|
|
||||||
res = db.run([
|
|
||||||
R.ff(['?a', '?b'],
|
|
||||||
T.person.friend('?a', '?b')),
|
|
||||||
R.ff(['?a', '?b'],
|
|
||||||
T.person.friend('?a', '?c'),
|
|
||||||
R.ff('?c', '?b')),
|
|
||||||
Q(['?a'],
|
|
||||||
T.person.first_name('?a', '?n'),
|
|
||||||
T.person.first_name('?alice', 'Alice'),
|
|
||||||
NotExists(R.ff('?a', '?alice'))
|
|
||||||
),
|
|
||||||
],
|
|
||||||
out={'friend': Pull('?a', ['person.first_name'])})
|
|
||||||
print(res)
|
|
@ -1,69 +0,0 @@
|
|||||||
// #[cfg(not(target_env = "msvc"))]
|
|
||||||
// use tikv_jemallocator::Jemalloc;
|
|
||||||
//
|
|
||||||
// #[cfg(not(target_env = "msvc"))]
|
|
||||||
// #[global_allocator]
|
|
||||||
// static GLOBAL: Jemalloc = Jemalloc;
|
|
||||||
//
|
|
||||||
use pyo3::exceptions::PyException;
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use cozo::{Db, DbBuilder};
|
|
||||||
|
|
||||||
#[pyclass(extends = PyException)]
|
|
||||||
struct ErrorBridge(cozo::Error);
|
|
||||||
|
|
||||||
trait PyResultExt<T> {
|
|
||||||
fn into_py_res(self) -> PyResult<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PyResultExt<T> for anyhow::Result<T> {
|
|
||||||
fn into_py_res(self) -> PyResult<T> {
|
|
||||||
match self {
|
|
||||||
Ok(t) => Ok(t),
|
|
||||||
Err(e) => Err(PyException::new_err(e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
|
||||||
struct CozoDbPy {
|
|
||||||
db: Db,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymethods]
|
|
||||||
impl CozoDbPy {
|
|
||||||
#[new]
|
|
||||||
#[args(create_if_missing = true, destroy_on_exit = false)]
|
|
||||||
fn new(path: &str, create_if_missing: bool, destroy_on_exit: bool) -> PyResult<Self> {
|
|
||||||
let _ = env_logger::try_init();
|
|
||||||
let builder = DbBuilder::default()
|
|
||||||
.path(path)
|
|
||||||
.create_if_missing(create_if_missing)
|
|
||||||
.destroy_on_exit(destroy_on_exit);
|
|
||||||
let db = Db::build(builder).into_py_res()?;
|
|
||||||
Ok(Self { db })
|
|
||||||
}
|
|
||||||
pub fn transact_attributes(&self, py: Python<'_>, payload: &str) -> PyResult<String> {
|
|
||||||
let payload: serde_json::Value = serde_json::from_str(payload).unwrap();
|
|
||||||
let ret = py.allow_threads(|| self.db.transact_attributes(&payload).into_py_res())?;
|
|
||||||
Ok(ret.to_string())
|
|
||||||
}
|
|
||||||
pub fn transact_triples(&self, py: Python<'_>, payload: &str) -> PyResult<String> {
|
|
||||||
let payload: serde_json::Value = serde_json::from_str(payload).unwrap();
|
|
||||||
let ret = py.allow_threads(|| self.db.transact_triples(&payload).into_py_res())?;
|
|
||||||
Ok(ret.to_string())
|
|
||||||
}
|
|
||||||
pub fn run_query(&self, py: Python<'_>, payload: &str) -> PyResult<String> {
|
|
||||||
let payload: serde_json::Value = serde_json::from_str(payload).unwrap();
|
|
||||||
let ret = py.allow_threads(|| self.db.run_query(&payload).into_py_res())?;
|
|
||||||
Ok(ret.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymodule]
|
|
||||||
fn cozopy(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|
||||||
m.add_class::<CozoDbPy>()?;
|
|
||||||
m.add_class::<ErrorBridge>()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cozohttp"
|
name = "cozoserver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
Loading…
Reference in New Issue