@owlmeans/postgres-resource 0.1.18-rc.40 → 0.1.18-rc.42
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/README.md +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/postgres-resource/SKILL.md +2 -2
- package/build/declarations.d.ts +1 -8
- package/build/declarations.d.ts.map +1 -1
- package/build/declarations.js.map +1 -1
- package/build/errors.d.ts +3 -1
- package/build/errors.d.ts.map +1 -1
- package/build/errors.js +4 -2
- package/build/errors.js.map +1 -1
- package/build/resource.d.ts +1 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js.map +1 -1
- package/build/types.d.ts +6 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.local.d.ts +14 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/build/utils/consts.local.d.ts +33 -0
- package/build/utils/consts.local.d.ts.map +1 -0
- package/build/utils/consts.local.js +61 -0
- package/build/utils/consts.local.js.map +1 -0
- package/build/utils/criteria.d.ts +2 -2
- package/build/utils/criteria.d.ts.map +1 -1
- package/build/utils/criteria.js +2 -3
- package/build/utils/criteria.js.map +1 -1
- package/build/utils/diff.d.ts.map +1 -1
- package/build/utils/diff.js +5 -3
- package/build/utils/diff.js.map +1 -1
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js.map +1 -1
- package/build/utils/introspect.d.ts.map +1 -1
- package/build/utils/introspect.js +1 -29
- package/build/utils/introspect.js.map +1 -1
- package/build/utils/life-cycle.d.ts +3 -8
- package/build/utils/life-cycle.d.ts.map +1 -1
- package/build/utils/life-cycle.js +5 -2
- package/build/utils/life-cycle.js.map +1 -1
- package/build/utils/marshal.d.ts.map +1 -1
- package/build/utils/marshal.js +11 -5
- package/build/utils/marshal.js.map +1 -1
- package/build/utils/migrations.d.ts.map +1 -1
- package/build/utils/migrations.js +9 -6
- package/build/utils/migrations.js.map +1 -1
- package/build/utils/name.d.ts.map +1 -1
- package/build/utils/name.js +2 -2
- package/build/utils/name.js.map +1 -1
- package/build/utils/schema.d.ts.map +1 -1
- package/build/utils/schema.js +6 -4
- package/build/utils/schema.js.map +1 -1
- package/build/utils/sql.d.ts +1 -9
- package/build/utils/sql.d.ts.map +1 -1
- package/build/utils/sql.js +0 -0
- package/build/utils/sql.js.map +1 -1
- package/build/utils/sync.d.ts.map +1 -1
- package/build/utils/sync.js +6 -16
- package/build/utils/sync.js.map +1 -1
- package/build/utils/types.d.ts +18 -0
- package/build/utils/types.d.ts.map +1 -0
- package/build/utils/types.js +2 -0
- package/build/utils/types.js.map +1 -0
- package/build/utils/types.local.d.ts +33 -0
- package/build/utils/types.local.d.ts.map +1 -0
- package/build/utils/types.local.js +2 -0
- package/build/utils/types.local.js.map +1 -0
- package/package.json +14 -13
- package/src/declarations.ts +1 -9
- package/src/errors.ts +5 -13
- package/src/resource.ts +3 -11
- package/src/types.local.ts +16 -0
- package/src/types.ts +7 -4
- package/src/utils/consts.local.ts +68 -0
- package/src/utils/criteria.ts +4 -19
- package/src/utils/diff.ts +5 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/introspect.ts +1 -32
- package/src/utils/life-cycle.ts +8 -15
- package/src/utils/marshal.ts +12 -7
- package/src/utils/migrations.ts +9 -6
- package/src/utils/name.ts +2 -3
- package/src/utils/schema.ts +8 -32
- package/src/utils/sql.ts +0 -0
- package/src/utils/sync.ts +6 -18
- package/src/utils/types.local.ts +35 -0
- package/src/utils/types.ts +19 -0
- package/tests/diff.spec.ts +24 -0
- package/tests/errors.spec.ts +11 -0
package/build/utils/sync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/utils/sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/utils/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PgRuntimeTable, TableSpec } from '../types.js';
|
|
2
|
+
import type { MigrationReport } from '@owlmeans/resource';
|
|
3
|
+
import type { BasicContext } from '@owlmeans/context';
|
|
4
|
+
export interface TableInit {
|
|
5
|
+
spec: TableSpec;
|
|
6
|
+
/** The Drizzle table CRUD is built against. */
|
|
7
|
+
entity: PgRuntimeTable;
|
|
8
|
+
reports: MigrationReport[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The context a placeholder resolves through.
|
|
12
|
+
*
|
|
13
|
+
* Resolution reads exactly one thing — `context.resource(alias).table` — so the config a context
|
|
14
|
+
* carries is irrelevant here, and pinning one would force every caller holding a server context
|
|
15
|
+
* to cast its way in. Deliberately open, and named so callers pass what they already have.
|
|
16
|
+
*/
|
|
17
|
+
export type PlaceholderContext = BasicContext<any>;
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAA;IACf,+CAA+C;IAC/C,MAAM,EAAE,cAAc,CAAA;IACtB,OAAO,EAAE,eAAe,EAAE,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SQL } from 'drizzle-orm';
|
|
2
|
+
import { PG_KEYWORD } from '../consts.js';
|
|
3
|
+
import type { PgPropertyOverride, PgRootOverride } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* A value at a path, as the jsonb it is (`#>`) and as text (`#>>`). The path is ONE bound `text[]`
|
|
6
|
+
* parameter, so a segment holding a comma or a brace stays one segment.
|
|
7
|
+
*/
|
|
8
|
+
export interface PathTarget {
|
|
9
|
+
value: SQL;
|
|
10
|
+
text: SQL;
|
|
11
|
+
/** Absent, or a JSON `null` — what every other store reads as "no value". */
|
|
12
|
+
missing: SQL;
|
|
13
|
+
}
|
|
14
|
+
export interface RawProperty {
|
|
15
|
+
type?: string | string[];
|
|
16
|
+
format?: string;
|
|
17
|
+
enum?: unknown[];
|
|
18
|
+
items?: RawProperty;
|
|
19
|
+
maxLength?: number;
|
|
20
|
+
maximum?: number;
|
|
21
|
+
minimum?: number;
|
|
22
|
+
default?: unknown;
|
|
23
|
+
nullable?: boolean;
|
|
24
|
+
secure?: boolean;
|
|
25
|
+
[PG_KEYWORD]?: PgPropertyOverride;
|
|
26
|
+
}
|
|
27
|
+
export interface RawSchema {
|
|
28
|
+
properties?: Record<string, RawProperty>;
|
|
29
|
+
required?: string[];
|
|
30
|
+
allOf?: RawSchema[];
|
|
31
|
+
[PG_KEYWORD]?: PgRootOverride;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../../src/utils/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAErE;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,GAAG,CAAA;IACV,IAAI,EAAE,GAAG,CAAA;IACT,6EAA6E;IAC7E,OAAO,EAAE,GAAG,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;IAChB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,CAAC,UAAU,CAAC,CAAC,EAAE,kBAAkB,CAAA;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAA;IACnB,CAAC,UAAU,CAAC,CAAC,EAAE,cAAc,CAAA;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../../src/utils/types.local.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/postgres-resource",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.42",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -26,22 +26,23 @@
|
|
|
26
26
|
"pg": "*"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@noble/hashes": "^
|
|
30
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
31
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
32
|
-
"@owlmeans/
|
|
33
|
-
"@owlmeans/
|
|
34
|
-
"@
|
|
35
|
-
"
|
|
29
|
+
"@noble/hashes": "^2.4.0",
|
|
30
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.36",
|
|
31
|
+
"@owlmeans/context": "^0.1.18-rc.33",
|
|
32
|
+
"@owlmeans/log": "^0.1.18-rc.1",
|
|
33
|
+
"@owlmeans/resource": "^0.1.18-rc.39",
|
|
34
|
+
"@owlmeans/server-context": "^0.1.18-rc.42",
|
|
35
|
+
"@scure/base": "^2.4.0",
|
|
36
|
+
"drizzle-orm": "~0.45.3"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@owlmeans/dep-config": "workspace:*",
|
|
39
|
-
"@owlmeans/test-integration": "^0.1.18-rc.
|
|
40
|
-
"@types/bun": "^1.4.
|
|
41
|
-
"@types/node": "^26.
|
|
42
|
-
"@types/pg": "^8.
|
|
40
|
+
"@owlmeans/test-integration": "^0.1.18-rc.32",
|
|
41
|
+
"@types/bun": "^1.4.2",
|
|
42
|
+
"@types/node": "^26.6.4",
|
|
43
|
+
"@types/pg": "^8.23.1",
|
|
43
44
|
"nodemon": "^3.1.14",
|
|
44
|
-
"pg": "^8.
|
|
45
|
+
"pg": "^8.23.1",
|
|
45
46
|
"typescript": "^7.0.2"
|
|
46
47
|
},
|
|
47
48
|
"publishConfig": {
|
package/src/declarations.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { createMigrationRegistry } from '@owlmeans/resource'
|
|
2
|
-
import type { MigrationRegistry } from '@owlmeans/resource'
|
|
3
|
-
import type { AnySchema } from 'ajv'
|
|
4
2
|
|
|
5
|
-
import type {
|
|
6
|
-
|
|
7
|
-
export interface PostgresDeclaration {
|
|
8
|
-
schema?: AnySchema
|
|
9
|
-
indexes: PgIndexSpec[]
|
|
10
|
-
migrations: MigrationRegistry<PostgresTx>
|
|
11
|
-
}
|
|
3
|
+
import type { PostgresTx, PostgresDeclaration } from './types.js'
|
|
12
4
|
|
|
13
5
|
/**
|
|
14
6
|
* Per-alias declaration store, held at module scope rather than on the resource object.
|
package/src/errors.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from '@owlmeans/resource'
|
|
5
5
|
|
|
6
6
|
import { PgErrorCode } from './consts.js'
|
|
7
|
+
import type { PgDriverError } from './types.local.js'
|
|
7
8
|
|
|
8
9
|
export class PostgresError extends ResourceError {
|
|
9
10
|
public static override typeName = `${ResourceError.typeName}PostgresError`
|
|
@@ -106,17 +107,6 @@ export class PostgresBootstrapError extends PostgresError {
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
interface PgDriverError {
|
|
110
|
-
code?: string
|
|
111
|
-
detail?: string
|
|
112
|
-
hint?: string
|
|
113
|
-
severity?: string
|
|
114
|
-
constraint?: string
|
|
115
|
-
table?: string
|
|
116
|
-
column?: string
|
|
117
|
-
message?: string
|
|
118
|
-
}
|
|
119
|
-
|
|
120
110
|
const isDriverError = (error: unknown): error is PgDriverError =>
|
|
121
111
|
error != null && typeof error === 'object' && 'code' in error
|
|
122
112
|
|
|
@@ -183,8 +173,10 @@ const describe = (error: PgDriverError): string => {
|
|
|
183
173
|
* Translate a raw `pg` driver error into the framework's error vocabulary, so a driver
|
|
184
174
|
* type never escapes the package. Errors that already are `ResilientError`s pass through
|
|
185
175
|
* untouched — the reconciler and the migration runner raise their own.
|
|
176
|
+
* A migration may supply its resolved SQL; placeholders stay intact and parameter values
|
|
177
|
+
* are never added. The statement travels in the message so error marshalling preserves it.
|
|
186
178
|
*/
|
|
187
|
-
export const pgErrorToResourceError = (error: unknown): Error => {
|
|
179
|
+
export const pgErrorToResourceError = (error: unknown, query?: string): Error => {
|
|
188
180
|
if (error instanceof ResilientError) {
|
|
189
181
|
return error
|
|
190
182
|
}
|
|
@@ -193,7 +185,7 @@ export const pgErrorToResourceError = (error: unknown): Error => {
|
|
|
193
185
|
return error instanceof Error ? error : new PostgresError(`${error}`)
|
|
194
186
|
}
|
|
195
187
|
|
|
196
|
-
const message = describe(driver)
|
|
188
|
+
const message = describe(driver) + (query == null ? '' : `\nSQL: ${query}`)
|
|
197
189
|
const produce = (): Error => {
|
|
198
190
|
switch (driver.code) {
|
|
199
191
|
case PgErrorCode.UniqueViolation:
|
package/src/resource.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { appendContextual, assertContext } from '@owlmeans/context'
|
|
2
|
-
import {
|
|
3
|
-
MisshapedRecord, RecordExists, RecordUpdateFailed, UnknownRecordError, UnsupportedArgumentError
|
|
4
|
-
} from '@owlmeans/resource'
|
|
5
|
-
import type {
|
|
6
|
-
Criteria, FirstOptions, ListOptions, ListResult, MigrationStage, ResourceRecord, WriteOptions
|
|
7
|
-
} from '@owlmeans/resource'
|
|
8
|
-
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
2
|
+
import { MisshapedRecord, RecordExists, RecordUpdateFailed, UnknownRecordError, UnsupportedArgumentError, type Criteria, type FirstOptions, type ListOptions, type ListResult, type MigrationStage, type ResourceRecord, type WriteOptions } from '@owlmeans/resource'
|
|
9
3
|
import type { AnySchema, JSONSchemaType } from 'ajv'
|
|
10
|
-
import { eq, sql } from 'drizzle-orm'
|
|
11
|
-
import type { SQL } from 'drizzle-orm'
|
|
4
|
+
import { eq, sql, type SQL } from 'drizzle-orm'
|
|
12
5
|
import type { PoolClient, QueryResultRow } from 'pg'
|
|
13
6
|
|
|
14
7
|
import { DEFAULT_DB_ALIAS, DEFAULT_PAGE_SIZE, ID_FIELD } from './consts.js'
|
|
@@ -24,9 +17,8 @@ import { initializeTable } from './utils/life-cycle.js'
|
|
|
24
17
|
import { recordToFullValues, recordToValues, resultToRecord, rowToRecord } from './utils/marshal.js'
|
|
25
18
|
import { makeTx } from './utils/migrations.js'
|
|
26
19
|
import { refOf, resolvePlaceholders } from './utils/sql.js'
|
|
20
|
+
import type { Config, Context } from './types.local.js'
|
|
27
21
|
|
|
28
|
-
type Config = ServerConfig
|
|
29
|
-
type Context<C extends Config = Config> = ServerContext<C>
|
|
30
22
|
|
|
31
23
|
/** Postgres has no row expiry — silently ignoring a TTL would lose data. */
|
|
32
24
|
const refuseTtl = (opts?: WriteOptions): void => {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
2
|
+
|
|
3
|
+
export interface PgDriverError {
|
|
4
|
+
code?: string
|
|
5
|
+
detail?: string
|
|
6
|
+
hint?: string
|
|
7
|
+
severity?: string
|
|
8
|
+
constraint?: string
|
|
9
|
+
table?: string
|
|
10
|
+
column?: string
|
|
11
|
+
message?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Config = ServerConfig
|
|
15
|
+
|
|
16
|
+
export type Context<C extends Config = Config> = ServerContext<C>
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Criteria, DbLocker, LockableResource, MigratableResource, Resource,
|
|
3
|
-
ResourceDbService, ResourceRecord, WriteOptions
|
|
4
|
-
} from '@owlmeans/resource'
|
|
1
|
+
import type { Criteria, DbLocker, LockableResource, MigratableResource, Resource, ResourceDbService, ResourceRecord, WriteOptions, MigrationRegistry } from '@owlmeans/resource'
|
|
5
2
|
import type { AnySchema } from 'ajv'
|
|
6
3
|
import type { Pool, PoolClient, QueryResultRow } from 'pg'
|
|
7
4
|
import type { NodePgDatabase } from 'drizzle-orm/node-postgres'
|
|
@@ -321,3 +318,9 @@ export interface DdlPlan {
|
|
|
321
318
|
fresh: boolean
|
|
322
319
|
statements: DdlStatement[]
|
|
323
320
|
}
|
|
321
|
+
|
|
322
|
+
export interface PostgresDeclaration {
|
|
323
|
+
schema?: AnySchema
|
|
324
|
+
indexes: PgIndexSpec[]
|
|
325
|
+
migrations: MigrationRegistry<PostgresTx>
|
|
326
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PgErrorCode } from '../consts.js'
|
|
2
|
+
|
|
3
|
+
export const COMPARISON: Record<string, string> = {
|
|
4
|
+
$eq: '=', $ne: '<>', $gt: '>', $gte: '>=', $lt: '<', $lte: '<='
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** A type cast as `pg_get_expr` / `pg_get_indexdef` print one: `::text`, `::character varying(64)[]`. */
|
|
8
|
+
export const CAST = /::(?:character varying|double precision|bit varying|timestamp with(?:out)? time zone|time with(?:out)? time zone|[a-z_][a-z0-9_]*)(?:\(\d+(?:\s*,\s*\d+)?\))?(?:\[\])?/g
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `pg_attribute` + `format_type` rather than `information_schema.columns`, because it
|
|
12
|
+
* returns one canonical type string with the typmod already baked in
|
|
13
|
+
* (`character varying(320)`). `information_schema` splits the same information across
|
|
14
|
+
* four columns and reports every array as `ARRAY`, which no comparison can use.
|
|
15
|
+
*/
|
|
16
|
+
export const COLUMNS = `
|
|
17
|
+
SELECT a.attname AS name,
|
|
18
|
+
format_type(a.atttypid, a.atttypmod) AS type,
|
|
19
|
+
a.attnotnull AS not_null,
|
|
20
|
+
pg_get_expr(d.adbin, d.adrelid) AS default_expr,
|
|
21
|
+
a.attidentity AS identity,
|
|
22
|
+
a.attgenerated AS generated,
|
|
23
|
+
a.attnum AS ordinal
|
|
24
|
+
FROM pg_attribute a
|
|
25
|
+
LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
|
|
26
|
+
WHERE a.attrelid = to_regclass($1) AND a.attnum > 0 AND NOT a.attisdropped
|
|
27
|
+
ORDER BY a.attnum
|
|
28
|
+
`
|
|
29
|
+
|
|
30
|
+
export const INDEXES = `
|
|
31
|
+
SELECT indexname AS name, indexdef AS definition
|
|
32
|
+
FROM pg_indexes
|
|
33
|
+
WHERE schemaname = $1 AND tablename = $2
|
|
34
|
+
`
|
|
35
|
+
|
|
36
|
+
export const CONSTRAINTS = `
|
|
37
|
+
SELECT c.conname AS name, c.contype AS type, pg_get_constraintdef(c.oid) AS definition
|
|
38
|
+
FROM pg_constraint c
|
|
39
|
+
WHERE c.conrelid = to_regclass($1)
|
|
40
|
+
AND c.contype <> 'n'
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
export const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* `{{ }}` / `{{self}}` — the owning resource's qualified table
|
|
47
|
+
* `{{alias}}` — another registered postgres resource's qualified table
|
|
48
|
+
* `{{alias.property}}` — a qualified column of that resource
|
|
49
|
+
* `{{#alias}}` — the bare quoted table name, for `ON CONFLICT ON CONSTRAINT`
|
|
50
|
+
* `{{$}}` — the owning resource's quoted schema
|
|
51
|
+
*
|
|
52
|
+
* Resource aliases in this codebase use `-` and `:` but never `.`, so `.` is unambiguous
|
|
53
|
+
* as the column separator.
|
|
54
|
+
*/
|
|
55
|
+
export const PLACEHOLDER = /\{\{\s*([#$]?)([A-Za-z0-9_:-]*)(?:\.([A-Za-z0-9_]+))?\s*\}\}/g
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Codes that mean "the cast is legal, the data isn't": a `text` column holding `'a'` retyped to
|
|
59
|
+
* `integer`, a value too wide for the new length, a number past the new range. Postgres refuses
|
|
60
|
+
* each of these rather than truncating, and the remedy is the same one a refused cast needs — so
|
|
61
|
+
* they are only read as a cast problem here, inside DDL. On the CRUD path the identical code means
|
|
62
|
+
* a caller passed a bad value, which is a different bug with a different fix.
|
|
63
|
+
*/
|
|
64
|
+
export const CAST_DATA_CODES: string[] = [
|
|
65
|
+
PgErrorCode.InvalidTextRepresentation,
|
|
66
|
+
PgErrorCode.StringDataRightTruncation,
|
|
67
|
+
PgErrorCode.NumericValueOutOfRange
|
|
68
|
+
]
|
package/src/utils/criteria.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { UnsupportedArgumentError } from '@owlmeans/resource'
|
|
2
|
-
import
|
|
3
|
-
import { and, asc, desc, or, param, sql } from 'drizzle-orm'
|
|
4
|
-
import type { SQL } from 'drizzle-orm'
|
|
1
|
+
import { UnsupportedArgumentError, type Criteria, type FieldOperators, type Sort } from '@owlmeans/resource'
|
|
2
|
+
import { and, asc, desc, or, param, sql, type SQL } from 'drizzle-orm'
|
|
5
3
|
|
|
6
4
|
import type { ColumnSpec, PgRuntimeTable, TableSpec } from '../types.js'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
$eq: '=', $ne: '<>', $gt: '>', $gte: '>=', $lt: '<', $lte: '<='
|
|
10
|
-
}
|
|
5
|
+
import { COMPARISON } from './consts.local.js'
|
|
6
|
+
import type { PathTarget } from './types.local.js'
|
|
11
7
|
|
|
12
8
|
const columnRef = (table: PgRuntimeTable, column: ColumnSpec): SQL => sql`${table[column.property]}`
|
|
13
9
|
|
|
@@ -166,17 +162,6 @@ const escapeLike = (value: string): string => value.replace(/[\\%_]/g, match =>
|
|
|
166
162
|
|
|
167
163
|
// ─── Dotted paths into a jsonb column ────────────────────────────────────────────────────────────
|
|
168
164
|
|
|
169
|
-
/**
|
|
170
|
-
* A value at a path, as the jsonb it is (`#>`) and as text (`#>>`). The path is ONE bound `text[]`
|
|
171
|
-
* parameter, so a segment holding a comma or a brace stays one segment.
|
|
172
|
-
*/
|
|
173
|
-
interface PathTarget {
|
|
174
|
-
value: SQL
|
|
175
|
-
text: SQL
|
|
176
|
-
/** Absent, or a JSON `null` — what every other store reads as "no value". */
|
|
177
|
-
missing: SQL
|
|
178
|
-
}
|
|
179
|
-
|
|
180
165
|
const pathTarget = (table: PgRuntimeTable, column: ColumnSpec, path: string[]): PathTarget => {
|
|
181
166
|
const value = sql`(${columnRef(table, column)} #> ${param(path)}::text[])`
|
|
182
167
|
|
package/src/utils/diff.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ColumnSpec, DdlPlan, DdlStatement, LiveTable, PgIndexSpec, PostgresResource, TableSpec
|
|
8
8
|
} from '../types.js'
|
|
9
9
|
import { qualify, quoteIdent } from './name.js'
|
|
10
|
+
import { CAST } from './consts.local.js'
|
|
10
11
|
|
|
11
12
|
const literal = (value: string | number | boolean | null): string => {
|
|
12
13
|
if (value === null) return 'NULL'
|
|
@@ -23,9 +24,6 @@ const defaultExpression = (column: ColumnSpec): string | undefined => {
|
|
|
23
24
|
return undefined
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
/** A type cast as `pg_get_expr` / `pg_get_indexdef` print one: `::text`, `::character varying(64)[]`. */
|
|
27
|
-
const CAST = /::(?:character varying|double precision|bit varying|timestamp with(?:out)? time zone|time with(?:out)? time zone|[a-z_][a-z0-9_]*)(?:\(\d+(?:\s*,\s*\d+)?\))?(?:\[\])?/g
|
|
28
|
-
|
|
29
27
|
/**
|
|
30
28
|
* Postgres echoes defaults back with explicit casts — a declared `'active'` comes back as
|
|
31
29
|
* `'active'::text`. Compare without them, so an unchanged default doesn't look like drift on
|
|
@@ -303,7 +301,10 @@ export const planSync = (
|
|
|
303
301
|
}
|
|
304
302
|
const liveConstraints: Record<string, string> = {}
|
|
305
303
|
for (const constraint of live.constraints) {
|
|
306
|
-
|
|
304
|
+
// Primary and foreign keys have their own paths. A NOT NULL (`n`) is a constraint row since
|
|
305
|
+
// Postgres 18 (`<table>_<column>_not_null`) and is owned by the column step above: dropping it by
|
|
306
|
+
// name is refused on a primary key column, and on any other it would undo a `required` property.
|
|
307
|
+
if (constraint.type === 'p' || constraint.type === 'f' || constraint.type === 'n') {
|
|
307
308
|
continue
|
|
308
309
|
}
|
|
309
310
|
liveConstraints[constraint.name] = constraint.definition
|
package/src/utils/index.ts
CHANGED
package/src/utils/introspect.ts
CHANGED
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
import type { PoolClient } from 'pg'
|
|
2
2
|
|
|
3
3
|
import type { LiveColumn, LiveConstraint, LiveIndex, LiveTable } from '../types.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* `pg_attribute` + `format_type` rather than `information_schema.columns`, because it
|
|
7
|
-
* returns one canonical type string with the typmod already baked in
|
|
8
|
-
* (`character varying(320)`). `information_schema` splits the same information across
|
|
9
|
-
* four columns and reports every array as `ARRAY`, which no comparison can use.
|
|
10
|
-
*/
|
|
11
|
-
const COLUMNS = `
|
|
12
|
-
SELECT a.attname AS name,
|
|
13
|
-
format_type(a.atttypid, a.atttypmod) AS type,
|
|
14
|
-
a.attnotnull AS not_null,
|
|
15
|
-
pg_get_expr(d.adbin, d.adrelid) AS default_expr,
|
|
16
|
-
a.attidentity AS identity,
|
|
17
|
-
a.attgenerated AS generated,
|
|
18
|
-
a.attnum AS ordinal
|
|
19
|
-
FROM pg_attribute a
|
|
20
|
-
LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
|
|
21
|
-
WHERE a.attrelid = to_regclass($1) AND a.attnum > 0 AND NOT a.attisdropped
|
|
22
|
-
ORDER BY a.attnum
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
const INDEXES = `
|
|
26
|
-
SELECT indexname AS name, indexdef AS definition
|
|
27
|
-
FROM pg_indexes
|
|
28
|
-
WHERE schemaname = $1 AND tablename = $2
|
|
29
|
-
`
|
|
30
|
-
|
|
31
|
-
const CONSTRAINTS = `
|
|
32
|
-
SELECT c.conname AS name, c.contype AS type, pg_get_constraintdef(c.oid) AS definition
|
|
33
|
-
FROM pg_constraint c
|
|
34
|
-
WHERE c.conrelid = to_regclass($1)
|
|
35
|
-
`
|
|
4
|
+
import { COLUMNS, CONSTRAINTS, INDEXES } from './consts.local.js'
|
|
36
5
|
|
|
37
6
|
/** Read the table exactly as Postgres currently holds it. */
|
|
38
7
|
export const introspectTable = async (
|
package/src/utils/life-cycle.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { BasicContext } from '@owlmeans/context'
|
|
2
|
-
import { MigrationStage, runMigrations } from '@owlmeans/resource'
|
|
3
|
-
import
|
|
2
|
+
import { MigrationStage, runMigrations, type DbConfig, type MigrationReport, type ResourceRecord } from '@owlmeans/resource'
|
|
3
|
+
import { logger } from '@owlmeans/log'
|
|
4
4
|
import type { PoolClient } from 'pg'
|
|
5
5
|
|
|
6
6
|
import { DEF_MIGRATIONS_TABLE, PgAutoSync } from '../consts.js'
|
|
7
7
|
import { getDeclaration } from '../declarations.js'
|
|
8
8
|
import { describePgError, pgErrorToResourceError } from '../errors.js'
|
|
9
|
-
import type {
|
|
10
|
-
PgRuntimeTable, PostgresDb, PostgresMeta, PostgresResource, TableSpec
|
|
11
|
-
} from '../types.js'
|
|
9
|
+
import type { PostgresDb, PostgresMeta, PostgresResource, TableSpec } from '../types.js'
|
|
12
10
|
import { planForeignKeys, planSync } from './diff.js'
|
|
13
11
|
import { introspectTable } from './introspect.js'
|
|
14
12
|
import { makeMigrationStore } from './migrations.js'
|
|
@@ -17,13 +15,9 @@ import { schemaToTableSpec } from './schema.js'
|
|
|
17
15
|
import { refOf, resolvePlaceholders } from './sql.js'
|
|
18
16
|
import { acquireLock, applyPlan, ensureSchema, releaseLock } from './sync.js'
|
|
19
17
|
import { specToTable } from './table.js'
|
|
18
|
+
import type { TableInit } from './types.js'
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
spec: TableSpec
|
|
23
|
-
/** The Drizzle table CRUD is built against. */
|
|
24
|
-
entity: PgRuntimeTable
|
|
25
|
-
reports: MigrationReport[]
|
|
26
|
-
}
|
|
20
|
+
const log = logger('postgres-resource')
|
|
27
21
|
|
|
28
22
|
/**
|
|
29
23
|
* Bring a resource's table to the shape its schema declares, then hand back everything the
|
|
@@ -90,10 +84,9 @@ export const initializeTable = async (
|
|
|
90
84
|
|
|
91
85
|
for (const report of reports) {
|
|
92
86
|
if (report.applied.length > 0) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
87
|
+
log.info('Migrations applied', {
|
|
88
|
+
resource: resource.alias, table: spec.qualified, stage: report.stage, applied: report.applied,
|
|
89
|
+
}, { event: 'migration.applied' })
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
} finally {
|
package/src/utils/marshal.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ResourceRecord } from '@owlmeans/resource'
|
|
2
|
+
import { logThrottle, logger } from '@owlmeans/log'
|
|
2
3
|
import { types as pgTypes } from 'pg'
|
|
3
4
|
|
|
4
5
|
import { ID_FIELD, PgTypeOid } from '../consts.js'
|
|
5
6
|
import type { ColumnSpec, TableSpec } from '../types.js'
|
|
6
7
|
|
|
8
|
+
const log = logger('postgres-resource')
|
|
9
|
+
|
|
7
10
|
/**
|
|
8
11
|
* Parse a temporal value the way the driver would have.
|
|
9
12
|
*
|
|
@@ -23,7 +26,7 @@ const toDate = (value: string, column: ColumnSpec): unknown => {
|
|
|
23
26
|
return (pgTypes.getTypeParser(oid as never) as (raw: string) => unknown)(value)
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
const fromDriver = (value: unknown, column: ColumnSpec): unknown => {
|
|
29
|
+
const fromDriver = (value: unknown, column: ColumnSpec, table?: string): unknown => {
|
|
27
30
|
if (value == null) {
|
|
28
31
|
return value
|
|
29
32
|
}
|
|
@@ -44,10 +47,12 @@ const fromDriver = (value: unknown, column: ColumnSpec): unknown => {
|
|
|
44
47
|
}
|
|
45
48
|
const parsed = Number(value)
|
|
46
49
|
if (!Number.isSafeInteger(parsed)) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
// Fires per row read: one line per window per column is enough.
|
|
51
|
+
if (logThrottle(`postgres-resource:${table ?? ''}:${column.column}:unsafe-bigint`, 300_000)) {
|
|
52
|
+
log.warn('Bigint column value exceeds the safe integer range; the value read back is imprecise', {
|
|
53
|
+
table, column: column.column,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
return parsed
|
|
@@ -100,7 +105,7 @@ export const rowToRecord = <T extends ResourceRecord>(row: Record<string, unknow
|
|
|
100
105
|
record[key] = value
|
|
101
106
|
continue
|
|
102
107
|
}
|
|
103
|
-
record[column.property] = fromDriver(value, column)
|
|
108
|
+
record[column.property] = fromDriver(value, column, spec.qualified)
|
|
104
109
|
}
|
|
105
110
|
if (record[ID_FIELD] != null) {
|
|
106
111
|
record[ID_FIELD] = `${record[ID_FIELD]}`
|
|
@@ -123,7 +128,7 @@ export const resultToRecord = <T extends ResourceRecord>(
|
|
|
123
128
|
const record: Record<string, unknown> = {}
|
|
124
129
|
for (const [key, value] of Object.entries(row)) {
|
|
125
130
|
const column = spec.byProperty[key]
|
|
126
|
-
record[key] = column == null ? value : fromDriver(value, column)
|
|
131
|
+
record[key] = column == null ? value : fromDriver(value, column, spec.qualified)
|
|
127
132
|
}
|
|
128
133
|
if (record[ID_FIELD] != null) {
|
|
129
134
|
record[ID_FIELD] = `${record[ID_FIELD]}`
|
package/src/utils/migrations.ts
CHANGED
|
@@ -15,29 +15,32 @@ export const makeTx = (
|
|
|
15
15
|
client,
|
|
16
16
|
|
|
17
17
|
query: async <Row extends QueryResultRow = QueryResultRow>(text: string, params?: unknown[]) => {
|
|
18
|
+
const query = resolve(text)
|
|
18
19
|
try {
|
|
19
|
-
const result = await client.query<Row>(
|
|
20
|
+
const result = await client.query<Row>(query, params as never[])
|
|
20
21
|
return result.rows
|
|
21
22
|
} catch (error) {
|
|
22
|
-
throw pgErrorToResourceError(error)
|
|
23
|
+
throw pgErrorToResourceError(error, query)
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
|
|
26
27
|
queryOne: async <Row extends QueryResultRow = QueryResultRow>(text: string, params?: unknown[]) => {
|
|
28
|
+
const query = resolve(text)
|
|
27
29
|
try {
|
|
28
|
-
const result = await client.query<Row>(
|
|
30
|
+
const result = await client.query<Row>(query, params as never[])
|
|
29
31
|
return result.rows[0] ?? null
|
|
30
32
|
} catch (error) {
|
|
31
|
-
throw pgErrorToResourceError(error)
|
|
33
|
+
throw pgErrorToResourceError(error, query)
|
|
32
34
|
}
|
|
33
35
|
},
|
|
34
36
|
|
|
35
37
|
execute: async (text: string, params?: unknown[]) => {
|
|
38
|
+
const query = resolve(text)
|
|
36
39
|
try {
|
|
37
|
-
const result = await client.query(
|
|
40
|
+
const result = await client.query(query, params as never[])
|
|
38
41
|
return result.rowCount ?? 0
|
|
39
42
|
} catch (error) {
|
|
40
|
-
throw pgErrorToResourceError(error)
|
|
43
|
+
throw pgErrorToResourceError(error, query)
|
|
41
44
|
}
|
|
42
45
|
},
|
|
43
46
|
|
package/src/utils/name.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { sha256 } from '@noble/hashes/sha2'
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha2.js'
|
|
2
2
|
import { hex } from '@scure/base'
|
|
3
3
|
import type { DbConfig, ResourceRecord } from '@owlmeans/resource'
|
|
4
4
|
|
|
5
5
|
import { PG_MAX_IDENTIFIER } from '../consts.js'
|
|
6
6
|
import type { PostgresResource } from '../types.js'
|
|
7
|
-
|
|
8
|
-
const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/
|
|
7
|
+
import { SAFE_IDENTIFIER } from './consts.local.js'
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Coerce an arbitrary name into a legal Postgres identifier of at most 63 bytes.
|