@tanstack/workflow-store-drizzle-postgres 0.0.2 → 0.0.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.
package/dist/tables.js ADDED
@@ -0,0 +1,95 @@
1
+ import { bigint, boolean, index, integer, jsonb, pgTable, primaryKey, text } from "drizzle-orm/pg-core";
2
+
3
+ //#region src/tables.ts
4
+ const workflowSchemaMigrations = pgTable("workflow_schema_migrations", {
5
+ migrationId: text("migration_id").primaryKey(),
6
+ packageName: text("package_name").notNull(),
7
+ packageVersion: text("package_version"),
8
+ appliedAt: bigint("applied_at", { mode: "number" }).notNull()
9
+ });
10
+ const workflowRuns = pgTable("workflow_runs", {
11
+ runId: text("run_id").primaryKey(),
12
+ workflowId: text("workflow_id").notNull(),
13
+ workflowVersion: text("workflow_version"),
14
+ status: text("status").notNull(),
15
+ input: jsonb("input").notNull(),
16
+ output: jsonb("output"),
17
+ error: jsonb("error"),
18
+ awaiting: jsonb("awaiting"),
19
+ waitingFor: jsonb("waiting_for"),
20
+ pendingApproval: jsonb("pending_approval"),
21
+ wakeAt: bigint("wake_at", { mode: "number" }),
22
+ leaseOwner: text("lease_owner"),
23
+ leaseExpiresAt: bigint("lease_expires_at", { mode: "number" }),
24
+ createdAt: bigint("created_at", { mode: "number" }).notNull(),
25
+ updatedAt: bigint("updated_at", { mode: "number" }).notNull()
26
+ }, (table) => [index("workflow_runs_status_idx").on(table.status, table.updatedAt), index("workflow_runs_lease_idx").on(table.status, table.leaseExpiresAt)]);
27
+ const workflowRunStates = pgTable("workflow_run_states", {
28
+ runId: text("run_id").primaryKey(),
29
+ workflowId: text("workflow_id").notNull(),
30
+ workflowVersion: text("workflow_version"),
31
+ status: text("status").notNull(),
32
+ input: jsonb("input").notNull(),
33
+ output: jsonb("output"),
34
+ error: jsonb("error"),
35
+ awaiting: jsonb("awaiting"),
36
+ waitingFor: jsonb("waiting_for"),
37
+ pendingApproval: jsonb("pending_approval"),
38
+ createdAt: bigint("created_at", { mode: "number" }).notNull(),
39
+ updatedAt: bigint("updated_at", { mode: "number" }).notNull()
40
+ });
41
+ const workflowEventLocks = pgTable("workflow_event_locks", {
42
+ runId: text("run_id").primaryKey(),
43
+ createdAt: bigint("created_at", { mode: "number" }).notNull()
44
+ });
45
+ const workflowEvents = pgTable("workflow_events", {
46
+ runId: text("run_id").notNull(),
47
+ eventIndex: integer("event_index").notNull(),
48
+ eventType: text("event_type").notNull(),
49
+ stepId: text("step_id"),
50
+ event: jsonb("event").notNull(),
51
+ createdAt: bigint("created_at", { mode: "number" }).notNull()
52
+ }, (table) => [primaryKey({ columns: [table.runId, table.eventIndex] }), index("workflow_events_type_idx").on(table.runId, table.eventType)]);
53
+ const workflowTimers = pgTable("workflow_timers", {
54
+ runId: text("run_id").notNull(),
55
+ signalId: text("signal_id").notNull(),
56
+ workflowId: text("workflow_id").notNull(),
57
+ workflowVersion: text("workflow_version"),
58
+ wakeAt: bigint("wake_at", { mode: "number" }).notNull(),
59
+ leaseOwner: text("lease_owner"),
60
+ leaseExpiresAt: bigint("lease_expires_at", { mode: "number" })
61
+ }, (table) => [primaryKey({ columns: [table.runId, table.signalId] }), index("workflow_timers_due_idx").on(table.wakeAt, table.leaseExpiresAt)]);
62
+ const workflowSignalDeliveries = pgTable("workflow_signal_deliveries", {
63
+ runId: text("run_id").notNull(),
64
+ signalId: text("signal_id").notNull(),
65
+ createdAt: bigint("created_at", { mode: "number" }).notNull()
66
+ }, (table) => [primaryKey({ columns: [table.runId, table.signalId] })]);
67
+ const workflowSchedules = pgTable("workflow_schedules", {
68
+ scheduleId: text("schedule_id").primaryKey(),
69
+ workflowId: text("workflow_id").notNull(),
70
+ workflowVersion: text("workflow_version"),
71
+ schedule: jsonb("schedule").notNull(),
72
+ overlapPolicy: text("overlap_policy").notNull(),
73
+ input: jsonb("input"),
74
+ nextFireAt: bigint("next_fire_at", { mode: "number" }),
75
+ enabled: boolean("enabled").notNull(),
76
+ updatedAt: bigint("updated_at", { mode: "number" }).notNull()
77
+ }, (table) => [index("workflow_schedules_due_idx").on(table.enabled, table.nextFireAt)]);
78
+ const workflowScheduleBuckets = pgTable("workflow_schedule_buckets", {
79
+ scheduleId: text("schedule_id").notNull(),
80
+ bucketId: text("bucket_id").notNull(),
81
+ workflowId: text("workflow_id").notNull(),
82
+ workflowVersion: text("workflow_version"),
83
+ runId: text("run_id").notNull(),
84
+ fireAt: bigint("fire_at", { mode: "number" }).notNull(),
85
+ input: jsonb("input"),
86
+ overlapPolicy: text("overlap_policy").notNull(),
87
+ status: text("status").notNull(),
88
+ leaseOwner: text("lease_owner"),
89
+ leaseExpiresAt: bigint("lease_expires_at", { mode: "number" }),
90
+ startedAt: bigint("started_at", { mode: "number" })
91
+ }, (table) => [primaryKey({ columns: [table.scheduleId, table.bucketId] }), index("workflow_schedule_buckets_lease_idx").on(table.status, table.fireAt, table.leaseExpiresAt)]);
92
+
93
+ //#endregion
94
+ export { workflowEventLocks, workflowEvents, workflowRunStates, workflowRuns, workflowScheduleBuckets, workflowSchedules, workflowSchemaMigrations, workflowSignalDeliveries, workflowTimers };
95
+ //# sourceMappingURL=tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.js","names":[],"sources":["../src/tables.ts"],"sourcesContent":["import {\n bigint,\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n} from 'drizzle-orm/pg-core'\n\nexport const workflowSchemaMigrations = pgTable('workflow_schema_migrations', {\n migrationId: text('migration_id').primaryKey(),\n packageName: text('package_name').notNull(),\n packageVersion: text('package_version'),\n appliedAt: bigint('applied_at', { mode: 'number' }).notNull(),\n})\n\nexport const workflowRuns = pgTable(\n 'workflow_runs',\n {\n runId: text('run_id').primaryKey(),\n workflowId: text('workflow_id').notNull(),\n workflowVersion: text('workflow_version'),\n status: text('status').notNull(),\n input: jsonb('input').notNull(),\n output: jsonb('output'),\n error: jsonb('error'),\n awaiting: jsonb('awaiting'),\n waitingFor: jsonb('waiting_for'),\n pendingApproval: jsonb('pending_approval'),\n wakeAt: bigint('wake_at', { mode: 'number' }),\n leaseOwner: text('lease_owner'),\n leaseExpiresAt: bigint('lease_expires_at', { mode: 'number' }),\n createdAt: bigint('created_at', { mode: 'number' }).notNull(),\n updatedAt: bigint('updated_at', { mode: 'number' }).notNull(),\n },\n (table) => [\n index('workflow_runs_status_idx').on(table.status, table.updatedAt),\n index('workflow_runs_lease_idx').on(table.status, table.leaseExpiresAt),\n ],\n)\n\nexport const workflowRunStates = pgTable('workflow_run_states', {\n runId: text('run_id').primaryKey(),\n workflowId: text('workflow_id').notNull(),\n workflowVersion: text('workflow_version'),\n status: text('status').notNull(),\n input: jsonb('input').notNull(),\n output: jsonb('output'),\n error: jsonb('error'),\n awaiting: jsonb('awaiting'),\n waitingFor: jsonb('waiting_for'),\n pendingApproval: jsonb('pending_approval'),\n createdAt: bigint('created_at', { mode: 'number' }).notNull(),\n updatedAt: bigint('updated_at', { mode: 'number' }).notNull(),\n})\n\nexport const workflowEventLocks = pgTable('workflow_event_locks', {\n runId: text('run_id').primaryKey(),\n createdAt: bigint('created_at', { mode: 'number' }).notNull(),\n})\n\nexport const workflowEvents = pgTable(\n 'workflow_events',\n {\n runId: text('run_id').notNull(),\n eventIndex: integer('event_index').notNull(),\n eventType: text('event_type').notNull(),\n stepId: text('step_id'),\n event: jsonb('event').notNull(),\n createdAt: bigint('created_at', { mode: 'number' }).notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.runId, table.eventIndex] }),\n index('workflow_events_type_idx').on(table.runId, table.eventType),\n ],\n)\n\nexport const workflowTimers = pgTable(\n 'workflow_timers',\n {\n runId: text('run_id').notNull(),\n signalId: text('signal_id').notNull(),\n workflowId: text('workflow_id').notNull(),\n workflowVersion: text('workflow_version'),\n wakeAt: bigint('wake_at', { mode: 'number' }).notNull(),\n leaseOwner: text('lease_owner'),\n leaseExpiresAt: bigint('lease_expires_at', { mode: 'number' }),\n },\n (table) => [\n primaryKey({ columns: [table.runId, table.signalId] }),\n index('workflow_timers_due_idx').on(table.wakeAt, table.leaseExpiresAt),\n ],\n)\n\nexport const workflowSignalDeliveries = pgTable(\n 'workflow_signal_deliveries',\n {\n runId: text('run_id').notNull(),\n signalId: text('signal_id').notNull(),\n createdAt: bigint('created_at', { mode: 'number' }).notNull(),\n },\n (table) => [primaryKey({ columns: [table.runId, table.signalId] })],\n)\n\nexport const workflowSchedules = pgTable(\n 'workflow_schedules',\n {\n scheduleId: text('schedule_id').primaryKey(),\n workflowId: text('workflow_id').notNull(),\n workflowVersion: text('workflow_version'),\n schedule: jsonb('schedule').notNull(),\n overlapPolicy: text('overlap_policy').notNull(),\n input: jsonb('input'),\n nextFireAt: bigint('next_fire_at', { mode: 'number' }),\n enabled: boolean('enabled').notNull(),\n updatedAt: bigint('updated_at', { mode: 'number' }).notNull(),\n },\n (table) => [\n index('workflow_schedules_due_idx').on(table.enabled, table.nextFireAt),\n ],\n)\n\nexport const workflowScheduleBuckets = pgTable(\n 'workflow_schedule_buckets',\n {\n scheduleId: text('schedule_id').notNull(),\n bucketId: text('bucket_id').notNull(),\n workflowId: text('workflow_id').notNull(),\n workflowVersion: text('workflow_version'),\n runId: text('run_id').notNull(),\n fireAt: bigint('fire_at', { mode: 'number' }).notNull(),\n input: jsonb('input'),\n overlapPolicy: text('overlap_policy').notNull(),\n status: text('status').notNull(),\n leaseOwner: text('lease_owner'),\n leaseExpiresAt: bigint('lease_expires_at', { mode: 'number' }),\n startedAt: bigint('started_at', { mode: 'number' }),\n },\n (table) => [\n primaryKey({ columns: [table.scheduleId, table.bucketId] }),\n index('workflow_schedule_buckets_lease_idx').on(\n table.status,\n table.fireAt,\n table.leaseExpiresAt,\n ),\n ],\n)\n"],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ create table if not exists "workflow_schema_migrations" (
2
+ migration_id text primary key,
3
+ package_name text not null,
4
+ package_version text,
5
+ applied_at bigint not null
6
+ );
7
+
8
+ create table if not exists "workflow_runs" (
9
+ run_id text primary key,
10
+ workflow_id text not null,
11
+ workflow_version text,
12
+ status text not null,
13
+ input jsonb not null,
14
+ output jsonb,
15
+ error jsonb,
16
+ awaiting jsonb,
17
+ waiting_for jsonb,
18
+ pending_approval jsonb,
19
+ wake_at bigint,
20
+ lease_owner text,
21
+ lease_expires_at bigint,
22
+ created_at bigint not null,
23
+ updated_at bigint not null
24
+ );
25
+
26
+ alter table "workflow_runs" add column if not exists awaiting jsonb;
27
+
28
+ create index if not exists "workflow_runs_status_idx"
29
+ on "workflow_runs" (status, updated_at);
30
+
31
+ create index if not exists "workflow_runs_lease_idx"
32
+ on "workflow_runs" (status, lease_expires_at);
33
+
34
+ create table if not exists "workflow_run_states" (
35
+ run_id text primary key,
36
+ workflow_id text not null,
37
+ workflow_version text,
38
+ status text not null,
39
+ input jsonb not null,
40
+ output jsonb,
41
+ error jsonb,
42
+ awaiting jsonb,
43
+ waiting_for jsonb,
44
+ pending_approval jsonb,
45
+ created_at bigint not null,
46
+ updated_at bigint not null
47
+ );
48
+
49
+ alter table "workflow_run_states" add column if not exists awaiting jsonb;
50
+
51
+ create table if not exists "workflow_event_locks" (
52
+ run_id text primary key,
53
+ created_at bigint not null
54
+ );
55
+
56
+ create table if not exists "workflow_events" (
57
+ run_id text not null,
58
+ event_index integer not null,
59
+ event_type text not null,
60
+ step_id text,
61
+ event jsonb not null,
62
+ created_at bigint not null,
63
+ primary key (run_id, event_index)
64
+ );
65
+
66
+ create index if not exists "workflow_events_type_idx"
67
+ on "workflow_events" (run_id, event_type);
68
+
69
+ create table if not exists "workflow_timers" (
70
+ run_id text not null,
71
+ signal_id text not null,
72
+ workflow_id text not null,
73
+ workflow_version text,
74
+ wake_at bigint not null,
75
+ lease_owner text,
76
+ lease_expires_at bigint,
77
+ primary key (run_id, signal_id)
78
+ );
79
+
80
+ create index if not exists "workflow_timers_due_idx"
81
+ on "workflow_timers" (wake_at, lease_expires_at);
82
+
83
+ create table if not exists "workflow_signal_deliveries" (
84
+ run_id text not null,
85
+ signal_id text not null,
86
+ created_at bigint not null,
87
+ primary key (run_id, signal_id)
88
+ );
89
+
90
+ create table if not exists "workflow_schedules" (
91
+ schedule_id text primary key,
92
+ workflow_id text not null,
93
+ workflow_version text,
94
+ schedule jsonb not null,
95
+ overlap_policy text not null,
96
+ input jsonb,
97
+ next_fire_at bigint,
98
+ enabled boolean not null,
99
+ updated_at bigint not null
100
+ );
101
+
102
+ create index if not exists "workflow_schedules_due_idx"
103
+ on "workflow_schedules" (enabled, next_fire_at);
104
+
105
+ create table if not exists "workflow_schedule_buckets" (
106
+ schedule_id text not null,
107
+ bucket_id text not null,
108
+ workflow_id text not null,
109
+ workflow_version text,
110
+ run_id text not null,
111
+ fire_at bigint not null,
112
+ input jsonb,
113
+ overlap_policy text not null,
114
+ status text not null,
115
+ lease_owner text,
116
+ lease_expires_at bigint,
117
+ started_at bigint,
118
+ primary key (schedule_id, bucket_id)
119
+ );
120
+
121
+ create index if not exists "workflow_schedule_buckets_lease_idx"
122
+ on "workflow_schedule_buckets" (status, fire_at, lease_expires_at);
123
+
124
+ insert into "workflow_schema_migrations" (
125
+ migration_id,
126
+ package_name,
127
+ package_version,
128
+ applied_at
129
+ )
130
+ values (
131
+ '0000_workflow_store',
132
+ '@tanstack/workflow-store-drizzle-postgres',
133
+ null,
134
+ (extract(epoch from now()) * 1000)::bigint
135
+ )
136
+ on conflict (migration_id) do nothing;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/workflow-store-drizzle-postgres",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Drizzle/Postgres durable execution store for TanStack Workflow.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -48,7 +48,9 @@
48
48
  },
