Semantic data access for SQL — map ontology-shaped models onto real schemas with explicit OntoMapper bindings (import ontosql)
Project description
OntoSQL
Semantic data access for SQL — map ontology-shaped models onto real database schemas and write CRUD in Python, not RDF.
Real databases are not one table per ontology class. OntoSQL separates physical SQLModel tables from semantic Pydantic entities and connects them with an explicit mapper. Application code uses semantic types; OntoSQL compiles SQL on the backend. RDF export uses TripleModel; graph-native apps can pair OntoSQL with SparqlModel — see Ecosystem.
Requirements: Python 3.10+. See Compatibility.
Install
pip install ontosql
pip install "ontosql[fastapi]" # OntoRouter + content negotiation
pip install "ontosql[jsonld]" # optional JSON-LD compact/frame (PyLD)
pip install "ontosql[sparql]" # SparqlModel graph sync adapter
pip install "ontosql[shacl]" # SHACL shape generation + validation
For async SQLite examples: pip install aiosqlite greenlet.
Start here
- Quick start (below) — models, maps, session CRUD in ~10 minutes
- Architecture — why two model layers and explicit maps
- Hybrid deployments — SQL + RDF graph sync (optional)
- Technical specification — full API reference
- FAQ · Troubleshooting
Runnable examples (after pip install ontosql):
python examples/person_org_demo.py # sync CRUD
python examples/person_org_async.py # async session (needs aiosqlite)
python examples/hybrid_person_org.py # graph sync + import + SHACL
pip install "ontosql[fastapi]" uvicorn && python examples/person_org_api.py
Quick start
0. Database engine
from sqlmodel import Session, SQLModel, create_engine
from ontosql import OntoSession
engine = create_engine("sqlite:///./app.db")
SQLModel.metadata.create_all(engine) # use Alembic in production
# Optional: seed data
with Session(engine) as raw:
...
1. Physical models (database truth)
from sqlmodel import Field, SQLModel
class OrgRow(SQLModel, table=True):
__tablename__ = "orgs"
id: int | None = Field(default=None, primary_key=True)
name: str
class PersonRow(SQLModel, table=True):
__tablename__ = "people"
id: int | None = Field(default=None, primary_key=True)
name: str
org_id: int | None = Field(default=None, foreign_key="orgs.id")
2. Semantic models (what your app uses)
from ontosql import OntoModel, onto_property
class Organization(OntoModel):
type_iri = "schema:Organization"
iri_template = "https://data.example.org/org/{id}"
id: int
name: str = onto_property("schema:name")
class Person(OntoModel):
type_iri = "schema:Person"
iri_template = "https://data.example.org/person/{id}"
id: int
name: str = onto_property("schema:name")
employer: Organization | None = onto_property("schema:worksFor")
3. Maps (explicit SQL bindings)
from ontosql import Map, OntoMapper
class OrganizationMap(OntoMapper[Organization]):
entity = Organization
id = Map(OrgRow.id)
name = Map(OrgRow.name, property="schema:name")
class PersonMap(OntoMapper[Person]):
entity = Person
id = Map(PersonRow.id)
name = Map(PersonRow.name, property="schema:name")
employer = Map.nested(
Organization,
join=(PersonRow.org_id == OrgRow.id),
target=OrgRow,
nested_map=OrganizationMap,
property="schema:worksFor",
fk_column=PersonRow.org_id,
)
See Cascade policies for nested write behavior (link, upsert, replace, ignore).
4. Session (CRUD)
from ontosql import OntoSession, paginate
with OntoSession(engine, maps=[PersonMap, OrganizationMap]) as session:
ada = session.get(Person, id=1)
team = session.find(Person, where=Person.employer.name.startswith("Analytical"))
page = paginate(session, Person, limit=20, offset=0)
new_person = session.save(Person.model_construct(name="Grace Hopper", id=None))
new_person.name = "Grace M. Hopper"
session.save(new_person)
session.delete(new_person)
Async sessions use AsyncOntoSession with the same API — see Async guide and examples/person_org_async.py.
5. Export and import
print(ada.to_rdf(format="turtle"))
print(ada.to_jsonld())
from ontosql.import_ import import_from_jsonld # trailing underscore (import is reserved)
restored = import_from_jsonld(ada.to_jsonld(), PersonMap)
Export walks OntoModel + onto_property metadata and serializes via TripleModel. Nested semantic objects become linked RDF resources.
Features
- OntoModel + onto_property — semantic entities with ontology IRIs
- OntoMapper / Map — declarative bindings to columns, joins, and nested entities
- OntoSession / AsyncOntoSession —
get,find,save,delete,paginate, identity map - Semantic queries — nested paths,
contains/endswith,OrderBy(desc=True) - CascadePolicy — explicit nested write behavior on
Map.nested(guide) - OntoRouter (
ontosql[fastapi]) — auto CRUD routes + content negotiation - PrefixRegistry — CURIE expansion and JSON-LD
@context - Export —
to_jsonld()/to_rdf()on semantic instances - Import —
ontosql.import_hydratesOntoModelfrom RDF (FAQ) - Graph sync — mirror SQL writes to RDF graphs on commit (HYBRID.md)
- SHACL — generate and validate shapes from maps (
ontosql[shacl]) - Prefix bundles —
PrefixRegistry.curated()for schema.org / DC Terms
FastAPI
from fastapi import FastAPI
from ontosql.fastapi import OntoRouter, onto_session_lifespan
app = FastAPI()
onto_session_lifespan(app, engine, [PersonMap, OrganizationMap])
router = OntoRouter(maps=[PersonMap, OrganizationMap])
router.register(Person)
router.include_in(app)
See examples/person_org_api.py for a runnable API.
Production warning:
OntoRouteris for development and demos only. POST/PATCH bodies are validated with generated Pydantic models, but there is no authentication, authorization, or rate limiting. UseAsyncOntoSessionfor async apps. See Security and SPECS.md.
Documentation
Getting started
Guides
Architecture and reference
- Architecture
- Ecosystem — OntoSQL, TripleModel, SparqlModel
- Technical specification
- Compatibility
- Security
- Dependencies
Project
- Roadmap
- Changelog
- Contributing
- Releasing (maintainers)
- Documentation site — build with
mkdocs serveormkdocs build --strict
Development
See CONTRIBUTING.md and Releasing.
pip install -e ".[dev]"
ruff check src tests
ruff format src tests
ty check
pytest --cov=ontosql --cov-fail-under=90
mkdocs build --strict
License
MIT — see LICENSE.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ontosql-0.4.0.tar.gz.
File metadata
- Download URL: ontosql-0.4.0.tar.gz
- Upload date:
- Size: 76.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1cf074f7d0113c0847d14189d3a5b037606ccdb8f664f49d5bb3229ae7e3b96
|
|
| MD5 |
b28f1409f4b16122be28d5f0cf0b5ff6
|
|
| BLAKE2b-256 |
728946d8268d029e1779d7e4ca14e50e12d4a0f53bcf542fd7634e794c0037bb
|
File details
Details for the file ontosql-0.4.0-py3-none-any.whl.
File metadata
- Download URL: ontosql-0.4.0-py3-none-any.whl
- Upload date:
- Size: 51.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a2c3b8bbe3fcfe907f5a8267f73ddb42cffea62b4a2d140822976df5ae5a35a
|
|
| MD5 |
62ac031b0c31ec66b6c02a4fe71c1e23
|
|
| BLAKE2b-256 |
56c235931a165d69cf39596777e4ece72a3e0cdc6a2429806d55183a86d36ee6
|