ProtectedconnectionProtected ReadonlydreamProtected ReadonlydreamProtecteddreamProtected Readonly InternalinnerStatic InternalsupportsWhether this driver implements the transaction-scoped advisory lock seam
(acquireAdvisoryTransactionLocks). Adapters that can hold a
key-addressed lock for the life of a transaction override this to true.
It defaults to false so that a driver without the primitive fails loud
for features that depend on it (today, the Sortable decorator) rather
than silently racing on position values.
Static InternalsupportsWhether this driver implements the per-worker test-database claim seam
(openTestDatabaseLockSession). Adapters that can hold a
process-lifetime, auto-releasing lock to reserve one database from the
test pool override this to true. It defaults to false so that a new
adapter fails loud under vitest rather than silently sharing a single
database across overlapping workers — see src/db/testDatabasePool.ts.
InternalAdapter seam for exclusive row locking. Given the select statement about to
be executed, return a statement that additionally acquires an exclusive
lock on each row it returns, held until the enclosing transaction commits
or rolls back (Postgres: SELECT ... FOR UPDATE OF <table>).
This is only ever reached when a caller opts into a locked read (today,
Query#destroy({ lock: true })), and only from inside a transaction. The
base implementation throws so that an adapter which has not implemented row
locking fails loud rather than silently performing an unlocked read and
quietly dropping the compare-and-set guarantee the caller asked for.
the select statement to lock
the alias of the Query's base table; only rows of that table are locked, so a joined query does not lock unrelated rows and does not fail on the nullable side of an outer join
ProtectedassertInternalPrevents mutation paths that discard an association query's ownership constraint.
InternalThe order statements that the declared order of the associations the
Query is built on or joins contributes to its ORDER BY, in the order they
sort, each column namespaced by the alias it is read from. Cursor
pagination folds these into its cursor.
An array of namespaced order statements
Retrieves the average value of the specified column for this Query
await Game.query().avg('score')
// 1
a column name on the model
the average of the values of the specified column for this Query
Retrieves the average of the specified column within each group, keyed by the value of the provided group column.
await CompositionAsset.query().avgBy('name', 'score')
// Map(2) { 'primary' => 5, 'secondary' => 4 }
the column to group by
the column to average within each group
A Map from each present group value to the average of the aggregated column in that group
Retrieves the number of records in the database
await User.query().count()
The number of records in the database
Retrieves the number of records in each group, keyed by the value of the provided group column.
await User.query().countBy('name')
// Map(2) { 'fred' => 2, 'zed' => 1 }
the column to group by
A Map from each present group value to the number of records in that group
InternalThis method is used internally by a Query driver to take the result of a single row in a database, and turn that row into the provided dream instance.
If needed, the return type can be overriden to explicitly define the resulting dream instance, in cases where a proper type for the dream class cannot be inferred, i.e.
this.dbResultToDreamInstance<typeof Dream, DreamInstance>(result, this.dreamClass)
executes provided query instance as a deletion query.
the number of deleted rows
InternalUsed to hydrate dreams with the provided associations
InternalUsed by loadBuider
InternalThe primary key of each table the Query reaches through a HasOne or HasMany association (one it joins, one an association it joins goes through, or one its association query is built on), namespaced by the alias it is read from, in join order. Such a join can return a row of the Query's table once for each row it matches, and these keys, with the Query's own primary key, tell those rows apart. Cursor pagination pages by them after the Query's own primary key.
An array of namespaced primary key columns
Retrieves the max value of the specified column for this Query
await User.query().max('id')
// 99
a column name on the model
the max value of the specified column for this Query
Retrieves the max value of the specified column within each group, keyed by the value of the provided group column.
await CompositionAsset.query().maxBy('name', 'score')
// Map(2) { 'primary' => 9, 'secondary' => 4 }
the column to group by
the column to take the max of within each group
A Map from each present group value to the max of the aggregated column in that group
Retrieves the min value of the specified column for this Query
await User.query().min('id')
// 1
a column name on the model
the min value of the specified column for this Query
Retrieves the min value of the specified column within each group, keyed by the value of the provided group column.
await CompositionAsset.query().minBy('name', 'score')
// Map(2) { 'primary' => 1, 'secondary' => 4 }
the column to group by
the column to take the min of within each group
A Map from each present group value to the min of the aggregated column in that group
Returns a new Kysely SelectQueryBuilder instance to be used in a sub Query
const records = await User.where({
id: Post.query().nestedSelect('userId'),
}).all()
// [User{id: 1}, ...]
the column to use for your nested Query
A Kysely SelectQueryBuilder instance
InternalRuns the query and extracts plucked values
An array of plucked values
InternalA page of a select that keeps one row of each group (DISTINCT ON, as a
Query that calls distinct, or an association that declares distinct,
produces), or null for any other select, whose pages cursor pagination
reads as it reads any select's.
The page is the values of the Query's order statement columns for each
row the select returns that matches any of rowsAfter (every row when it
is null), sorted by the Query's order statements and limited by its
limit. The select chooses each group's row before rowsAfter narrows the
rows, so that the page holds only rows the select returns.
A driver whose selects never keep one row of each group returns null.
where statements, any of which a row of the page matches
The page's rows, each an array of its order statement columns' values, or null
InternalFor a select that keeps one row of each group (DISTINCT ON, as a Query
that calls distinct, or an association that declares distinct,
produces), the values of rowKeyColumns for every row it returns, sorted
by those columns, ascending; null for any other select. findEach and
pluckEach read a select that keeps one row of each group from these
keys rather than by a cursor, which would narrow the select before it
chooses each group's row.
A driver whose selects never keep one row of each group returns null.
the namespaced columns that tell the select's rows apart
The rows' values of rowKeyColumns, or null
Returns the sql that would be executed by this Query
User.where({ email: 'how@yadoin' }).sql()
// {
// query: {
// kind: 'SelectQueryNode',
// from: { kind: 'FromNode', froms: [Array] },
// selections: [ [Object] ],
// distinctOn: undefined,
// joins: undefined,
// groupBy: undefined,
// orderBy: undefined,
// where: { kind: 'WhereNode', where: [Object] },
// frontModifiers: undefined,
// endModifiers: undefined,
// limit: undefined,
// offset: undefined,
// with: undefined,
// having: undefined,
// explain: undefined,
// setOperations: undefined
// },
// sql: 'select "users".* from "users" where ("users"."email" = $1 and "users"."deleted_at" is null)',
// parameters: [ 'how@yadoin' ]
//}
An object representing the underlying sql statement
Retrieves the sum value of the specified column for this Query
await Game.query().sum('score')
// 1
a column name on the model
the sum of the values of the specified column for this Query
Retrieves the sum of the specified column within each group, keyed by the value of the provided group column.
await CompositionAsset.query().sumBy('name', 'score')
// Map(2) { 'primary' => 10, 'secondary' => 4 }
the column to group by
the column to sum within each group
A Map from each present group value to the sum of the aggregated column in that group
Retrieves an array containing all records matching the Query.
Be careful using this, since it will attempt to pull every
record into memory at once. When querying might return a large
number of records, consider using .findEach, which will pull
the records in batches.
await User.query().all()
an array of dreams
InternalUsed for applying first and last queries
A dream instance or null
Converts the given dream class into a Kysely query, enabling you to build custom queries using the Kysely API
await User.query().toKysely('select').where('email', '=', 'how@yadoin').execute()
the type of Kysely query builder instance you would like to obtain
A Kysely query. Depending on the type passed, it will return either a SelectQueryBuilder, DeleteQueryBuilder, or an UpdateQueryBuilder
executes provided query instance as an update query.
the number of updated rows
StaticacquireInternalAcquire exclusive, transaction-scoped locks on arbitrary keys, waiting
until any other transaction holding one of them finishes. The locks are
released when the enclosing transaction commits or rolls back — never by an
explicit unlock — so callers only ever have to acquire (Postgres:
pg_advisory_xact_lock(bigint)).
Unlike applyRowLock, this does not depend on rows existing: it is
the only way to serialize writers that are about to insert into the same
logical group. The Sortable decorator uses it to make each sort scope's
position computation exclusive, keyed on the physical database, table,
position field and scope values.
The seam takes the whole key set rather than one key at a time so that a driver able to express it can take them in a single round trip — the batched, row-locking query APIs can need one key per candidate record per sortable field. Keys must be acquired in the order given: callers sort them, and that shared order is what keeps two operations over the same scopes from deadlocking. A driver that has no bulk form implements this by looping over the keys in order.
The wait must be bounded. A caller that finds a key held waits for the
holder's transaction, and an implementation that waits forever turns an
ordinary mistake — a sortable operation issued without the enclosing
transaction, so that it waits on a key that transaction itself holds — into
a permanently wedged connection that no deadlock detector can see, because
only one side is waiting. So an implementation applies the
sortableScopeLockTimeout DreamApp option (milliseconds) to the
acquisition and raises SortableScopeLockWaitTimedOut when it elapses. A
configured 0 means no bound, and is applied just as literally: the
acquisition waits without bound even where the connection carries a
wait bound of its own. The bound belongs to
the acquisition alone: whatever lock-wait behavior the connection was
configured with has to be in force again by the time this returns, so that
the row locks applyRowLock takes are unaffected.
Only ever called when supportsAdvisoryTransactionLocks is true;
the base default throws.
the transaction the locks are scoped to
the 64-bit signed lock keys, in acquisition order
Staticdbcreate the database. Must respond to the NODE_ENV value.
Staticdbdelete the database. Must respond to the NODE_ENV value.
Staticdestroydestroys a dream, possibly implementing soft delete if reallyDestroy is false and the record being deleted implements soft delete.
the dream instance you wish to destroy
a transaction to encapsulate, consistently provided by underlying dream mechanisms
whether or not to reallyDestroy. If false, soft delete will be attempted when relevant
the number of rows this call removed (or soft deleted). Zero means
the row was already gone, or that a preventDeletion veto stopped the
write — callers distinguish the two by the veto flag, and use the count to
decide whether there is anything for the after-destroy hooks to act on.
StaticduplicateStaticensureStaticforeignInternalreturns the foreign key type based on the primary key received. gives the driver the opportunity to switch i.e. bigserial to bigint.
StaticgenerateThis should build a new migration file in the migrations folder
of your application. This will then need to be read and run
whenever the migrate method is called. The filename should
contain a timestamp at the front of the filename, so that it
is sorted by date in the file tree, and, more importantly, so
they can be run in order by your migration runner.
StaticintrospectReads the tables, columns and enums of the connection's database, from
which sync writes the connection's types/db.ts and types/dream.ts.
It returns every table the connection can read, sorted by schema and
name; sync applies tableIncludePattern and tableExcludePattern
itself.
the connection to read
StaticisInternalWhether error is the database aborting a transaction to break a deadlock
with another. withConcurrentWriterRetry reruns a transaction of Dream's
own that was aborted this way. A driver that does not recognize one reports
false, and nothing is retried.
StaticisInternalWhether error is the database refusing a write for violating a unique
constraint. withConcurrentWriterRetry asks this of an error raised at
COMMIT, which is where a DEFERRABLE INITIALLY DEFERRED constraint — the
one DreamMigrationHelpers.addDeferrableUniqueConstraint declares — reports
a collision. A driver that does not recognize one reports false, and nothing
is retried.
Staticmigratemigrate the database. Must respond to the NODE_ENV value.
StaticopenInternalOpen a dedicated, process-lifetime lock session used to claim one database
from the per-worker test pool. Only ever called when
supportsParallelTestDatabases is true; the base default throws.
The returned session wraps a single dedicated connection: the orchestrator
(src/db/testDatabasePool.ts) probes many pool indexes on the one session
via tryAcquire and keeps whichever it acquires, holding it for the
worker's lifetime.
StaticprimaryInternalused to return the computed primary key type based on the primaryKeyType set in the DreamApp class.
Staticrollbackrollback the database. Must respond to the NODE_ENV value.
Staticsavepersists any unsaved changes to the database. If a transaction is provided as a second argument, it will use that transaction to encapsulate the persisting of the dream, as well as any subsequent model hooks that are fired.
StaticsetInternalthis method is called when dream is initializing, and is used to configure the database to utilize custom type parsers for a variety of data types.
the name of the connection you are doing this for
void
Staticsyncdefines the syncing behavior for dream and psychic,
which is run whenever the sync command is called.
This is an important step, and will be incredibly
comlpex to override. You will need to do the following
when overriding this method:
StatictransactionBuilds a new DreamTransaction instance, provides the instance to the provided callback.
await ApplicationModel.transaction(async txn => {
const user = await User.txn(txn).create({ email: 'how@yadoin' })
await Pet.txn(txn).create({ user })
})
A callback function to call. The transaction provided to the callback can be passed to subsequent database calls within the transaction callback
void
stores the Dream models joined in this Query instance