49
49
  "files": [
50
50
  "dist/",
51
- "src"
51
+ "migrations/",
52
+ "src",
53
+ "SCHEMA_MIGRATIONS.md"
52
54
  ],
53
55
  "dependencies": {
54
56
  "@tanstack/workflow-core": "workspace:*",
package/src/index.ts CHANGED
@@ -1,10 +1,32 @@
1
+ export { createDrizzlePostgresWorkflowStore } from './store'
1
2
  export {
2
- createDrizzlePostgresWorkflowStore,
3
3
  defaultDrizzlePostgresWorkflowStoreTables,
4
- } from './store'
4
+ getDrizzlePostgresWorkflowStoreSchemaStatements,
5
+ resolveDrizzlePostgresWorkflowStoreTables,
6
+ } from './schema-contract'
7
+ export {
8
+ drizzlePostgresWorkflowStoreSchemaVersion,
9
+ getDrizzlePostgresWorkflowStoreMigrations,
10
+ getDrizzlePostgresWorkflowStoreMigrationSql,
11
+ } from './migrations'
12
+ export {
13
+ workflowEventLocks,
14
+ workflowEvents,
15
+ workflowRuns,
16
+ workflowRunStates,
17
+ workflowScheduleBuckets,
18
+ workflowSchedules,
19
+ workflowSchemaMigrations,
20
+ workflowSignalDeliveries,
21
+ workflowTimers,
22
+ } from './tables'
5
23
  export type {
6
24
  DrizzlePostgresDatabase,
7
25
  DrizzlePostgresWorkflowStore,
8
26
  DrizzlePostgresWorkflowStoreOptions,
9
- DrizzlePostgresWorkflowStoreTables,
10
27
  } from './store'
