Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
0.5.0 - 2026-06-29¶
Added¶
Map.computed— read-only semantic fields from SQL expressions; filterable and orderableMap.collection— many-to-many bridge-table mappings withlink/upsert/replace/ignorecascade policies- Batch export —
instances_to_graph,instances_to_jsonld,instances_to_rdf,write_instance_to_graph - Select-plan cache —
compile/cache.pyskeleton cache per mapper - Batched collection hydration — one query per collection field after
find/get AsyncOntoSession.create_tables()andsession.expire_all()- Session
registry=— optionalPrefixRegistryonOntoSession/AsyncOntoSessionfor post-commit graph sync strict_graph_sync=onOntoSession/AsyncOntoSession(defaultTrue) — raisesGraphSyncErroron session exit when graph sync fails after SQL commitAsyncOntoSession.__del__—ResourceWarningwhen session opened but not closed (parity with sync)- PyLD safety —
safe_document_loaderblocks remote@contextfetches by default;allow_remote_contextsopt-in ontosql.io—to_jsonld,to_rdf,from_jsonldmodule-level I/O API (preferred over instance methods)ontosql.ports—SessionBackend,PlanExecutor,MapperLookup,MapperMetadata,GraphSyncPortprotocolsontosql.rdf— shared RDF kernel (literals,formats,predicates)OntoMapper.metadata()— neutral field metadata view for RDF/import/sync layersOntoSession/AsyncOntoSession— optionalmapper_registry=for sharedMapperLookupinjectionOntoRouter— optionalmapper_registry=for shared mapper lookup- Compile layer split —
columns,nested_write,collection_write,save_plan,execute_runner - Session internals split —
IdentityMap,PendingWorkQueue,GraphSyncQueue, shared flush coordinator - Documentation audit: slim README, beta banners, when-to-use, semantic queries, FastAPI quick start, mkdocstrings API reference, expanded FAQ/troubleshooting, SPECS drift fixes
- Documentation adoption audit — API/Architecture/Operations nav split, tutorial, I/O and query reference, upgrading guide 0.5.0 consolidation, SECURITY
max_triplesaccuracy, examples/README - Enterprise adoption — enterprise-adoption.md evaluation + checklist, SUPPORT.md, compliance guide
- Operations guides — Alembic, testing, upgrading, graph sync runbook
- API reference — FastAPI, export, import, sync, SHACL; GLOSSARY.md
Fixed¶
- Partial flush — SQL checkpoint prevents double-apply on retry; per-iteration graph queue restore preserves pushes for completed items
count(where=...)— subtracts only pending-delete tombstones that match the filterfind(limit=...)— over-fetches past tombstones so pages return up tolimitrowsrollback()— always clears delete tombstones (even whenclear_uow=False)- Collection
REPLACE— DB snapshot loads M2M members without priorget(); orphan member rows removed when membership shrinks OntoGraphSync.push()— acceptsprior_nested_iris=for stale nested retraction on direct adapter useOntoRoutercreate body — required fields enforced in generated schema; missing fields return 422; non-object JSON body returns 400load_graph— invalid UTF-8 raisesOntoImportError;max_triplesenforced incrementally during parse- REPLACE exclusivity — inbound FK checks span all registered mappers (cross-table references block delete)
- Session snapshots — DB nested FK values merged into session snapshot for REPLACE compile
- Graph sync — stale nested RDF subjects retracted on patch/replace; exclusive nested removed on root delete
OntoSession.flush()— partial failure preserves unprocessed queue; deferred insert merges PK into caller instance- Identity map — pending deletes hidden from
get();get(iri=)respects cached instance; duplicate deferred saves deduplicated execute_write_plan— raises on zero-row UPDATE; raises when collection writes lack parent identityOntoRouter—limitge=1; unified Accept negotiation for list JSON-LD; malformed/deep JSON → 400;application/jsonplain JSON- UPSERT cascade — clearing a nested association (
employer=None) now nulls the FK on update - Session graph sync — pre-save nested IRIs captured at queue time (stale nested retraction works via session path)
- Graph sync collections —
Map.collectionpredicates owned in patch mode; collection member IRIs tracked for stale removal find()— excludes pending-delete tombstones (consistent withget())- Session lifecycle — exception exit clears pending queue; flush failure preserves deferred-insert identity mapping
- Snapshot merge — DB-null nested FK overrides stale session nested dict; empty DB collection lists no longer overwrite session collection snapshots
- Accept negotiation —
application/jsonparticipates in q-value sorting with RDF types; invalidqvalues rejected;application/*maps toapplication/ld+json - Import — non-URI collection members raise
OntoImportError; duplicate collection IRIs deduplicated; multi-valued scalar literals; nested literal objects raiseOntoImportError - Write execute — collection bridge sync runs before REPLACE nested deletes on update
- Deferred graph sync —
prior_nested_iriscaptured at deferredsave()queue time count()— subtracts pending-delete tombstones (consistent withget()/find())- Delete graph sync — nested IRIs from pre-delete DB/session snapshot when fields unset
- Delete SQL cascade —
REPLACEnested rows deleted on rootdelete()when exclusively owned - Export — batch export deduplicates by logical IRI
OntoRouter— listGETdefaults to JSON-LD withoutAccept; RDF negotiation returns 406 on unsupported payloads
Changed¶
- SOLID refactor — protocol-driven boundaries; unified sync/async flush coordinator and execute runner
OntoModel.to_jsonld/to_rdf/from_jsonld— delegate toontosql.io(instance methods retained as thin wrappers)- RDF format helpers — moved from
ontosql.export._formatstoontosql.rdf.formats(shim retained) rollback()— defaultclear_uow=True(wasFalse); warns whenclear_uow=Falseleaves pending workexecute_write_plan/async_execute_write_plan— accept optionalmapper_registry=andstrict_updates=(default strict)execute_write_plan— REPLACE nested deletes requiremapper_registry=(cross-table FK safety)compile_save_plan— REPLACE cascade on update requiressnapshot=compact_jsonld/frame_jsonld—allow_remote_contexts=Truerequires explicitdocument_loader=
Migration¶
See guides/upgrading.md for ontosql.io, ontosql.ports, and mapper_registry= moves. See Migrating from 0.4.x to 0.5.x below for earlier upgrades.
Migrating from 0.4.x to 0.5.x¶
0.5.0 bundles the 0.4.x feature set, SOLID internal refactor (ontosql.io, ontosql.ports, ontosql.rdf), and audit-driven session/graph/API fixes. Most applications need no code changes unless you adopt new features or hit the migration table in upgrading.md.
New capabilities (optional)¶
Map.computed— read-only SQL expression fields; excluded fromsave(); filterable and orderableMap.collection— many-to-many bridge tables with explicit cascade policies; see bridge-tables.md- Batch export —
instances_to_graph,instances_to_jsonld,instances_to_rdffor efficient multi-instance RDF - Select-plan cache — internal performance improvement; no API change
Behavior notes¶
materialize_findnow builds oneStorevia batch export (same RDF intent, different memory profile)CascadePolicy.REPLACE(from 0.4.0) deletes old nested rows when associations change — do not use on shared nested entities; see cascade-policies.mdOntoRouterrequires authdependenciesand async lifespan for public exposure; see SECURITY.md- Graph sync is eventual-consistency after SQL commit, not two-phase commit; see HYBRID.md
API stability (0.5.x)¶
Until 1.0, minor releases may add APIs and fix bugs. Breaking changes are reserved for 2.0+ per ROADMAP.md. Semver guarantees begin at 1.0.
0.4.0 - 2026-06-25¶
Added¶
- RDF import —
ontosql.import_withimport_from_jsonld,import_from_rdf,graph_to_instance;OntoModel.from_jsonld() - Graph sync —
ontosql.syncwithpush_instance,remove_instance,StoreSyncTarget,sync_instance_to_store(add/replace/patchmodes) - Session graph hook —
OntoSession/AsyncOntoSessiongraph_syncandgraph_sync_modequeue graph updates onsave()/delete()and apply after commit - SparqlModel adapter —
OntoGraphSyncpush/pull (ontosql.sync.sparql) - Materialized views —
materialize_find,materialize_entity - SHACL —
ontosql.shaclshape generation andvalidate_instance; optionalontosql[shacl]extra (pyshacl) - Prefix bundles —
PrefixRegistry.curated("schema_org" | "dcterms") - Documentation site — MkDocs + Material theme;
pip install ontosql[docs]; CImkdocs build --strict - Contributor docs —
CONTRIBUTING.md, FAQ, troubleshooting, security notes, cascade policies guide, compatibility matrix - Standalone PyPI-runnable examples (
examples/models.py); async session example - HYBRID.md and examples/hybrid_person_org.py
Changed¶
CascadePolicy.REPLACE— deletes old nested row when FK changes or nested becomesNone(snapshot-based)- Export honors
onto_property(datatype=..., language=...)on literals - CI coverage threshold lowered to 90%
- Documentation pass: quick start bootstrap, graph sync timing, shipped vs planned labels in ecosystem docs
Fixed¶
- Graph sync — updates apply after SQL commit on session exit, not immediately on
save(); rolled-back sessions discard queued graph updates - Graph sync on delete —
delete()queues subgraph removal viaremove_instanceonly after SQL delete succeeds push_instance/GraphSyncTarget— patch mode mutatestarget.graphin place (fixes SparqlModel adapter)- Graph patch root IRI — uses
build_instance_iri(instance)instead of nondeterministic set iteration - Shared nested graph nodes — nested subjects patched by owned predicates only; delete removes root subject only
- REPLACE cascade — nulls parent FK before deleting old nested row; raises
ExecuteErrorwhen a shared nested row is still referenced - Session snapshots — keyed by
(entity_type, identity)instead ofid(instance)for stable REPLACE behavior - Detached updates — load DB snapshot when session snapshot missing so REPLACE and updates work without prior
get() - Pending writes —
save(flush_now=False)/delete(flush_now=False)auto-flush on session exit;clear_pending()clears graph sync queues - Import —
model_validateafter hydrate;Optional[T]/int | Nonecoercion - FastAPI
OntoRouter— POST/PATCH validate bodies with generated Pydantic models; PATCH cannot retarget row via bodyid; list supports RDFAcceptheaders;offsetvalidatedge=0 - Invalid
graph_sync_moderaisesValueErrorinstead of silent no-op
0.3.1 - 2026-06-10¶
Added¶
- PyPI release workflow (
.github/workflows/release.yml) onv*.*.*tags
Changed¶
- Test suite refactored for behavioral integration coverage; CI coverage threshold 94%
OntoRouterlistlimitcapped at 100 via FastAPIQuery(le=100)- Documentation:
OntoRouterproduction limitations;CascadePolicy.REPLACEreserved (same as upsert until 0.4); export uses semanticonto_propertymetadata only;docs/DEPS.mdsynced withpyproject.toml
Fixed¶
ExecuteErrorraised when executing delete plans without awhereclause- PyLD optional dependency pinned to
>=3.0(PyPI max is 3.0.0) - UPSERT nested insert with
id=Nonenow propagates inserted FK into parent row
0.3.0 - 2026-06-10¶
Added¶
- Write path —
OntoSession.save()/delete(),flush(),clear_pending(), identity map, partial updates CascadePolicy—link,upsert,replace,ignoreonMap.nested(..., cascade=, fk_column=)- Query — nested
FieldPath(Person.employer.name),contains/endswith,OrderBy(desc=),paginate()/Page OntoRouter— FastAPI CRUD routes with content negotiation;onto_session_lifespan, OpenAPI enrichment- Optional
ontosql[jsonld]extra —compact_jsonld/frame_jsonld(PyLD) - TripleModel (
triplemodel>=0.12.0) as core RDF dependency OntoModel.to_jsonld()andto_rdf();ontosql.exporthelpers- Optional
ontosql[sparql]extra; ECOSYSTEM.md
Changed¶
PrefixRegistry.expand()delegates to TripleModelexpand_curie()- Examples: full CRUD demo and
examples/person_org_api.py
0.2.0 - 2026-05-16¶
First release of OntoSQL — semantic data access for SQL via explicit maps.
Added¶
OntoModelandonto_property— Pydantic semantic entities with ontology metadataOntoMapper,Map, andMap.nested— declarative bindings from semantic fields to SQL columns and joinsOntoSession(sync) andAsyncOntoSession—get,find, andexecute_sqlwith semantic query expressionsPrefixRegistry— CURIE expansion, compaction, and JSON-LD@context- Optional
ontosql[fastapi]extra — content negotiation helpers for dict, string, and future semantic export types - Integration tests for Person / Organization nested
worksForover SQLite (sync and async) - Example:
examples/person_org_demo.py - Documentation: ARCHITECTURE.md, SPECS.md, ROADMAP.md