oRm 0.6.0
Breaking Changes
-
Engine$hydrate()renamed toEngine$reflect()(andEngine$hydrate_schema()toEngine$reflect_schema()). The public verb now matches the internal reflection vocabulary it has always used (reflect_columns(),reflect_tables()) and the established ORM term for schema introspection (SQLAlchemy’sMetaData.reflect()). “Hydrate” conventionally means populating an object instance from a row, which is not what this method does — it builds a model from table metadata. There is no deprecation shim; update calls fromengine$hydrate(...)toengine$reflect(...).
New Features
-
Set-level CRUD on
TableModel— the CRUD spine is now complete and discoverable at the model level, mirroring the row-levelRecordverbs:-
Model$create(...)inserts a row (sugar overModel$record(...)$create()) and returns the persistedRecord. -
Model$update(...)issues a singleUPDATE ... WHERE. Bare expressions are the WHERE filter (likeread()); named arguments are the SET values (likecreate()), e.g.User$update(id == 1, name = "Kent", age = 35). -
Model$delete(...)issues a singleDELETE ... WHEREfrom bare-expression filters. -
update()/delete()return the affected-row count invisibly and refuse a filterless whole-table write unless.all = TRUE. Both require a primary key.
-
-
TableModel$define_relationship()method form —define_relationship()is now exposed as a model method that supplies the local model asself, making it discoverable via$-autocomplete per the verb-mirroring convention. The standalonedefine_relationship()function is retained for functional/pipe-style use and internal wiring; both share one implementation.
Bug Fixes
Double-qualification of table names in
Engine—Engine$model()andEngine$reflect()qualified the tablename before passing it toTableModel$new(), which qualified it again. Qualification now happens once, insideTableModel$new();reflect()keeps a locally qualified name only for column reflection.Single-column
read()— reads that project to a single column no longer collapse to an unnamed vector when building aRecord. Theget,one_or_none, andallmodes now usedrop = FALSEso the column name is preserved.
Documentation
- Renamed the “Hydrating Models from Existing Tables” vignette to “Reflecting Models from Existing Tables” and updated the README and
vignette("using-engine")for thereflect()/reflect_schema()naming.
oRm 0.5.0
New Features
-
PostgreSQL rich table reflection —
engine$hydrate()now captures full column metadata when using the PostgreSQL dialect:- Canonical types (e.g.
integer,text,timestamp with time zone) - Primary key flags, nullability, and column defaults
- Server-side defaults (sequences,
now(), etc.) stored asdbplyr::sql()objects and applied by the database at insert time - Foreign keys reflected as
ForeignKeyobjects, schema-qualified when the target lives in another schema
- Canonical types (e.g.
-
Schema-qualified foreign keys —
ForeignKey()now accepts cross-schema targets:- New
ref_schemaargument:ForeignKey("INTEGER", ref_schema = "other", ref_table = "users", ref_column = "id") - Three-part
referencesshorthand:ForeignKey("INTEGER", references = "other.users.id") -
render_constraint()emitsREFERENCES "other"."users" ("id")for cross-schema FKs
- New
-
Engine$hydrate_schema()— hydrate an entire schema in one call and auto-wire relationships:- Hydrates all (or a selected subset of) tables via
hydrate() - Turns every reflected
ForeignKeyinto amany_to_one/one_to_manyrelationship pair viadefine_relationship() - Accepts
tables,exclude,.schema, andwire_relationshipsarguments - Foreign keys pointing at tables outside the hydrated set emit a warning and are skipped
- Hydrates all (or a selected subset of) tables via
-
reflect_tables()generic — new dialect-dispatched function that lists the tables available in a schema:- Default implementation wraps
DBI::dbListTables() - PostgreSQL implementation queries
pg_catalog.pg_tablesfor the target schema
- Default implementation wraps
Improvements
-
Recordnow skips server-side defaults (dbplyr::sql()objects) at insert time, letting the database compute the value and relying onflush()to read it back
Documentation
- Updated README and
vignette("using-engine")to document PostgreSQL rich reflection, schema-qualified foreign keys, andhydrate_schema()
oRm 0.4.0
New Features
- Added
Method()function for attaching custom methods to models at both table and record levels- Table-level methods operate on the entire table for custom queries and bulk operations
- Record-level methods operate on individual records for instance-specific behavior
- Both method types have access to
selffor calling model/record methods
- Added automatic JSON serialization/deserialization for PostgreSQL
- JSON and JSONB columns automatically serialize R objects when writing to database
- Automatically deserialize JSON to R objects when reading from database
- Added
Engine(.read_only = TRUE)for read-only database access- Application-level guards block all INSERT, UPDATE, DELETE, CREATE TABLE, and DROP TABLE operations
- Dialect-level enforcement: SQLite uses the
SQLITE_ROopen flag; PostgreSQL setsdefault_transaction_read_only=onvia libpq; MySQL executesSET SESSION TRANSACTION READ ONLYpost-connect
- Added partial model support: a
TableModelcan declare a subset of an existing table’s columns-
read()projects results to only the declared fields, preventing undeclared columns from surfacing inRecordobjects - Useful for scoped, safe access to production tables with sensitive or irrelevant columns
-
-
create_table(overwrite = TRUE)now prompts for confirmation in interactive sessions- Pass
ask = FALSEto bypass the prompt in scripts and automated workflows
- Pass