28
+ export type { DrizzlePostgresWorkflowStoreMigration } from './migrations'
29
+ export type {
30
+ DrizzlePostgresWorkflowStoreSchemaOptions,
31
+ DrizzlePostgresWorkflowStoreTables,
32
+ } from './schema-contract'
@@ -0,0 +1,34 @@
1
+ import { getDrizzlePostgresWorkflowStoreSchemaStatements } from './schema-contract'
2
+ import type { DrizzlePostgresWorkflowStoreSchemaOptions } from './schema-contract'
3
+
4
+ export interface DrizzlePostgresWorkflowStoreMigration {
5
+ id: string
6
+ name: string
7
+ order: number
8
+ statements: Array<string>
9
+ sql: string
10
+ }
11
+
12
+ export const drizzlePostgresWorkflowStoreSchemaVersion = '0000_workflow_store'
13
+
14
+ export function getDrizzlePostgresWorkflowStoreMigrations(
15
+ options?: DrizzlePostgresWorkflowStoreSchemaOptions,
16
+ ): Array<DrizzlePostgresWorkflowStoreMigration> {
17
+ const statements = getDrizzlePostgresWorkflowStoreSchemaStatements(options)
18
+
19
+ return [
20
+ {
21
+ id: '0000_workflow_store',
22
+ name: 'Create TanStack Workflow Drizzle/Postgres store tables',
23
+ order: 0,
24
+ statements,
25
+ sql: `${statements.join(';\n\n')};\n`,
26
+ },
27
+ ]
28
+ }
29
+
30
+ export function getDrizzlePostgresWorkflowStoreMigrationSql(
31
+ options?: DrizzlePostgresWorkflowStoreSchemaOptions,
32
+ ): string {
33
+ return getDrizzlePostgresWorkflowStoreMigrations(options)[0]!.sql
34
+ }
@@ -0,0 +1,208 @@
1
+ export interface DrizzlePostgresWorkflowStoreTables {
2
+ schemaMigrations: string
3
+ runs: string
4
+ runStates: string
5
+ eventLocks: string
6
+ events: string
7
+ timers: string
8
+ signalDeliveries: string
9
+ schedules: string
10
+ scheduleBuckets: string
11
+ }
12
+
13
+ export interface DrizzlePostgresWorkflowStoreSchemaOptions {
14
+ schema?: string
15
+ tables?: Partial<DrizzlePostgresWorkflowStoreTables>
16
+ }
17
+
18
+ export const defaultDrizzlePostgresWorkflowStoreTables: DrizzlePostgresWorkflowStoreTables =
19
+ {
20
+ schemaMigrations: 'workflow_schema_migrations',
21
+ runs: 'workflow_runs',
22
+ runStates: 'workflow_run_states',
23
+ eventLocks: 'workflow_event_locks',
24
+ events: 'workflow_events',
25
+ timers: 'workflow_timers',
26
+ signalDeliveries: 'workflow_signal_deliveries',
27
+ schedules: 'workflow_schedules',
28
+ scheduleBuckets: 'workflow_schedule_buckets',
29
+ }
30
+
31
+ export function resolveDrizzlePostgresWorkflowStoreTables(
32
+ tables?: Partial<DrizzlePostgresWorkflowStoreTables>,
33
+ ): DrizzlePostgresWorkflowStoreTables {
34
+ return {
35
+ ...defaultDrizzlePostgresWorkflowStoreTables,
36
+ ...tables,
37
+ }
38
+ }
39
+
40
+ export function getDrizzlePostgresWorkflowStoreSchemaStatements(
41
+ options: DrizzlePostgresWorkflowStoreSchemaOptions = {},
42
+ ): Array<string> {
43
+ const tables = resolveDrizzlePostgresWorkflowStoreTables(options.tables)
44
+ const schemaMigrations = qualifiedTableName(
45
+ options.schema,
46
+ tables.schemaMigrations,
47
+ )
48
+ const runs = qualifiedTableName(options.schema, tables.runs)
49
+ const runStates = qualifiedTableName(options.schema, tables.runStates)
50
+ const eventLocks = qualifiedTableName(options.schema, tables.eventLocks)
51
+ const events = qualifiedTableName(options.schema, tables.events)
52
+ const timers = qualifiedTableName(options.schema, tables.timers)
53
+ const signalDeliveries = qualifiedTableName(
54
+ options.schema,
55
+ tables.signalDeliveries,
56
+ )
57
+ const schedules = qualifiedTableName(options.schema, tables.schedules)
58
+ const scheduleBuckets = qualifiedTableName(
59
+ options.schema,
60
+ tables.scheduleBuckets,
61
+ )
62
+
63
+ return [
64
+ ...(options.schema
65
+ ? [`create schema if not exists ${quoteIdent(options.schema)}`]
66
+ : []),
67
+ `create table if not exists ${schemaMigrations} (
68
+ migration_id text primary key,
69
+ package_name text not null,
70
+ package_version text,
71
+ applied_at bigint not null
72
+ )`,
73
+ `create table if not exists ${runs} (
74
+ run_id text primary key,
75
+ workflow_id text not null,
76
+ workflow_version text,
77
+ status text not null,
78
+ input jsonb not null,
79
+ output jsonb,
80
+ error jsonb,
81
+ awaiting jsonb,
82
+ waiting_for jsonb,
83
+ pending_approval jsonb,
84
+ wake_at bigint,
85
+ lease_owner text,
86
+ lease_expires_at bigint,
87
+ created_at bigint not null,
88
+ updated_at bigint not null
89
+ )`,
90
+ `alter table ${runs} add column if not exists awaiting jsonb`,
91
+ `create index if not exists ${quoteIdent(`${tables.runs}_status_idx`)}
92
+ on ${runs} (status, updated_at)`,
93
+ `create index if not exists ${quoteIdent(`${tables.runs}_lease_idx`)}
94
+ on ${runs} (status, lease_expires_at)`,
95
+ `create table if not exists ${runStates} (
96
+ run_id text primary key,
97
+ workflow_id text not null,
98
+ workflow_version text,
99
+ status text not null,
100
+ input jsonb not null,
101
+ output jsonb,
102
+ error jsonb,
103
+ awaiting jsonb,
104
+ waiting_for jsonb,
105
+ pending_approval jsonb,
106
+ created_at bigint not null,
107
+ updated_at bigint not null
108
+ )`,
109
+ `alter table ${runStates} add column if not exists awaiting jsonb`,
110
+ `create table if not exists ${eventLocks} (
111
+ run_id text primary key,
112
+ created_at bigint not null
113
+ )`,
114
+ `create table if not exists ${events} (
115
+ run_id text not null,
116
+ event_index integer not null,
117
+ event_type text not null,
118
+ step_id text,
119
+ event jsonb not null,
120
+ created_at bigint not null,
121
+ primary key (run_id, event_index)
122
+ )`,
123
+ `create index if not exists ${quoteIdent(`${tables.events}_type_idx`)}
124
+ on ${events} (run_id, event_type)`,
125
+ `create table if not exists ${timers} (
126
+ run_id text not null,
127
+ signal_id text not null,
128
+ workflow_id text not null,
129
+ workflow_version text,
130
+ wake_at bigint not null,
131
+ lease_owner text,
132
+ lease_expires_at bigint,
133
+ primary key (run_id, signal_id)
134
+ )`,
135
+ `create index if not exists ${quoteIdent(`${tables.timers}_due_idx`)}
136
+ on ${timers} (wake_at, lease_expires_at)`,
137
+ `create table if not exists ${signalDeliveries} (
138
+ run_id text not null,
139
+ signal_id text not null,
140
+ created_at bigint not null,
141
+ primary key (run_id, signal_id)
142
+ )`,
143
+ `create table if not exists ${schedules} (
144
+ schedule_id text primary key,
145
+ workflow_id text not null,
146
+ workflow_version text,
147
+ schedule jsonb not null,
148
+ overlap_policy text not null,
149
+ input jsonb,
150
+ next_fire_at bigint,
151
+ enabled boolean not null,
152
+ updated_at bigint not null
153
+ )`,
154
+ `create index if not exists ${quoteIdent(`${tables.schedules}_due_idx`)}
155
+ on ${schedules} (enabled, next_fire_at)`,
156
+ `create table if not exists ${scheduleBuckets} (
157
+ schedule_id text not null,
158
+ bucket_id text not null,
159
+ workflow_id text not null,
160
+ workflow_version text,
161
+ run_id text not null,
162
+ fire_at bigint not null,
163
+ input jsonb,
164
+ overlap_policy text not null,
165
+ status text not null,
166
+ lease_owner text,
167
+ lease_expires_at bigint,
168
+ started_at bigint,
169
+ primary key (schedule_id, bucket_id)
170
+ )`,
171
+ `create index if not exists ${quoteIdent(
172
+ `${tables.scheduleBuckets}_lease_idx`,
173
+ )}
174
+ on ${scheduleBuckets} (status, fire_at, lease_expires_at)`,
175
+ `insert into ${schemaMigrations} (
176
+ migration_id,
177
+ package_name,
178
+ package_version,
179
+ applied_at
180
+ )
181
+ values (
182
+ '0000_workflow_store',
183
+ '@tanstack/workflow-store-drizzle-postgres',
184
+ null,
185
+ (extract(epoch from now()) * 1000)::bigint
186
+ )
187
+ on conflict (migration_id) do nothing`,
188
+ ].map(normalizeSqlStatement)
189
+ }
190
+
191
+ export function qualifiedTableName(schema: string | undefined, table: string) {
192
+ return schema
193
+ ? `${quoteIdent(schema)}.${quoteIdent(table)}`
194
+ : quoteIdent(table)
195
+ }
196
+
197
+ function quoteIdent(identifier: string) {
198
+ return `"${identifier.replaceAll('"', '""')}"`
199
+ }
200
+
201
+ function normalizeSqlStatement(statement: string) {
202
+ return statement
203
+ .split('\n')
204
+ .map((line, index) =>
205
+ index === 0 ? line.trimEnd() : line.replace(/^ {4}/, '').trimEnd(),
206
+ )
207
+ .join('\n')
208
+ }