Skip to content

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 orderable
  • Map.collection — many-to-many bridge-table mappings with link / upsert / replace / ignore cascade policies
  • Batch exportinstances_to_graph, instances_to_jsonld, instances_to_rdf, write_instance_to_graph
  • Select-plan cachecompile/cache.py skeleton cache per mapper
  • Batched collection hydration — one query per collection field after find / get
  • AsyncOntoSession.create_tables() and session.expire_all()
  • Session registry= — optional PrefixRegistry on OntoSession / AsyncOntoSession for post-commit graph sync
  • strict_graph_sync= on OntoSession / AsyncOntoSession (default True) — raises GraphSyncError on session exit when graph sync fails after SQL commit
  • AsyncOntoSession.__del__ResourceWarning when session opened but not closed (parity with sync)
  • PyLD safetysafe_document_loader blocks remote @context fetches by default; allow_remote_contexts opt-in
  • ontosql.ioto_jsonld, to_rdf, from_jsonld module-level I/O API (preferred over instance methods)
  • ontosql.portsSessionBackend, PlanExecutor, MapperLookup, MapperMetadata, GraphSyncPort protocols
  • ontosql.rdf — shared RDF kernel (literals, formats, predicates)
  • OntoMapper.metadata() — neutral field metadata view for RDF/import/sync layers
  • OntoSession / AsyncOntoSession — optional mapper_registry= for shared MapperLookup injection
  • OntoRouter — optional mapper_registry= for shared mapper lookup
  • Compile layer splitcolumns, nested_write, collection_write, save_plan, execute_runner
  • Session internals splitIdentityMap, 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_triples accuracy, examples/README
  • Enterprise adoptionenterprise-adoption.md evaluation + checklist, SUPPORT.md, compliance guide
  • Operations guidesAlembic, testing, upgrading, graph sync runbook
  • API referenceFastAPI, 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 filter
  • find(limit=...) — over-fetches past tombstones so pages return up to limit rows
  • rollback() — always clears delete tombstones (even when clear_uow=False)
  • Collection REPLACE — DB snapshot loads M2M members without prior get(); orphan member rows removed when membership shrinks
  • OntoGraphSync.push() — accepts prior_nested_iris= for stale nested retraction on direct adapter use
  • OntoRouter create body — required fields enforced in generated schema; missing fields return 422; non-object JSON body returns 400
  • load_graph — invalid UTF-8 raises OntoImportError; max_triples enforced 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 identity
  • OntoRouterlimit ge=1; unified Accept negotiation for list JSON-LD; malformed/deep JSON → 400; application/json plain 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 collectionsMap.collection predicates owned in patch mode; collection member IRIs tracked for stale removal
  • find() — excludes pending-delete tombstones (consistent with get())
  • 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 negotiationapplication/json participates in q-value sorting with RDF types; invalid q values rejected; application/* maps to application/ld+json
  • Import — non-URI collection members raise OntoImportError; duplicate collection IRIs deduplicated; multi-valued scalar literals; nested literal objects raise OntoImportError
  • Write execute — collection bridge sync runs before REPLACE nested deletes on update
  • Deferred graph syncprior_nested_iris captured at deferred save() queue time
  • count() — subtracts pending-delete tombstones (consistent with get() / find())
  • Delete graph sync — nested IRIs from pre-delete DB/session snapshot when fields unset
  • Delete SQL cascadeREPLACE nested rows deleted on root delete() when exclusively owned
  • Export — batch export deduplicates by logical IRI
  • OntoRouter — list GET defaults to JSON-LD without Accept; 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 to ontosql.io (instance methods retained as thin wrappers)
  • RDF format helpers — moved from ontosql.export._formats to ontosql.rdf.formats (shim retained)
  • rollback() — default clear_uow=True (was False); warns when clear_uow=False leaves pending work
  • execute_write_plan / async_execute_write_plan — accept optional mapper_registry= and strict_updates= (default strict)
  • execute_write_plan — REPLACE nested deletes require mapper_registry= (cross-table FK safety)
  • compile_save_plan — REPLACE cascade on update requires snapshot=
  • compact_jsonld / frame_jsonldallow_remote_contexts=True requires explicit document_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 from save(); filterable and orderable
  • Map.collection — many-to-many bridge tables with explicit cascade policies; see bridge-tables.md
  • Batch exportinstances_to_graph, instances_to_jsonld, instances_to_rdf for efficient multi-instance RDF
  • Select-plan cache — internal performance improvement; no API change

Behavior notes

  • materialize_find now builds one Store via 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.md
  • OntoRouter requires auth dependencies and 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 importontosql.import_ with import_from_jsonld, import_from_rdf, graph_to_instance; OntoModel.from_jsonld()
  • Graph syncontosql.sync with push_instance, remove_instance, StoreSyncTarget, sync_instance_to_store (add / replace / patch modes)
  • Session graph hookOntoSession / AsyncOntoSession graph_sync and graph_sync_mode queue graph updates on save() / delete() and apply after commit
  • SparqlModel adapterOntoGraphSync push/pull (ontosql.sync.sparql)
  • Materialized viewsmaterialize_find, materialize_entity
  • SHACLontosql.shacl shape generation and validate_instance; optional ontosql[shacl] extra (pyshacl)
  • Prefix bundlesPrefixRegistry.curated("schema_org" | "dcterms")
  • Documentation site — MkDocs + Material theme; pip install ontosql[docs]; CI mkdocs build --strict
  • Contributor docsCONTRIBUTING.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 becomes None (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 deletedelete() queues subgraph removal via remove_instance only after SQL delete succeeds
  • push_instance / GraphSyncTarget — patch mode mutates target.graph in 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 ExecuteError when a shared nested row is still referenced
  • Session snapshots — keyed by (entity_type, identity) instead of id(instance) for stable REPLACE behavior
  • Detached updates — load DB snapshot when session snapshot missing so REPLACE and updates work without prior get()
  • Pending writessave(flush_now=False) / delete(flush_now=False) auto-flush on session exit; clear_pending() clears graph sync queues
  • Importmodel_validate after hydrate; Optional[T] / int | None coercion
  • FastAPI OntoRouter — POST/PATCH validate bodies with generated Pydantic models; PATCH cannot retarget row via body id; list supports RDF Accept headers; offset validated ge=0
  • Invalid graph_sync_mode raises ValueError instead of silent no-op

0.3.1 - 2026-06-10

Added

  • PyPI release workflow (.github/workflows/release.yml) on v*.*.* tags

Changed

  • Test suite refactored for behavioral integration coverage; CI coverage threshold 94%
  • OntoRouter list limit capped at 100 via FastAPI Query(le=100)
  • Documentation: OntoRouter production limitations; CascadePolicy.REPLACE reserved (same as upsert until 0.4); export uses semantic onto_property metadata only; docs/DEPS.md synced with pyproject.toml

Fixed

  • ExecuteError raised when executing delete plans without a where clause
  • PyLD optional dependency pinned to >=3.0 (PyPI max is 3.0.0)
  • UPSERT nested insert with id=None now propagates inserted FK into parent row

0.3.0 - 2026-06-10

Added

  • Write pathOntoSession.save() / delete(), flush(), clear_pending(), identity map, partial updates
  • CascadePolicylink, upsert, replace, ignore on Map.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() and to_rdf(); ontosql.export helpers
  • Optional ontosql[sparql] extra; ECOSYSTEM.md

Changed

  • PrefixRegistry.expand() delegates to TripleModel expand_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

  • OntoModel and onto_property — Pydantic semantic entities with ontology metadata
  • OntoMapper, Map, and Map.nested — declarative bindings from semantic fields to SQL columns and joins
  • OntoSession (sync) and AsyncOntoSessionget, find, and execute_sql with semantic query expressions
  • PrefixRegistry — 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 worksFor over SQLite (sync and async)
  • Example: examples/person_org_demo.py
  • Documentation: ARCHITECTURE.md, SPECS.md, ROADMAP.md