Skip to content

Releases: vsdudakov/yara-orm

1.19.1 — decimal precision

Choose a tag to compare

@vsdudakov vsdudakov released this 12 Oct 18:48
dce645b

Decimal precision fix: a Decimal with more than 28 decimal places, such as 1 / Decimal("162.35"), now binds instead of failing with invalid decimal "…": Failed to parse, and DecimalField rounds to its decimal_places before binding, as Tortoise did. Highlights:

Fixed

  • Decimals with more than 28 decimal places bind instead of failing. The engine's rust_decimal holds at most 28 places, even though NUMERIC accepts any scale. The binder now rounds the extra fractional digits half away from zero, as PostgreSQL does. Values that fit still bind exactly. A value whose integer part is too large, NaN or infinity still raises, and the error now gives the limit. (#31)
  • DecimalField rounds to decimal_places before binding, half away from zero, so model writes store the column's scale on every backend, including SQLite, which has no column scale of its own. (#31)

Behaviour note: decimal values passed for a DecimalField, filter values included, are now rounded to the field's scale. On SQLite the stored text carries the full scale (1.5 is written as 1.5000000000); the value compares equal.

Full details in CHANGELOG.md.

1.19.0 — password provider

Choose a tag to compare

@vsdudakov vsdudakov released this 12 Oct 09:40
520a780

Password provider release: a PostgreSQL pool can now call a function for its password each time it opens a connection, so short-lived credentials such as RDS IAM tokens are created at connect time instead of being refreshed on a timer. Highlights:

