-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(versioning): Add support for auto data versioning (#355)
DEV-17: datamodels auto compute tag Adds support for tagging nodes based on properties set in the dictionary. Adds the following sysan properties * version: version number for the given node * tag: a uuid string that represents nodes of same version (ie, all nodes with same tag are versions of each other) * latest: True, if the given node is the latest These values are evaluated using properties defined in the dictionary (currently only biodictionary defines those properties). The property name is tagProperties
- Loading branch information
Showing
16 changed files
with
514 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
repos: | ||
- repo: git@github.com:Yelp/detect-secrets | ||
rev: v0.13.0 | ||
hooks: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import os | ||
import uuid | ||
|
||
from sqlalchemy import and_, event, select | ||
|
||
UUID_NAMESPACE_SEED = os.getenv("UUID_NAMESPACE_SEED", "86bb916a-24c5-48e4-8a46-5ea73a379d47") | ||
UUID_NAMESPACE = uuid.UUID("urn:uuid:{}".format(UUID_NAMESPACE_SEED), version=4) | ||
|
||
|
||
def __generate_hash(seed, label): | ||
namespace = UUID_NAMESPACE | ||
name = "{}-{}".format(seed, label) | ||
return str(uuid.uuid5(namespace, name)) | ||
|
||
|
||
def compute_tag(node): | ||
"""Computes unique tag for given node | ||
Args: | ||
node (models.Node): mode instance | ||
Returns: | ||
str: computed tag | ||
""" | ||
keys = [node.node_id if p == "node_id" else node.props[p] for p in node.tag_properties] | ||
keys += sorted([p.dst.tag or compute_tag(p.dst) for p in node.edges_out if p.label != "relates_to"]) | ||
return __generate_hash(keys, node.label) | ||
|
||
|
||
def __get_tagged_version(node_id, table, tag, conn): | ||
"""Super private function to figure out the proper version number to use just after insertion | ||
Args: | ||
node_id (str): current node_id | ||
table (sqlalchemy.Table): node table instance | ||
tag (str): currently computed tag | ||
conn (sqlalchemy.engine.Connection): currently active connection instance | ||
Returns: | ||
int: appropriate version number to use. 1 greater than the current max | ||
""" | ||
query = select([table]).where( | ||
and_(table.c._sysan["tag"].astext == tag, table.c.node_id != node_id) | ||
) | ||
max_version = 0 | ||
for r in conn.execute(query): | ||
max_version = max(r._sysan.get("version", 0), max_version) | ||
|
||
# reset latest | ||
r._sysan["latest"] = False | ||
conn.execute( | ||
table.update().where(table.c.node_id == r.node_id).values(_sysan=r._sysan) | ||
) | ||
return max_version + 1 | ||
|
||
|
||
def inject_set_tag_after_insert(cls): | ||
"""Injects an event listener that sets the tag and version properties on nodes, just before they are inserted | ||
Args: | ||
cls (class): node class type | ||
""" | ||
|
||
@event.listens_for(cls, "after_insert") | ||
def set_node_tag(mapper, conn, node): | ||
table = node.__table__ | ||
tag = compute_tag(node) | ||
|
||
version = __get_tagged_version(node.node_id, table, tag, conn) | ||
|
||
node._sysan["tag"] = tag | ||
node._sysan["latest"] = True | ||
node._sysan["version"] = version | ||
|
||
# update tag and version | ||
conn.execute( | ||
table.update() | ||
.where(table.c.node_id == node.node_id) | ||
.values(_sysan=node._sysan) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
psql -U postgres -c "create user test with superuser password 'test';" | ||
psql -U postgres -c "create database automated_test with owner test;" | ||
psql -U postgres -c "create database automated_test with owner test;" | ||
psql -U postgres -c "create database dev_models with owner test;" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import psqlgraph | ||
from psqlgraph import Node, Edge, create_all, ext | ||
|
||
from gdcdatamodel import models | ||
|
||
|
||
def truncate(engine, namespace=None): | ||
""" | ||
Remove data from existing tables | ||
""" | ||
abstract_node = psqlgraph.Node | ||
abstract_edge = psqlgraph.Edge | ||
if namespace: | ||
abstract_node = ext.get_abstract_node(namespace) | ||
abstract_edge = ext.get_abstract_edge(namespace) | ||
conn = engine.connect() | ||
for table in abstract_node.get_subclass_table_names(): | ||
if table != abstract_node.__tablename__: | ||
conn.execute('delete from {}'.format(table)) | ||
for table in abstract_edge.get_subclass_table_names(): | ||
if table != abstract_edge.__tablename__: | ||
conn.execute('delete from {}'.format(table)) | ||
|
||
if not namespace: | ||
# add ng models only to main graph model | ||
truncate_ng_tables(conn) | ||
conn.close() | ||
|
||
|
||
def create_tables(engine, namespace=None): | ||
""" | ||
create a table | ||
""" | ||
|
||
base = psqlgraph.base.ORMBase | ||
if namespace: | ||
base = ext.get_orm_base(namespace) | ||
create_all(engine, base) | ||
|
||
if not namespace: | ||
# add ng models only to main graph | ||
create_ng_tables(engine) | ||
|
||
|
||
def create_ng_tables(engine): | ||
models.versioned_nodes.Base.metadata.create_all(engine) | ||
models.submission.Base.metadata.create_all(engine) | ||
models.redaction.Base.metadata.create_all(engine) | ||
models.qcreport.Base.metadata.create_all(engine) | ||
models.misc.Base.metadata.create_all(engine) | ||
|
||
|
||
def truncate_ng_tables(conn): | ||
|
||
# Extend this list as needed | ||
ng_models_metadata = [ | ||
models.versioned_nodes.Base.metadata, | ||
models.submission.Base.metadata, | ||
models.redaction.Base.metadata, | ||
models.qcreport.Base.metadata, | ||
models.misc.Base.metadata, | ||
] | ||
|
||
for meta in ng_models_metadata: | ||
for table in meta.tables: | ||
conn.execute("DELETE FROM {}".format(table)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import pkg_resources | ||
import yaml | ||
|
||
|
||
def _load(name): | ||
with pkg_resources.resource_stream(__name__, name) as f: | ||
return yaml.safe_load(f) | ||
|
||
|
||
class Dictionary: | ||
|
||
def __init__(self, name): | ||
self.schema = _load(name) | ||
|
||
|
||
BasicDictionary = Dictionary("schema/basic.yaml") |
Oops, something went wrong.