@rvoh/dream
    Preparing search index...

    Class PostgresQueryDriver<DreamInstance>

    Type Parameters

    • DreamInstance extends Dream

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    connectionOverride: DbConnectionType | undefined
    dreamClass: DreamConstructorType<DreamInstance>
    dreamInstance: DreamInstance
    dreamTransaction: DreamTransaction<Dream, any> | null = null
    innerJoinDreamClasses: readonly typeof Dream[] = ...

    stores the Dream models joined in this Query instance

    query: Query<DreamInstance, any>
    supportsAdvisoryTransactionLocks: boolean = true

    Whether 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.

    supportsParallelTestDatabases: boolean = true

    Whether 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.

    Methods

    • Internal

      Postgres implementation of the row-locking seam: appends FOR UPDATE OF "<tableAlias>" to the select, so every row the statement returns is exclusively locked until the enclosing transaction ends.

      Scoping the lock to the Query's own base table (rather than a bare FOR UPDATE) means a query that joins other tables neither locks rows the caller never asked about nor raises Postgres's "FOR UPDATE cannot be applied to the nullable side of an outer join".

      This is a waiting lock: neither NOWAIT nor SKIP LOCKED is applied, so a statement that collides with another transaction's lock blocks until that transaction ends. Callers that cannot afford an unbounded wait should set a lock_timeout on the connection; see the guarded-destroy notes on Query#destroy.

      Parameters

      • kyselyQuery: SelectQueryBuilder<any, any, any>
      • tableAlias: string

      Returns SelectQueryBuilder<any, any, any>

    • Internal

      The 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. They are read off the same join code that emits them, by building the select.

      Returns OrderQueryStatement<string>[]

      An array of namespaced order statements

    • Retrieves the average value of the specified column for this Query

      await Game.query().avg('score')
      // 1

      Parameters

      • columnName: string

        a column name on the model

      Returns Promise<any>

      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 }

      Parameters

      • groupColumn: string

        the column to group by (base or joined-association-namespaced)

      • aggregatedColumn: string

        the column to average within each group

      Returns Promise<Map<any, any>>

      A Map from each present group value to the average of the aggregated column in that group

    • 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 }

      Parameters

      • groupColumn: string

        the column to group by (base or joined-association-namespaced)

      Returns Promise<Map<any, number>>

      A Map from each present group value to the number of records in that group

    • Internal

      This 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)
      

      Type Parameters

      Parameters

      • result: any
      • dreamClass: typeof Dream

      Returns RetType

    • Internal

      Used to hydrate dreams with the provided associations

      Parameters

      • dreams: Dream[]
      • association: AssociationStatement
      • preloadedDreamsAndWhatTheyPointTo: PreloadedDreamsAndWhatTheyPointTo[]

      Returns void

    • Internal

      The 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. They are read off the same join code that emits the joins, by building the select.

      Returns string[]

      An array of namespaced primary key columns

    • Retrieves the max value of the specified column for this Query

      await User.query().max('id')
      // 99

      Parameters

      • columnName: string

        a column name on the model

      Returns Promise<any>

      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 }

      Parameters

      • groupColumn: string

        the column to group by (base or joined-association-namespaced)

      • aggregatedColumn: string

        the column to take the max of within each group

      Returns Promise<Map<any, any>>

      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

      Parameters

      • columnName: string

        a column name on the model

      Returns Promise<any>

      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 }

      Parameters

      • groupColumn: string

        the column to group by (base or joined-association-namespaced)

      • aggregatedColumn: string

        the column to take the min of within each group

      Returns Promise<Map<any, any>>

      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}, ...]

      Type Parameters

      • SimpleFieldType extends
            | number
            | typeof iterator
            | "toString"
            | "charAt"
            | "charCodeAt"
            | "concat"
            | "indexOf"
            | "lastIndexOf"
            | "localeCompare"
            | "match"
            | "replace"
            | "search"
            | "slice"
            | "split"
            | "substring"
            | "toLowerCase"
            | "toLocaleLowerCase"
            | "toUpperCase"
            | "toLocaleUpperCase"
            | "trim"
            | "length"
            | "substr"
            | "valueOf"
            | "codePointAt"
            | "includes"
            | "endsWith"
            | "normalize"
            | "repeat"
            | "startsWith"
            | "anchor"
            | "big"
            | "blink"
            | "bold"
            | "fixed"
            | "fontcolor"
            | "fontsize"
            | "italics"
            | "link"
            | "small"
            | "strike"
            | "sub"
            | "sup"
            | "padStart"
            | "padEnd"
            | "trimEnd"
            | "trimStart"
            | "trimLeft"
            | "trimRight"
            | "matchAll"
            | "replaceAll"
            | "at"
            | "toLocaleString"
      • PluckThroughFieldType

      Parameters

      Returns SelectQueryBuilder<any, any, any>

      A Kysely SelectQueryBuilder instance

    • Internal

      A page of a select that carries DISTINCT ON (as a Query that calls distinct, or an association that declares distinct, produces), or null for any other select.

      Such a select keeps the row of each group that sorts first in its ORDER BY, so narrowing it to the rows after a cursor would let it keep a row it does not return (a group's later row, once the cursor has passed the group's first). It is read as a derived table instead, and narrowed to rowsAfter, sorted and limited outside it. The Query's order statements follow the select's own ORDER BY, if it has one, so that the select keeps the same row of each group every time it runs, and each of their columns is read out of it under a short alias (as pluck reads them), since a joined table's column cannot be named outside it.

      Parameters

      • rowsAfter: Record<string, unknown>[] | null

        where statements, any of which a row of the page matches

      Returns Promise<unknown[][] | null>

      The page's rows, each an array of its order statement columns' values, or null

    • Internal

      For a select that carries 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.

      The select runs as all() runs it, with its own ORDER BY choosing each group's row, and is read as a derived table, sorted outside it. Each of rowKeyColumns is read out of it under a short alias (as pluck reads them), since a joined table's column cannot be named outside it.

      Parameters

      • rowKeyColumns: string[]

        the namespaced columns that tell the select's rows apart

      Returns Promise<unknown[][] | null>

      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' ]
      //}

      Returns CompiledQuery<{ [key: string]: any }>

      An object representing the underlying sql statement

    • Retrieves the sum value of the specified column for this Query

      await Game.query().sum('score')
      // 1

      Parameters

      • columnName: string

        a column name on the model

      Returns Promise<any>

      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 }

      Parameters

      • groupColumn: string

        the column to group by (base or joined-association-namespaced)

      • aggregatedColumn: string

        the column to sum within each group

      Returns Promise<Map<any, any>>

      A Map from each present group value to the sum of the aggregated column in that group

    • Internal

      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()
      

      Parameters

      Returns Promise<DreamInstance[]>

      an array of dreams

    • executes provided query instance as an update query.

      Parameters

      • attributes: DrainOuterGeneric<
            {
                [K in string
                | number
                | symbol]?: UpdateType<DreamInstance["DB"][DreamInstance["table"]][K]>
            },
        >

      Returns Promise<number>

      the number of updated rows

    • Internal

      Postgres implementation of the transaction-scoped advisory lock seam.

      Uses the single-bigint form pg_advisory_xact_lock(bigint), whose lock space is distinct from the two-int4 form the test-database pool claims with (see openTestDatabaseLockSession), so an application lock can never collide with a pool claim.

      Every key is taken in one statement, over unnest of the key array: a function scan yields its rows in array order, so the caller's sorted acquisition order — the thing that keeps two operations over the same scopes from deadlocking — is preserved, while a batch that needs one key per candidate record costs one round trip rather than N.

      The locks are held until the enclosing transaction ends, and are waiting (no NOWAIT): a second transaction asking for the same key blocks at that key's row until the holder commits or rolls back. Because they are transaction-scoped there is nothing to release, and re-acquiring a key within one transaction is a no-op rather than an error.

      The wait is bounded by lock_timeout, taken from DreamApp.sortableScopeLockTimeout and applied to the acquisition statement alone: the prior value is read in the same statement that sets the bound and restored in the next one, so the transaction's row-lock waits keep whatever the application configured. Postgres cancels the statement with 55P03 when the bound elapses, and that is translated here into SortableScopeLockWaitTimedOut so no Postgres error code escapes the driver.

      A timeout of 0 means "no bound", which is what lock_timeout itself means by it, and is sent as the bound rather than skipped: an application whose connection carries a lock_timeout of its own would otherwise have its acquisition cancelled by that bound, which is neither the unbounded wait 0 asks for nor a cancellation this driver could translate.

      Parameters

      Returns Promise<void>

    • destroys a dream, possibly implementing soft delete if reallyDestroy is false and the record being deleted implements soft delete. Does nothing at all when a beforeDestroy hook called preventDeletion.

      Parameters

      • dream: Dream

        the dream instance you wish to destroy

      • txn: DreamTransaction<Dream>

        a transaction to encapsulate, consistently provided by underlying dream mechanisms

      • reallyDestroy: boolean

        whether or not to reallyDestroy. If false, soft delete will be attempted when relevant

      Returns Promise<number>

      the number of rows removed — zero when a preventDeletion veto stopped the write, and zero when the row was already gone, which on the soft delete path includes a row that is already soft deleted

    • Internal

      returns the foreign key type based on the primary key received. gives the driver the opportunity to switch i.e. bigserial to bigint.

      Parameters

      • primaryKey: LegacyCompatiblePrimaryKeyType

      Returns "bigint" | "integer" | "uuid"

    • This 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.

      Parameters

      • connectionName: string
      • migrationName: string
      • columnsWithTypes: string[]

      Returns Promise<void>

    • Reads the tables, views, materialized views, and partitioned and foreign tables of every schema the connection's user can use, except Postgres's own schemas, tables that inherit from another (partitions included) and Kysely's migration tables. A domain column reads as the type at the bottom of its domains. An enum outside the public schema is named <schema>.<name>.

      Parameters

      • connectionName: string

        the connection to read

      Returns Promise<IntrospectedDatabase>

    • Internal

      Whether 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.

      Parameters

      • error: unknown

      Returns boolean

    • Internal

      Whether 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.

      Parameters

      • error: unknown

      Returns boolean

    • Internal

      Postgres implementation of the per-worker test-database claim seam (see TestDatabaseLockSession and src/db/testDatabasePool.ts).

      Postgres advisory locks are global to the cluster (not scoped to a single database), so one dedicated connection — to the postgres maintenance database — can reserve a pool index for the whole cluster. We use the two-int4 form pg_try_advisory_lock(key1, key2), whose lock space is distinct from the single-bigint form pg_advisory_lock(bigint) that application code typically uses, so a claim can never clash with an app-level advisory lock. key1 folds a hash of the lock namespace (the base database name) into a fixed dream-pool constant; key2 is the pool index. The lock auto-releases when the connection drops on process exit.

      Parameters

      • connectionName: string

      Returns Promise<TestDatabaseLockSession>

    • persists 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.

      RETURNING * (rather than enumerating the compiled column list) keeps writes working under schema/image skew: during a rolling deploy, a container built before a drop-column migration would otherwise name the dropped column in RETURNING and fail with 42703 column does not exist on every write, even writes that never touch that column. The SET/VALUES half still names only dirty attributes, so a write that actually sets a dropped column still fails loudly. The returned row is filtered to the compiled column list before hydration (see internal/saveDream.ts), so a column the image doesn't know about never reaches setAttributes.

      KNOWN CONSTRAINT: star-selects are only safe because nothing in this stack uses named prepared statements — node-postgres prepares a statement only when given an explicit name, and Kysely never names them, so every query is re-planned. With named prepared statements, a concurrent ADD COLUMN changes a cached plan's result shape and Postgres raises cached plan must not change result type (the reason Rails added enumerate_columns_in_select_statements). If a future driver or pooling layer enables named prepared statements, revisit every RETURNING * / select * in this driver.

      Parameters

      Returns Promise<any>

    • Internal

      this 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.

      Parameters

      • connectionName: string

        the name of the connection you are doing this for

      Returns Promise<void>

      void

    • defines the syncing behavior for dream and psychic, which is run whenever the sync command is called.

      Parameters

      • connectionName: string
      • onSync: () => void | Promise<void>
      • options: { schemaOnly?: boolean } = {}

      Returns Promise<void>