@fabrika/db 0.9.0-dev.1 → 0.9.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ import { type Session } from './database';
2
+ import type { Primitive } from './description';
3
+ import type { TableModel } from './policy';
4
+ /** Where a site's file references belong, and what claiming a pending one needs. */
5
+ export interface FileBinding {
6
+ /** The work a reference of this site belongs to: one request, or one job attempt. */
7
+ readonly holder: object;
8
+ /** The id a pending file must carry to be claimed here: the request (or attempt) that staged it. */
9
+ readonly request: string;
10
+ /** How long a pending file may wait for its first reference. */
11
+ readonly graceMs: number;
12
+ /** Whether files of `kind` wait for a clean scan: a claimed one is `quarantined` until then. */
13
+ scans(kind: string): boolean;
14
+ }
15
+ /**
16
+ * Puts a file reference in each file column of `rows`, read with `action` in `session`: one statement loads every
17
+ * file's metadata. Without a binding (a store's own runner) the columns keep their ids.
18
+ */
19
+ export declare function answerFiles<R>(model: TableModel, binding: FileBinding | undefined, session: Session, rows: R[], action: string): Promise<R[]>;
20
+ /**
21
+ * A write's value for a file column: `null`, or the id of a file reference of the column's kind. A string id, a copied
22
+ * object or a reference of another kind is refused; whether the site holds it is checked where the write runs.
23
+ */
24
+ export declare function fileValue(model: TableModel, column: string, value: unknown): string | null;
25
+ /**
26
+ * The top-level scope a row of `model` lies in, from the values it is written with: `<dimension>:<value>`, or `null` for
27
+ * an application table, which sets no scope.
28
+ */
29
+ export declare function rowScope(model: TableModel, values: ReadonlyMap<string, Primitive | null>): string | null | undefined;
30
+ /** The top-level scope of the row whose key is `key`, read in `session`: what an update's file references are stamped with. */
31
+ export declare function storedRowScope(model: TableModel, session: Session, key: string, keyValue: string): Promise<string | null>;
32
+ /**
33
+ * The file references of a write, in `session` (its transaction), after its statement: each file is locked `for share`
34
+ * while its state is checked, a pending one this request staged within the grace is claimed, and the first reference
35
+ * from a dimensional table stamps its scope; a reference from another top-level scope is refused.
36
+ */
37
+ export declare function referenceFiles(model: TableModel, binding: FileBinding | undefined, session: Session, values: ReadonlyMap<string, Primitive | null>, scope: () => Promise<string | null>): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import type { StoredFileMeta, StoredFileStatus } from './stored-files';
2
+ /** What a handler sees of a stored file: its metadata, never its object. */
3
+ export interface FileReference {
4
+ readonly id: string;
5
+ readonly name: string | null;
6
+ readonly type: string;
7
+ readonly size: number;
8
+ readonly status: StoredFileStatus;
9
+ }
10
+ /** Whose a reference is, and what it lets that work do. */
11
+ export interface FileHolding {
12
+ readonly id: string;
13
+ readonly kind: string;
14
+ /** The work that holds it: one request, or one job attempt. */
15
+ readonly holder: object;
16
+ /** Read under an action that reads the file (or received, or put): it may be written into a column, served and opened. */
17
+ readonly readable: boolean;
18
+ }
19
+ /**
20
+ * A reference to a file for `holder`; only `@fabrika/db` and the framework mint one. A `readable` one also lets its
21
+ * holder write the file into a column, serve it and open it, through any reference to the same file.
22
+ */
23
+ export declare function fileReference(meta: StoredFileMeta, holder: object, readable: boolean): FileReference;
24
+ /** What a reference holds, or `undefined` for any other value: a structural copy, a string id or a forged object. */
25
+ export declare function fileHoldingOf(value: unknown): FileHolding | undefined;
26
+ /** Whether `holder` received, put, or read under a read action the file `id`. */
27
+ export declare function holdsFile(holder: object, id: string): boolean;
@@ -0,0 +1,59 @@
1
+ import { type Session } from './database';
2
+ import type { DataLayerRuntime } from './store';
3
+ /** One webhook binding: the scope value it reaches, the provider account it accepts, and its signing secret. */
4
+ export interface WebhookBinding {
5
+ readonly id: string;
6
+ /** The webhook mount's name. */
7
+ readonly webhook: string;
8
+ readonly scope: {
9
+ readonly type: string;
10
+ readonly value: string;
11
+ };
12
+ /** The provider account: for GitHub, `installation:<id>` or `repository:<id>`, which a delivery must name. */
13
+ readonly account: string;
14
+ readonly secret: string;
15
+ }
16
+ export interface NewWebhookBinding extends WebhookBinding {
17
+ readonly createdBy: string;
18
+ readonly createdAt: number;
19
+ }
20
+ export interface WebhookTables {
21
+ /** Records a binding, in `using` when given: the transaction of the procedure that binds. */
22
+ createBinding(binding: NewWebhookBinding, using?: Session): Promise<void>;
23
+ /** The binding `id` of `webhook`, or `null`. */
24
+ binding(webhook: string, id: string): Promise<WebhookBinding | null>;
25
+ /**
26
+ * Replaces the secret of the binding when it belongs to `webhook` and `scope`, in `using` when given: a provider that
27
+ * issues its own signing secret shows it only after the binding's URL is registered. `false` when there was none.
28
+ */
29
+ replaceSecret(webhook: string, id: string, scope: {
30
+ readonly type: string;
31
+ readonly value: string;
32
+ }, secret: string, using?: Session): Promise<boolean>;
33
+ /** Removes the binding when it belongs to `webhook` and `scope`, in `using` when given; `false` when there was none. */
34
+ removeBinding(webhook: string, id: string, scope: {
35
+ readonly type: string;
36
+ readonly value: string;
37
+ }, using?: Session): Promise<boolean>;
38
+ /**
39
+ * Claims a delivery key for `leaseMs`: `null` when the binding completed it within the retention window, or another
40
+ * copy holds an unexpired claim. A claim whose lease expired is taken over. Keys of the binding older than
41
+ * `retainedSince` are dropped first, so the table stays bounded.
42
+ */
43
+ claimDelivery(bindingId: string, deliveryKey: string, now: number, leaseMs: number, retainedSince: number): Promise<DeliveryClaim | null>;
44
+ /**
45
+ * Completes a claimed delivery in `using`, the transaction its handler wrote in, so the work and the completion
46
+ * commit together; `false` when another copy took the claim over meanwhile, and that transaction must not commit.
47
+ * Without `using` (a handler with no transaction) it completes on its own.
48
+ */
49
+ completeDelivery(claim: DeliveryClaim, using?: Session): Promise<boolean>;
50
+ /** Gives a claim back after its handler failed, so the provider's redelivery runs it again at once. */
51
+ releaseDelivery(claim: DeliveryClaim): Promise<void>;
52
+ }
53
+ /** One copy's claim on a delivery: its lease end fences the completion against a copy that took the claim over. */
54
+ export interface DeliveryClaim {
55
+ readonly bindingId: string;
56
+ readonly key: string;
57
+ readonly leaseUntil: number;
58
+ }
59
+ export declare function webhookTables(runtime: () => DataLayerRuntime): WebhookTables;
@@ -0,0 +1,32 @@
1
+ import type { DataAccess } from './orm';
2
+ import { type FrameworkTables, type Locator } from './registry';
3
+ import type { DataLayerRuntime } from './store';
4
+ export type { Admissions } from './admissions';
5
+ export type { LeaseFence } from './capability';
6
+ export type { InvocationTransaction, Session } from './database';
7
+ export { CAPABILITY_ERRORS, CapabilityError, type CapabilityErrorReason, LeaseLostError, QUERY_REFUSALS, type QueryRefusal, QueryRefusedError, } from './errors';
8
+ export type { FileBinding } from './file-columns';
9
+ export { type FileHolding, fileHoldingOf, type FileReference, fileReference, holdsFile } from './file-references';
10
+ export type { DeliveryClaim, NewWebhookBinding, WebhookBinding, WebhookTables } from './framework-tables';
11
+ export type { JobLeases, JobLeaseState, JobOutcome, OverdueClaim } from './job-leases';
12
+ export type { DataAccess, DataHandles, DataSite } from './orm';
13
+ export type { FrameworkTables, Locator } from './registry';
14
+ export type { SqlMode, SqlSite, SqlTag, SqlValue } from './sql';
15
+ export type { FileColumnRef, QuarantinedStoredFile, ServedFile, StagedFile, StoredFileMeta, StoredFiles, StoredFileStatus } from './stored-files';
16
+ /** Whether `value` is an object `scoped(tables)` created, rather than a look-alike with the same fields. */
17
+ export declare function isScopedDatabase(value: unknown): boolean;
18
+ /**
19
+ * Connects the layer `scoped(tables)` created to `runtime`, once, and answers its locator, which nothing else can
20
+ * reach. Throws for any other value and for a layer that is already connected.
21
+ */
22
+ export declare function bindScopedDatabase(value: unknown, runtime: DataLayerRuntime): Locator;
23
+ /**
24
+ * The framework's own writes over the layer `scoped(tables)` created: the webhook tables, the job leases and the
25
+ * admission counters. Each operation needs the layer bound first. Throws for any other value.
26
+ */
27
+ export declare function frameworkTablesOf(value: unknown): FrameworkTables;
28
+ /**
29
+ * The mini-ORM of the layer `scoped(tables)` created: the invocation transactions and the `ctx.db` handles the
30
+ * framework builds per site. Each operation needs the layer bound first. Throws for any other value.
31
+ */
32
+ export declare function dataAccessOf(value: unknown): DataAccess;
@@ -0,0 +1,23 @@
1
+ import type { OperationNode } from 'kysely';
2
+ export type RootKind = 'SelectQueryNode' | 'InsertQueryNode' | 'UpdateQueryNode' | 'DeleteQueryNode';
3
+ export interface ForeignKeyPair {
4
+ readonly childColumn: string;
5
+ readonly parentColumn: string;
6
+ }
7
+ export interface GuardContext {
8
+ readonly root: RootKind;
9
+ readonly table: string;
10
+ /** The children a select may join, each with the composite foreign key its ON must equal. */
11
+ readonly joins: Readonly<Record<string, readonly ForeignKeyPair[]>>;
12
+ /** The scope predicate; it must be the WHERE itself or its top-level right conjunct. Absent for an insert only. */
13
+ readonly scope: OperationNode | undefined;
14
+ /**
15
+ * A select that locks its rows: `share` is the layer's check of a mutation's destination, `update` a mutation's
16
+ * `getForUpdate` of its own target, `claim` a queue claim's `for update skip locked`. No other lock is admitted.
17
+ */
18
+ readonly lock?: 'share' | 'update' | 'claim';
19
+ /** An insert that does nothing on a conflict of its listed columns: `on conflict (columns) do nothing`, and no other. */
20
+ readonly onConflict?: 'nothing';
21
+ }
22
+ /** Refuses any operation tree outside the allowlist. Runs on the final tree, immediately before it is compiled. */
23
+ export declare function assertAllowedTree(root: OperationNode, context: GuardContext): void;
@@ -0,0 +1,4 @@
1
+ /** `^[a-z_][a-z0-9_]*$`, at most 63 characters (Postgres truncates longer names). */
2
+ export declare function isPlainIdentifier(value: unknown): value is string;
3
+ /** A plain identifier, or two joined by one dot (`note_comments.body`, the alias of a joined column). */
4
+ export declare function isPlainAlias(value: unknown): value is string;
@@ -0,0 +1,10 @@
1
+ export type { AppCapability, AppGrant, CapabilityAuthority, CapabilityGrant, ContainerGrant, LeaseFence, Ref, RefGrant, RowGrant, RowRef, Within, WithinGrant, } from './capability';
2
+ export { MAX_WITHIN_VALUES } from './capability';
3
+ export { applicationSchema, Database, type PostgresOptions } from './database';
4
+ export type { AllowedOperator, ComparisonOperator, ConditionTuple, ListOperator, NoColumns, NullOperator, PatternOperator, Primitive, ScopedSelect, } from './description';
5
+ export { CAPABILITY_ERRORS, CapabilityError, type CapabilityErrorReason, DatabaseError, LeaseLostError, PolicyError, QUERY_REFUSALS, type QueryRefusal, QueryRefusedError, } from './errors';
6
+ export type { AnyDbIndex, ChildRows, ContainedRows, CountOptions, DataKind, DbIndex, IndexedTable, ListOptions, ListPage, NoUnscoped, OrderTerm, OwnerRow, ReadOnlyUnscoped, ReferenceRows, ReferenceTables, RowFor, Saved, ScopeTarget, TargetForm, TargetRow, Unavailable, UnownedTarget, UnscopedDeclaration, UnscopedInsert, UnscopedMode, UnscopedRows, UnscopedTables, VersionArguments, WithinRows, WithinTables, } from './orm-types';
7
+ export { type ChildPolicy, type ChildScope, type ColumnList, defineTables, type DimensionPolicy, type DimensionScope, type InsertValues, isTables, readTables, type RecordActions, type ReferencePolicy, type ReferenceScope, type RowOf, type TableActions, type TableInsert, Tables, type TableUpdate, type UpdateValues, type VersionColumn, type VocabularyTables, } from './policy';
8
+ export { type AggregateRow, type AggregateSpec, type ChildListScope, type DataLayer, type DataLayerRuntime, scoped, type ScopedDatabase, } from './store';
9
+ export { type TablePolicies, tablePolicies } from './tables';
10
+ export type { ColumnTypes, DefineVocabularyPolicies, NormalizedPolicies, TableVocabulary, TypedColumnList, VocabularyAction, VocabularyChildScope, VocabularyContainer, VocabularyContainerOf, VocabularyDimension, VocabularyDimensionScope, VocabularyPolicyMap, VocabularyTablePolicy, } from './vocabulary-tables';
@@ -0,0 +1,84 @@
1
+ import type { LeaseFence } from './capability';
2
+ import { type Session } from './database';
3
+ import type { DataLayerRuntime } from './store';
4
+ export type JobOutcome = 'succeeded' | 'failed';
5
+ export interface JobLeaseState {
6
+ readonly generation: number;
7
+ /** The attempt holding the lease, or `null` when it is free. */
8
+ readonly holder: string | null;
9
+ readonly expiresAt: Date;
10
+ /** The holding attempt's deadline: no write of it commits after this. */
11
+ readonly attemptDeadline: Date;
12
+ /** When the job was first seen in this schema: the baseline of a job that never succeeded. */
13
+ readonly firstSeenAt: Date;
14
+ readonly lastStartedAt: Date | null;
15
+ readonly lastFinishedAt: Date | null;
16
+ readonly lastStatus: JobOutcome | null;
17
+ readonly lastSucceededAt: Date | null;
18
+ readonly lastDurationMs: number | null;
19
+ readonly lastMissedReportedAt: Date | null;
20
+ }
21
+ /** A job overdue by twice its period, claimed for one report. */
22
+ export interface OverdueClaim {
23
+ readonly lastSucceededAt: Date | null;
24
+ readonly firstSeenAt: Date;
25
+ }
26
+ export interface JobLeases {
27
+ /** The database's clock. */
28
+ now(): Promise<Date>;
29
+ /** Records that the job exists (its first-seen time), once; later calls change nothing. */
30
+ register(job: string): Promise<void>;
31
+ /**
32
+ * Frees a lease whose holder never finished before it expired (the run crashed) and records the run as failed.
33
+ * `true` for the one caller that freed it.
34
+ */
35
+ reapCrashed(job: string): Promise<boolean>;
36
+ /**
37
+ * A free lease for `holder`, under a new generation, for `leaseMs`; its attempt may write for `attemptMs`. `null`
38
+ * while another run holds it.
39
+ */
40
+ acquire(job: string, holder: string, attemptMs: number, leaseMs: number): Promise<LeaseFence | null>;
41
+ /**
42
+ * `acquire` of a registered job that never waits for a lock: `null` at once while another run holds the lease or an
43
+ * attempt's transaction holds its row. A kick takes the lease only this way, on a connection requests share.
44
+ */
45
+ tryAcquire(job: string, holder: string, attemptMs: number, leaseMs: number): Promise<LeaseFence | null>;
46
+ /**
47
+ * Hands a live lease to the next attempt under a new generation, so no write of the previous attempt commits from
48
+ * now on. `null` when `fence` no longer holds it.
49
+ */
50
+ renew(fence: LeaseFence, holder: string, attemptMs: number, leaseMs: number): Promise<LeaseFence | null>;
51
+ /** Frees the lease and records the run's outcome and duration; `false` when `fence` no longer held it. */
52
+ finish(fence: LeaseFence, outcome: JobOutcome): Promise<boolean>;
53
+ /** Records that a kick arrived: the run that started before it runs the job once more. Never waits on the lease. */
54
+ markPending(job: string): Promise<void>;
55
+ /**
56
+ * Clears the flag `markPending` set; `true` for the one caller that cleared it. A run clears it when it starts (it
57
+ * covers every kick before it) and again after it succeeded, when `true` means one more run.
58
+ */
59
+ takePending(job: string): Promise<boolean>;
60
+ /**
61
+ * Claims one report of a job that has not succeeded within twice `periodMs`, at most once per period: only the
62
+ * caller that gets the claim reports.
63
+ */
64
+ claimOverdue(job: string, periodMs: number): Promise<OverdueClaim | null>;
65
+ /**
66
+ * Refuses every further write of the attempt `fence` names and cancels the statements it still has running; the
67
+ * runner calls it when the attempt ends.
68
+ */
69
+ cancelInFlight(fence: LeaseFence): Promise<void>;
70
+ state(job: string): Promise<JobLeaseState | null>;
71
+ }
72
+ /**
73
+ * The database's clock inside `session`'s transaction: a queue claim compares and moves `due` by it, so no process
74
+ * clock decides when a row is due.
75
+ */
76
+ export declare function databaseNow(session: Session): Promise<Date>;
77
+ /**
78
+ * Runs `work` in a mutation's transaction under `fence`. Before it: the attempt still holds its lease, the lease row
79
+ * stays locked `for share` until the commit (a takeover or a renewal waits), and every statement is bounded by the
80
+ * attempt's remaining time. After it, just before the commit: the attempt still holds the lease within its deadline.
81
+ * Otherwise the transaction rolls back with `LeaseLostError`; so does a statement the deadline or the runner cancelled.
82
+ */
83
+ export declare function fencedTransaction<T>(session: Session, fence: LeaseFence, work: (transaction: Session) => Promise<T>): Promise<T>;
84
+ export declare function jobLeases(runtime: () => DataLayerRuntime): JobLeases;
@@ -0,0 +1,13 @@
1
+ import type { OperationNode } from 'kysely';
2
+ import type { RefGrant } from './capability';
3
+ import type { Container } from './policy';
4
+ export interface LinkValue {
5
+ readonly link: Container;
6
+ readonly value: string;
7
+ }
8
+ /**
9
+ * The column values a Ref addresses over `links`: the first link takes the Ref's id, every other link a value
10
+ * from its chain. A chain entry no link covers cannot be enforced, so it is refused rather than ignored.
11
+ */
12
+ export declare function linkValues(table: string, links: readonly Container[], grant: RefGrant): readonly LinkValue[];
13
+ export declare function linksPredicate(table: string, values: readonly LinkValue[]): OperationNode;
@@ -0,0 +1,25 @@
1
+ /** Migration identity of the framework's tables in every application schema: bundle `fabrika`, same ledger. */
2
+ export declare const FRAMEWORK_MIGRATION_BUNDLE = "fabrika";
3
+ export declare const WEBHOOK_BINDINGS_TABLE = "fabrika_webhook_bindings";
4
+ export declare const WEBHOOK_DELIVERIES_TABLE = "fabrika_webhook_deliveries";
5
+ export declare const JOB_LEASES_TABLE = "fabrika_job_leases";
6
+ export declare const JOB_KICKS_TABLE = "fabrika_job_kicks";
7
+ export declare const FORM_ADMISSIONS_TABLE = "fabrika_form_admissions";
8
+ export declare const FORM_CHALLENGES_TABLE = "fabrika_form_challenges";
9
+ export declare const FORM_FILES_TABLE = "fabrika_form_files";
10
+ export declare const FORM_BYTES_TABLE = "fabrika_form_bytes";
11
+ export declare const FILES_TABLE = "fabrika_files";
12
+ export declare const FILE_DELETIONS_TABLE = "fabrika_file_deletions";
13
+ /** The function an application's last adoption migration calls with the name of a file collection it adopted. */
14
+ export declare const FILES_RELEASE_FUNCTION = "fabrika_files_release";
15
+ /**
16
+ * The function an adoption migration calls right before it reads a collection's table: it copies the rows an older
17
+ * instance wrote since 0008 ran, so each one it adopts has its `fabrika_files` row. Idempotent.
18
+ */
19
+ export declare const FILES_COPY_FUNCTION = "fabrika_files_copy_legacy";
20
+ export interface FrameworkMigration {
21
+ /** Ordered by name; an applied one is immutable, like an application's. */
22
+ readonly name: string;
23
+ readonly sql: string;
24
+ }
25
+ export declare const FRAMEWORK_MIGRATIONS: readonly FrameworkMigration[];
@@ -0,0 +1,62 @@
1
+ import { type DeleteQueryNode, type InsertQueryNode, type OperationNode, ReferenceNode, ReturningNode, type SelectQueryNode, type UpdateQueryNode, WhereNode } from 'kysely';
2
+ import { type NameSet } from './builtins';
3
+ import type { Condition, Primitive, SelectState } from './description';
4
+ export declare function column(table: string, name: string): ReferenceNode;
5
+ export declare function equals(table: string, name: string, value: Primitive): OperationNode;
6
+ export declare function allOf(nodes: readonly OperationNode[]): OperationNode;
7
+ /** One node, or the OR of several in a parenthesis: inside an AND, `a and b or c` would read as `(a and b) or c`. */
8
+ export declare function anyOf(nodes: readonly OperationNode[]): OperationNode;
9
+ export declare function inList(table: string, name: string, values: readonly string[]): OperationNode;
10
+ /** The scope of a `Within` that is not limited to scope values. */
11
+ export declare function everything(): OperationNode;
12
+ /** LIKE treats `\` as its escape character by default, so the text matches literally. */
13
+ export declare function containsPattern(text: string): string;
14
+ /**
15
+ * The caller's conditions go inside an explicit parenthesis and the scope is the top-level right conjunct, so
16
+ * `x or true` cannot escape it. The guard checks this shape.
17
+ */
18
+ export declare function scopedWhere(conditions: OperationNode | undefined, scope: OperationNode): WhereNode;
19
+ /** `returning key as id[, version as version]`: a mutation's acknowledgement, never row data. */
20
+ export declare function acknowledgement(table: string, key: string, version: string | undefined): ReturningNode;
21
+ /** `after` is a keyset page's position, ANDed to the caller's conditions inside their parenthesis. */
22
+ export declare function selectNode(state: SelectState, visible: readonly string[], scope: OperationNode, after?: OperationNode, days?: NameSet): SelectQueryNode;
23
+ export interface AggregateColumns {
24
+ readonly groupBy: readonly string[];
25
+ readonly count: boolean;
26
+ readonly sum: readonly string[];
27
+ readonly min: readonly string[];
28
+ readonly max: readonly string[];
29
+ }
30
+ export declare function aggregateNode(table: string, columns: AggregateColumns, conditions: readonly Condition[], scope: OperationNode, days?: NameSet): SelectQueryNode;
31
+ /** `conflict` names the columns of a unique index the insert does nothing on: `on conflict (<columns>) do nothing`. */
32
+ export declare function insertNode(table: string, values: ReadonlyMap<string, Primitive | null>, answer: ReturningNode, conflict?: readonly string[]): InsertQueryNode;
33
+ export declare function updateNode(table: string, values: ReadonlyMap<string, Primitive | null>, bump: string | undefined, where: WhereNode, answer: ReturningNode): UpdateQueryNode;
34
+ export declare function deleteNode(table: string, where: WhereNode, key: string): DeleteQueryNode;
35
+ /** `select key from table where (conditions) and scope limit 1`: does the scoped object exist? */
36
+ export declare function existsNode(table: string, key: string, scope: OperationNode, conditions?: OperationNode): SelectQueryNode;
37
+ /** `select key as id, version as version from table where (conditions) and scope limit 1`: an update that sets nothing. */
38
+ export declare function acknowledgementNode(table: string, key: string, version: string | undefined, where: WhereNode): SelectQueryNode;
39
+ /** `select columns from table where scope limit 1`: the containment columns of one object, for the framework's locator. */
40
+ export declare function locateNode(table: string, columns: readonly string[], scope: OperationNode): SelectQueryNode;
41
+ /**
42
+ * The same check, locked: `for share` keeps the row from moving until the transaction that checked it ends, `for
43
+ * update` also keeps every other writer and locker of it waiting.
44
+ */
45
+ export declare function lockNode(table: string, key: string, scope: OperationNode, lock?: 'share' | 'update'): SelectQueryNode;
46
+ /** The alias a keyset page's position column is selected under; a column name holds no dot, so none collides. */
47
+ export declare function cursorAlias(index: number): string;
48
+ /** `select …, cast(<column> as text) as "keyset.c<n>"`: each order column's exact value, which a Date would round. */
49
+ export declare function withCursorColumns(node: SelectQueryNode, table: string, columns: readonly string[]): SelectQueryNode;
50
+ /**
51
+ * A queue claim's lease: `select <columns> from table where (<conditions> and (<due> is not null and <due> <= $now and
52
+ * <attempts> < $max)) and scope order by <due>, <key> limit $n for update skip locked`. A row another claim holds is
53
+ * skipped, never waited for.
54
+ */
55
+ export declare function claimNode(state: SelectState, columns: readonly string[], due: {
56
+ readonly due: string;
57
+ readonly attempts: string;
58
+ readonly now: Date;
59
+ readonly maxAttempts: number;
60
+ }, scope: OperationNode, days: NameSet): SelectQueryNode;
61
+ /** `select <columns> from table where scope for update`: a mutation's precondition read of its own target. */
62
+ export declare function lockedSelectNode(table: string, columns: readonly string[], scope: OperationNode, days?: NameSet): SelectQueryNode;