Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 137 additions & 113 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["cmungall <cjm@berkeleybop.org>"]

[tool.poetry.dependencies]
python = "^3.8"
linkml = "^1.2.10"
linkml = "^1.2.11"
SQLAlchemy-Utils = "^0.38.2"
click = "^8.1.3"

Expand Down
5 changes: 4 additions & 1 deletion src/semsql/builder/build.Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ $(TEMPLATE): $(THIS_DIR)/sql_schema/semsql.sql
mv $@.tmp $@
.PRECIOUS: $(TEMPLATE)

%-min.owl: %.owl
robot remove -i $< --axioms "equivalent disjoint annotation" -o $@

# -- MAIN TARGET --
# A db is constructed from
# (1) triples loaded using rdftab
Expand All @@ -61,7 +64,7 @@ $(TEMPLATE): $(THIS_DIR)/sql_schema/semsql.sql
# will be simplified in future. See:
# - https://github.com/balhoff/relation-graph/issues/123
# - https://github.com/balhoff/relation-graph/issues/25
%-$(RGSUFFIX).tsv: %.owl
%-$(RGSUFFIX).tsv: %-min.owl
$(RG) --disable-owl-nothing true \
--ontology-file $<\
--output-file $@.ttl.tmp \
Expand Down
37 changes: 37 additions & 0 deletions src/semsql/builder/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import click
import logging
import semsql.builder.builder as builder
from linkml_runtime import SchemaView
from linkml_runtime.utils.formatutils import underscore
from semsql.sqlutils.viewgen import get_viewdef
from sqlalchemy import text


Expand Down Expand Up @@ -68,6 +71,40 @@ def query(input, query):
print(row)


@main.command()
@click.argument('inputs', nargs=-1)
@click.option('--index/--no-index', default=True, help='Create indexes on each column')
@click.option('--name', '-n', help='Name of class/view to materialize. If blank, will perform for ALL')
def view2table(inputs, name: str, index: bool):
"""
Generates a command that turns a view into a table

See https://github.com/cmungall/semantic-sql/issues/9

Example usage:
```
semsql view2table src/linkml/rdf.yaml -n rdfs_label_statement | sqlite3 db/pato.db
```
"""
for input in inputs:
with open(input, 'r') as stream:
sv = SchemaView(input)
schema = sv.schema
for cn, c in sv.all_classes().items():
tn = underscore(cn)
if name is None or str(cn) == name or tn == name:
view = get_viewdef(c)
if view is not None:
print(f'DROP VIEW {tn};')
print(f'CREATE TABLE {tn} AS {view};')
if index:
for sn in sv.class_slots(cn):
colname = underscore(sn)
print(f'CREATE INDEX {tn}_{colname} ON {tn}({colname});')
else:
logging.error(f'No view for {cn}')



if __name__ == '__main__':
main()
29 changes: 12 additions & 17 deletions src/semsql/sqlutils/view2table.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import click
from typing import List

from linkml_runtime import SchemaView
from linkml_runtime.linkml_model import SchemaDefinition, ClassDefinitionName, SlotDefinitionName
from linkml.utils.formatutils import underscore
from linkml.utils.schemaloader import SchemaLoader
from semsql import get_viewdef

def all_slots(schema: SchemaDefinition, cn: ClassDefinitionName) -> List[SlotDefinitionName]:
c = schema.classes[cn]
slots = list(c.slots)
if c.is_a:
slots += all_slots(schema, c.is_a)
if c.mixins:
for m in c.mixins:
slots += all_slots(schema, m)
return slots
from linkml_runtime.utils.formatutils import underscore
from semsql.sqlutils.viewgen import get_viewdef




@click.command()
@click.argument('inputs', nargs=-1)
Expand All @@ -32,16 +26,17 @@ def cli(inputs, name: str, index: bool):
"""
for input in inputs:
with open(input, 'r') as stream:
schema = SchemaLoader(input).schema
for cn, c in schema.classes.items():
sv = SchemaView(input)
schema = sv.schema
for cn, c in sv.all_classes().items():
tn = underscore(cn)
if name is None or str(cn) == name or tn == name:
view = get_viewdef(schema, c)
view = get_viewdef(c)
if view is not None:
print(f'DROP VIEW {tn};')
print(f'CREATE TABLE {tn} AS {view};')
if index:
for sn in all_slots(schema, cn):
for sn in sv.class_slots(cn):
colname = underscore(sn)
print(f'CREATE INDEX {tn}_{colname} ON {tn}({colname});')

Expand Down
3 changes: 1 addition & 2 deletions src/semsql/sqlutils/viewgen.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import click
from typing import List
from linkml_runtime.linkml_model import SchemaDefinition, ClassDefinition
from linkml.utils.schemaloader import load_raw_schema, SchemaLoader
from linkml_runtime.utils.formatutils import underscore

VIEW_CODE = 'sqlview>>'

def get_viewdef(schema: SchemaDefinition, c: ClassDefinition) -> str:
def get_viewdef(c: ClassDefinition) -> str:
"""
Return all VIEW definitions for a class
:param schema:
Expand Down