Added

  • YaraOrm.set_password accepts a callable. The PostgreSQL pool calls it each time it opens a new connection and uses the string it returns, so an expiring credential such as an RDS IAM token is created at connect time instead of being refreshed on a timer. The callable runs on a worker thread, so a slow token fetch does not stall queries on connections already open. A plain string still works as before. Any other type raises TypeError. (#29, thanks @senhadjielrhazi)

Changed

  • Dev tooling moves into pyproject.toml dependency groups. ruff and ty are pinned in a lint group (ruff==0.17.0, ty==0.0.86); build and test tools are in a test group; dev includes both. CI and make dev install them with pip install --group …, so a new ty release can no longer fail lint on unrelated pull requests. (#30)
  • Build and docs minimums raised to maturin>=1.15.0 and mkdocs-material>=9.7.7.

Full details in CHANGELOG.md.

1.18.0 — password rotation

Choose a tag to compare

@vsdudakov vsdudakov released this 09 Oct 08:57

Password rotation release: a PostgreSQL pool can now take a new password without being rebuilt, so short-lived credentials such as RDS IAM tokens refresh without failing in-flight queries. Highlights:

Added

  • YaraOrm.set_password(password, connection="default") rotates a PostgreSQL pool's password in place. PostgreSQL checks the password only when a connection opens, so the next connection the pool opens presents the new one; the pool stays open and connections already in use keep working. Refresh an RDS IAM authentication token (15 minutes) on a shorter timer instead of opening a second pool and closing the one serving traffic, which failed in-flight queries with Pool has been closed. Until the first rotation the URL's password is used exactly as parsed. Other backends raise ValueError. (#28, thanks @senhadjielrhazi)

Changed

  • PostgreSQL connection errors carry the server's message and SQLSTATE. A failed connect used to surface as the driver's bare db error; it now reads e.g. password authentication failed for user "app" (SQLSTATE 28P01). Code that matched on the old db error text needs updating.

Full details in CHANGELOG.md.

1.17.0 — PostgreSQL sslmode follows libpq

Choose a tag to compare

@vsdudakov vsdudakov released this 09 Oct 08:57
d2dc791

PostgreSQL TLS release: sslmode now follows libpq, so managed databases with a private CA (RDS/Aurora, Cloud SQL, Azure) connect under the default mode again. Highlights:

Fixed

  • PostgreSQL sslmode now follows libpq. Every mode except disable verified the server certificate against the OS trust store, so prefer (the default, and the mode most URLs inherit without saying so) could not reach a managed database at all: RDS/Aurora, Cloud SQL and Azure present a certificate signed by their own private CA, and the handshake failed with UnknownIssuer before the first query. As in libpq (and therefore asyncpg and psycopg), prefer and require now encrypt without authenticating the server. The connection is still TLS; this is not a fallback to plaintext.

Added

  • sslmode=verify-ca and sslmode=verify-full are accepted in PostgreSQL URLs and are the way to ask for certificate verification now that require no longer implies it. verify-ca checks the chain, verify-full also checks the hostname.
  • sslrootcert=<path> adds the PEM roots in that file to the trust store for the verifying modes (typically the RDS/Cloud SQL CA bundle). As in libpq, it does not by itself turn verification on. An unreadable file, or one holding no certificate, is a configuration error rather than a silent fallback to the OS roots.

Full details in CHANGELOG.md.

1.16.0 — construction semantics

Choose a tag to compare

@vsdudakov vsdudakov released this 31 Aug 05:14
504a7da

Construction semantics release: an instance now agrees with the row it writes in four places that previously needed application-side shims, plus a bulk_update batching fix. Highlights:

Added

  • Model.__iter__: instances iterate as (name, value) pairs, so dict(instance) works and pair-walking consumers (pydantic from_attributes, serializers, factories) take a model directly. Declared columns first in declaration order, columns absent under only()/defer() skipped rather than fetched, private attributes omitted, Meta.extra_kwargs = "store" extras last.

Changed

  • An explicit <name>_id wins over a relation object at construction. Book(author=obj, author_id=x) used to store obj.pk; it now keeps x (by field name or db-column alias), and an object whose pk disagrees is not cached as the prefetched relation. Factories need this: a SubFactory is evaluated even when the caller passes author_id=. Passing only one form is unchanged.
  • auto_now_add fills the column instead of imposing a value. Backdated fixtures, imports and backfills keep the stamp they pass. auto_now still always stamps, as does a field declaring both.

Fixed

  • Foreign-key columns are coerced on assignment. create(parent_id=str(pk)) left the raw str on the instance, so child.parent_id == parent.id was False until re-fetch. ForeignKeyFieldInstance.to_python_value now mirrors to_db and the <name>_id column is normalised in __init__ like every other coerced column.
  • bulk_update respects the dialect's bind-parameter ceiling. Batches are clamped from max_bind_params (each row costs a (pk, value) pair per field plus a pk slot in WHERE ... IN), so a large batch_size no longer overflows PostgreSQL's 65535 / SQL Server's 2100 limit; SQLite now declares its default 32766.

Full details in CHANGELOG.md.

1.15.0 — custom PostgreSQL column types

Choose a tag to compare

@vsdudakov vsdudakov released this 16 Jul 08:25

Feature release: custom PostgreSQL column types (pgvector vector, inet, citext, ...) now work end-to-end through the ORM. Highlights:

Added

  • yara_orm.RawText: a thin str subclass that binds as an untyped text parameter on PostgreSQL — the server infers the type from context (target column, <=> operand) and parses the text through the type's own input function. Custom field kinds return it from to_db; previously every ORM INSERT/UPDATE into such a column failed with SQLSTATE 42804 unless the database installed a global CREATE CAST (text AS ...) WITH INOUT AS IMPLICIT. On every other backend it binds like a plain string.
  • Field.select_as_text: PostgreSQL SELECT/RETURNING projections read the column through CAST(col AS text) and to_python parses the text form — previously selecting a custom-typed column raised unsupported PostgreSQL type OID, forcing .defer() workarounds. Applied at every projection site (full-row, only()/defer(), select_related, values(), m2m prefetch, RETURNING) via the new BaseDialect.select_column hook; comparisons and grouping keep the column's real type.
  • The custom-fields guide documents both on a complete pgvector VectorField example.

Full details in CHANGELOG.md.

1.14.5 — create-path type coercion

Choose a tag to compare

@vsdudakov vsdudakov released this 16 Jul 07:15

Correctness fix release. Highlights:

Fixed

  • Create paths return canonical Python types: create(), get_or_create(), update_or_create(), bulk_create() and their QuerySet variants previously kept loose input (a string for a decimal or UUID column) as a raw str on the returned instance, while get() yielded Decimal/UUID. DecimalField, UUIDField, BooleanField (semantic string handling — bool("false") would be True), TimeDeltaField, IntEnumField and CharEnumField now normalise on assignment, so create(balance="12.34").balance is a Decimal and matches a fetched row.
  • update_from_dict (the update_or_create update path) applies the same coercion.
  • JSONField is deliberately unchanged (a string is a valid JSON value); int/float/char fields stay identity to keep the plain construction fast path.

Full details in CHANGELOG.md.

1.14.4 — correctness hotfix

Choose a tag to compare

@vsdudakov vsdudakov released this 10 Jul 22:00

Correctness hotfix release. Highlights:

Changed

  • ManyToManyField(through_fields=...) now reads Django's (owner_column, target_column) order — declarations written against the previous (forward_key, backward_key) reading must swap the two elements (the explicit forward_key=/backward_key= kwargs are unchanged).
  • Related-manager bulk writes are unscoped: parent.children.update(...)/.delete() reach every related row even under a soft-delete Meta.manager; reads keep the manager scope.

Fixed

  • Oracle: zero-fraction datetime binds compared unequal to stored values, so col >= :midnight dropped exact-midnight rows — such values now bind as DATE.
  • Datetime write paths: DatetimeField.to_db widens bare dates to midnight datetimes (plain-attribute save(), update(), bulk_update() no longer store date-only text); the __date lookup narrows its value to a date.
  • m2m cleanup is atomic on non-cascading dialects (SQL Server): a failed row delete no longer strips the surviving rows' join links.
  • SQL Server bulk_create: ids return via OUTPUT ... INTO (works with triggers, error 334 gone) in arrival order (correct under negative IDENTITY increments).
  • bulk_get_or_create/bulk_update_or_create accept a mix of explicit and auto pks.
  • PostgreSQL execute_many: numeric mixes widen to NUMERIC (no precision loss above 2^53); naive/aware datetime and str/UUID mixes are accepted.
  • Plus the fifteen correctness fixes from the full-codebase review (#18): ZoneInfo-aware binds, batch parameter-type unification, the sync-fast-path pool deadlock, get_or_create connection binding and root-filter inheritance, decode-plan snapshots, grouped-projection order_by annotations, and manager-scoped lazy relation reads.

Full details in CHANGELOG.md.

v1.14.3

Choose a tag to compare

@vsdudakov vsdudakov released this 08 Jul 11:31

Fixed

  • Custom-Prefetch correctness and performance. The custom-queryset M2M
    prefetch path decodes through-table link values the way hydration does, so
    pk types the driver returns in a non-native form (e.g. a CHAR(36) UUID pk
    on MySQL/MariaDB) group correctly instead of silently producing empty
    prefetched lists; the plain M2M join path decodes its owner-id column the
    same way. A target shared by several owners now deep-copies mutable column
    values (JSON dicts/lists), so mutating one owner's prefetched instance can
    no longer leak into another's. Per-owner LIMIT/OFFSET semantics now
    apply to every relation kind (reverse FK and forward FK, not just M2M),
    and the per-owner queries run concurrently outside a transaction instead of
    serially (no more N+1 latency for sliced prefetches).
  • Non-finite floats in JSON documents are rejected. Binding
    NaN/±Infinity inside a JSONField value now raises a clear
    ValueError (like json.dumps(..., allow_nan=False) and PostgreSQL's
    jsonb) instead of silently storing the strings "inf"/"NaN" (1.14.2)
    or null (≤ 1.14.1), both of which changed the member's type under readers
    and filters with no decode path back.
  • SQL Server connection URLs. An explicit trust_cert=true is honoured
    even with encrypt=strict, so "encryption required but trust the
    (self-signed) server cert" stays expressible; encrypt=strict alone still
    defaults to full certificate validation. Percent-decoding of URL
    credentials is no longer lossy: a %-sequence that does not decode to
    valid UTF-8 (a raw password merely containing %) passes through unchanged
    instead of being rewritten to U+FFFD.
  • Primary-key migrations. Moving the pk between columns now emits the
    demoting AlterField before the promoting one, so DROP PRIMARY KEY runs
    before ADD PRIMARY KEY ("multiple primary keys" previously aborted the
    migration when the promoted column diffed first). On MySQL/MariaDB,
    demoting an AUTO_INCREMENT pk first restates the column via
    MODIFY COLUMN to strip the flag (MySQL errno 1075 rejects dropping the
    pk of a live auto column).
  • bulk_create(update_fields=..., on_conflict=[]) on SQL Server. An
    explicit empty conflict target now takes the same unique-column
    substitution as an omitted one, instead of rendering a MERGE that matches
    on the uninserted auto pk column and failing.

yara-orm 1.14.2

Choose a tag to compare

@vsdudakov vsdudakov released this 07 Jul 11:07

Patch release: prefetch/dialect correctness fixes and hot-path optimizations.

Fixed

  • Prefetch correctness — custom Prefetch filters/ordering honoured for M2M; LIMIT/OFFSET/slice on a custom M2M Prefetch applies per owner; reverse-M2M managers read the cache under related_name (no more N+1).
  • Dialect / backend — PostgreSQL-only nested block comments (new nests_block_comments flag); MySQL/MariaDB escape backslashes in string literals; MSSQL percent-decodes URL credentials and honours ?encrypt=strict; SQLite rolls back on COMMIT failure; PostgreSQL clamps max_size to >= 1.
  • Query / field — relation fields named like lookup operators (slot__date) traverse correctly; FloatField coerces numeric strings; non-finite floats in JSON params preserved as text across both binders.
  • Migrations / models — primary-key change diffing renders ADD/DROP PRIMARY KEY per dialect; bulk_create(update_fields=..., on_conflict=[]) falls back to the pk target; compiled insert plan snapshotted before awaiting (concurrent cross-dialect save safety).

Changed

  • Hot-path optimizations — per-dialect compiled statement plan cache (O(1) restore); scalar-field compile path skips the relation probe; custom-M2M prefetch drops a redundant generator.
  • SQLite benchmarks use sync_fast_path — fastest on every SQLite op except the sub-millisecond group_by; SQLite/MariaDB tables and charts refreshed.

Full changelog: https://github.com/vsdudakov/yara-orm/blob/main/CHANGELOG.md