@lumifai/harness-tool-pack-postgres 0.0.1
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 +84 -0
- package/dist/cast-types.d.ts +1 -0
- package/dist/cast-types.js +24 -0
- package/dist/cast-types.js.map +1 -0
- package/dist/catalog-cache.d.ts +9 -0
- package/dist/catalog-cache.js +49 -0
- package/dist/catalog-cache.js.map +1 -0
- package/dist/catalog.d.ts +45 -0
- package/dist/catalog.js +221 -0
- package/dist/catalog.js.map +1 -0
- package/dist/constants.d.ts +45 -0
- package/dist/constants.js +94 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -0
- package/dist/identifiers.d.ts +1 -0
- package/dist/identifiers.js +21 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/insert-compiler.d.ts +21 -0
- package/dist/insert-compiler.js +126 -0
- package/dist/insert-compiler.js.map +1 -0
- package/dist/insert-executor.d.ts +25 -0
- package/dist/insert-executor.js +101 -0
- package/dist/insert-executor.js.map +1 -0
- package/dist/insert-language.d.ts +56 -0
- package/dist/insert-language.js +218 -0
- package/dist/insert-language.js.map +1 -0
- package/dist/postgres.d.ts +39 -0
- package/dist/postgres.js +503 -0
- package/dist/postgres.js.map +1 -0
- package/dist/query-compiler.d.ts +16 -0
- package/dist/query-compiler.js +504 -0
- package/dist/query-compiler.js.map +1 -0
- package/dist/query-executor.d.ts +27 -0
- package/dist/query-executor.js +223 -0
- package/dist/query-executor.js.map +1 -0
- package/dist/query-language.d.ts +208 -0
- package/dist/query-language.js +500 -0
- package/dist/query-language.js.map +1 -0
- package/dist/workspace-file.d.ts +6 -0
- package/dist/workspace-file.js +47 -0
- package/dist/workspace-file.js.map +1 -0
- package/package.json +43 -0
- package/skills/postgres/SKILL.md +144 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @lumifai/harness-tool-pack-postgres
|
|
2
|
+
|
|
3
|
+
PostgreSQL schema inspection, JSON query, and guarded insert tools for the Lumif harness.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createPostgresToolPack } from '@lumifai/harness-tool-pack-postgres';
|
|
9
|
+
|
|
10
|
+
createPostgresToolPack({
|
|
11
|
+
connectionString: process.env.DATABASE_URL,
|
|
12
|
+
// Per-tenant credentials: return a connection string for a least-privilege,
|
|
13
|
+
// RLS-bound role. Access control is enforced in PostgreSQL, not in the pack.
|
|
14
|
+
resolveConnectionString: async (context) => tenantDatabaseUrl(context),
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Access control (which schemas, tables, columns, and rows are visible or writable)
|
|
19
|
+
is enforced in the database by the connection role's `GRANT`s and row-level
|
|
20
|
+
security policies. Provision a dedicated role with the minimum privileges needed
|
|
21
|
+
(for example `SELECT` for reads and `INSERT` only on approved tables) and connect
|
|
22
|
+
as that role; the tools expose exactly what the role can see and write.
|
|
23
|
+
|
|
24
|
+
## Tools
|
|
25
|
+
|
|
26
|
+
| Tool | Purpose |
|
|
27
|
+
| ----------------------------- | ----------------------------------------------- |
|
|
28
|
+
| `postgres_list_schemas` | List accessible schemas with relation counts |
|
|
29
|
+
| `postgres_get_schema_details` | Columns, keys, foreign keys, optional indexes |
|
|
30
|
+
| `postgres_preview_data` | Bounded preview of one relation |
|
|
31
|
+
| `postgres_query` | Execute a validated JSON `QueryPlan` |
|
|
32
|
+
| `postgres_insert` | Insert rows from inline JSON or a workspace CSV |
|
|
33
|
+
|
|
34
|
+
Raw SQL is intentionally unsupported.
|
|
35
|
+
|
|
36
|
+
## Insert sources
|
|
37
|
+
|
|
38
|
+
`postgres_insert` accepts one table target and a discriminated source:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"schema": "public",
|
|
43
|
+
"relation": "users",
|
|
44
|
+
"source": {
|
|
45
|
+
"kind": "json",
|
|
46
|
+
"columns": ["email", "active"],
|
|
47
|
+
"rows": [["a@example.com", true]]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"schema": "public",
|
|
55
|
+
"relation": "users",
|
|
56
|
+
"source": {
|
|
57
|
+
"kind": "csv",
|
|
58
|
+
"path": "/data/users.csv"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
CSV paths must be absolute within the Mastra workspace filesystem
|
|
64
|
+
(for example `/data/users.csv`). Host filesystem paths are rejected. Partial
|
|
65
|
+
success is intentional: valid rows commit; rejected rows are returned with
|
|
66
|
+
row indexes and error codes. Structural failures (missing workspace, bad CSV,
|
|
67
|
+
unknown table) fail the tool call.
|
|
68
|
+
|
|
69
|
+
## Security model
|
|
70
|
+
|
|
71
|
+
Defense in depth:
|
|
72
|
+
|
|
73
|
+
1. PostgreSQL least-privilege role, RLS, column grants, and per-tenant credentials (the authority for access control)
|
|
74
|
+
2. No raw SQL: the model emits validated JSON plans or insert payloads, compiled server-side and parameterized via `pg-sql2`
|
|
75
|
+
3. Read-only transactions for queries; read-write transactions with per-row savepoints for inserts; timeouts; hard row/byte/cell limits
|
|
76
|
+
4. Schema metadata is loaded on demand (schema list is a single lightweight query; details/query compile load only the schemas they need) and cached briefly per connection fingerprint
|
|
77
|
+
5. CSV inserts read only through the configured Mastra workspace filesystem
|
|
78
|
+
|
|
79
|
+
Extension functions are disabled by default. If enabled, configure and call them
|
|
80
|
+
with the exact schema-qualified name, such as `public.mask_email`. Use
|
|
81
|
+
`date_part(field, source)` instead of `EXTRACT`. `current_date` /
|
|
82
|
+
`current_timestamp` are supported as niladic keywords.
|
|
83
|
+
|
|
84
|
+
Bundled agent skills ship in this package and are merged into `workspace.skills` when the pack is enabled.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function assertAllowedCastType(type: string): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertAllowedCastType = assertAllowedCastType;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const ALLOWED_CAST_TYPES = new Set([
|
|
6
|
+
'text',
|
|
7
|
+
'varchar',
|
|
8
|
+
'integer',
|
|
9
|
+
'bigint',
|
|
10
|
+
'numeric',
|
|
11
|
+
'boolean',
|
|
12
|
+
'date',
|
|
13
|
+
'timestamp',
|
|
14
|
+
'timestamptz',
|
|
15
|
+
'json',
|
|
16
|
+
'jsonb',
|
|
17
|
+
'uuid',
|
|
18
|
+
]);
|
|
19
|
+
function assertAllowedCastType(type) {
|
|
20
|
+
if (!ALLOWED_CAST_TYPES.has(type.toLowerCase())) {
|
|
21
|
+
throw new errors_1.PostgresToolError('COMPILATION_ERROR', `Cast type "${type}" is not allowed.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=cast-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cast-types.js","sourceRoot":"","sources":["../src/cast-types.ts"],"names":[],"mappings":";;AAiBA,sDAIC;AArBD,qCAA6C;AAE7C,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,MAAM;IACN,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,SAAS;IACT,MAAM;IACN,WAAW;IACX,aAAa;IACb,MAAM;IACN,OAAO;IACP,MAAM;CACP,CAAC,CAAC;AAEH,SAAgB,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,0BAAiB,CAAC,mBAAmB,EAAE,cAAc,IAAI,mBAAmB,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Client } from 'pg';
|
|
2
|
+
import type { PostgresCatalog } from './catalog';
|
|
3
|
+
/**
|
|
4
|
+
* Loads a schema-scoped catalog, reusing an in-memory entry keyed by connection
|
|
5
|
+
* fingerprint + sorted schema list for a short TTL.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadCachedCatalog(connectionString: string, client: Client, schemas: string[], ttlMs?: number): Promise<PostgresCatalog>;
|
|
8
|
+
/** Test helper — clears the process-local catalog cache. */
|
|
9
|
+
export declare function clearCatalogCache(): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadCachedCatalog = loadCachedCatalog;
|
|
4
|
+
exports.clearCatalogCache = clearCatalogCache;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const catalog_1 = require("./catalog");
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
const catalogCache = new Map();
|
|
9
|
+
function hashConnectionKey(connectionString) {
|
|
10
|
+
return (0, node_crypto_1.createHash)('sha256').update(connectionString, 'utf8').digest('hex');
|
|
11
|
+
}
|
|
12
|
+
function cacheKey(connectionString, schemas) {
|
|
13
|
+
return `${hashConnectionKey(connectionString)}::${[...schemas].sort().join(',')}`;
|
|
14
|
+
}
|
|
15
|
+
function pruneExpiredEntries(now) {
|
|
16
|
+
for (const [key, entry] of catalogCache) {
|
|
17
|
+
if (entry.expiresAt <= now) {
|
|
18
|
+
catalogCache.delete(key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Loads a schema-scoped catalog, reusing an in-memory entry keyed by connection
|
|
24
|
+
* fingerprint + sorted schema list for a short TTL.
|
|
25
|
+
*/
|
|
26
|
+
async function loadCachedCatalog(connectionString, client, schemas, ttlMs = constants_1.DEFAULT_CATALOG_CACHE_TTL_MS) {
|
|
27
|
+
const uniqueSchemas = [...new Set(schemas)].sort();
|
|
28
|
+
if (uniqueSchemas.length === 0) {
|
|
29
|
+
return { schemas: new Set(), relations: new Map() };
|
|
30
|
+
}
|
|
31
|
+
const key = cacheKey(connectionString, uniqueSchemas);
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const cached = catalogCache.get(key);
|
|
34
|
+
if (cached) {
|
|
35
|
+
if (cached.expiresAt > now) {
|
|
36
|
+
return cached.catalog;
|
|
37
|
+
}
|
|
38
|
+
catalogCache.delete(key);
|
|
39
|
+
}
|
|
40
|
+
const catalog = await (0, catalog_1.loadPostgresCatalog)(client, { schemas: uniqueSchemas });
|
|
41
|
+
pruneExpiredEntries(now);
|
|
42
|
+
catalogCache.set(key, { catalog, expiresAt: now + Math.max(ttlMs, 0) });
|
|
43
|
+
return catalog;
|
|
44
|
+
}
|
|
45
|
+
/** Test helper — clears the process-local catalog cache. */
|
|
46
|
+
function clearCatalogCache() {
|
|
47
|
+
catalogCache.clear();
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=catalog-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-cache.js","sourceRoot":"","sources":["../src/catalog-cache.ts"],"names":[],"mappings":";;AAmCA,8CAyBC;AAGD,8CAEC;AAjED,6CAAyC;AAKzC,uCAAgD;AAChD,2CAA2D;AAO3D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAC;AAEnD,SAAS,iBAAiB,CAAC,gBAAwB;IACjD,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,QAAQ,CAAC,gBAAwB,EAAE,OAAiB;IAC3D,OAAO,GAAG,iBAAiB,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAW;IACtC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;YAC3B,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,iBAAiB,CACrC,gBAAwB,EACxB,MAAc,EACd,OAAiB,EACjB,QAAgB,wCAA4B;IAE5C,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;YAC3B,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;QACD,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,IAAA,6BAAmB,EAAC,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;IAC9E,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzB,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACxE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,4DAA4D;AAC5D,SAAgB,iBAAiB;IAC/B,YAAY,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Client } from 'pg';
|
|
2
|
+
export type CatalogColumn = {
|
|
3
|
+
name: string;
|
|
4
|
+
dataType: string;
|
|
5
|
+
isNullable: boolean;
|
|
6
|
+
ordinalPosition: number;
|
|
7
|
+
};
|
|
8
|
+
export type CatalogRelation = {
|
|
9
|
+
schema: string;
|
|
10
|
+
name: string;
|
|
11
|
+
kind: 'table' | 'view';
|
|
12
|
+
columns: CatalogColumn[];
|
|
13
|
+
primaryKey: string[];
|
|
14
|
+
uniqueKeys: string[][];
|
|
15
|
+
foreignKeys: {
|
|
16
|
+
name: string;
|
|
17
|
+
columns: string[];
|
|
18
|
+
referencedSchema: string;
|
|
19
|
+
referencedTable: string;
|
|
20
|
+
referencedColumns: string[];
|
|
21
|
+
}[];
|
|
22
|
+
indexes?: {
|
|
23
|
+
name: string;
|
|
24
|
+
columns: string[];
|
|
25
|
+
isUnique: boolean;
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
export type PostgresCatalog = {
|
|
29
|
+
schemas: Set<string>;
|
|
30
|
+
relations: Map<string, CatalogRelation>;
|
|
31
|
+
};
|
|
32
|
+
export type SchemaSummary = {
|
|
33
|
+
name: string;
|
|
34
|
+
relation_count: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Lightweight schema listing: one query for names + relation counts.
|
|
38
|
+
* Does not load columns, keys, or foreign keys.
|
|
39
|
+
*/
|
|
40
|
+
export declare function listSchemaSummaries(client: Client): Promise<SchemaSummary[]>;
|
|
41
|
+
export declare function loadPostgresCatalog(client: Client, options?: {
|
|
42
|
+
schemas?: string[];
|
|
43
|
+
}): Promise<PostgresCatalog>;
|
|
44
|
+
export declare function loadRelationIndexes(client: Client, schema: string, relation: string): Promise<CatalogRelation['indexes']>;
|
|
45
|
+
export declare function getCatalogRelation(catalog: PostgresCatalog, schema: string, name: string): CatalogRelation | undefined;
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listSchemaSummaries = listSchemaSummaries;
|
|
4
|
+
exports.loadPostgresCatalog = loadPostgresCatalog;
|
|
5
|
+
exports.loadRelationIndexes = loadRelationIndexes;
|
|
6
|
+
exports.getCatalogRelation = getCatalogRelation;
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
function relationKey(schema, name) {
|
|
9
|
+
return `${schema}.${name}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Lightweight schema listing: one query for names + relation counts.
|
|
13
|
+
* Does not load columns, keys, or foreign keys.
|
|
14
|
+
*/
|
|
15
|
+
async function listSchemaSummaries(client) {
|
|
16
|
+
const result = await client.query(`SELECT
|
|
17
|
+
s.schema_name,
|
|
18
|
+
COALESCE(t.relation_count, 0)::text AS relation_count
|
|
19
|
+
FROM information_schema.schemata s
|
|
20
|
+
LEFT JOIN (
|
|
21
|
+
SELECT table_schema, COUNT(*)::int AS relation_count
|
|
22
|
+
FROM information_schema.tables
|
|
23
|
+
WHERE table_type IN ('BASE TABLE', 'VIEW')
|
|
24
|
+
GROUP BY table_schema
|
|
25
|
+
) t ON t.table_schema = s.schema_name
|
|
26
|
+
WHERE s.schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
27
|
+
AND s.schema_name NOT LIKE 'pg_temp_%'
|
|
28
|
+
AND s.schema_name NOT LIKE 'pg_toast_temp_%'
|
|
29
|
+
ORDER BY s.schema_name`);
|
|
30
|
+
return result.rows
|
|
31
|
+
.filter((row) => !constants_1.SYSTEM_SCHEMAS.has(row.schema_name))
|
|
32
|
+
.map((row) => ({
|
|
33
|
+
name: row.schema_name,
|
|
34
|
+
relation_count: Number(row.relation_count),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
async function loadPostgresCatalog(client, options) {
|
|
38
|
+
let schemas;
|
|
39
|
+
if (options?.schemas) {
|
|
40
|
+
const requested = options.schemas.filter((name) => name.length > 0 && !constants_1.SYSTEM_SCHEMAS.has(name));
|
|
41
|
+
if (requested.length === 0) {
|
|
42
|
+
return { schemas: new Set(), relations: new Map() };
|
|
43
|
+
}
|
|
44
|
+
const schemasResult = await client.query(`SELECT schema_name
|
|
45
|
+
FROM information_schema.schemata
|
|
46
|
+
WHERE schema_name = ANY($1::text[])`, [requested]);
|
|
47
|
+
schemas = new Set(schemasResult.rows.map((row) => row.schema_name));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const schemasResult = await client.query(`SELECT schema_name
|
|
51
|
+
FROM information_schema.schemata
|
|
52
|
+
WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
53
|
+
AND schema_name NOT LIKE 'pg_temp_%'
|
|
54
|
+
AND schema_name NOT LIKE 'pg_toast_temp_%'`);
|
|
55
|
+
schemas = new Set(schemasResult.rows.map((row) => row.schema_name).filter((name) => !constants_1.SYSTEM_SCHEMAS.has(name)));
|
|
56
|
+
}
|
|
57
|
+
if (schemas.size === 0) {
|
|
58
|
+
return { schemas, relations: new Map() };
|
|
59
|
+
}
|
|
60
|
+
const schemaList = Array.from(schemas);
|
|
61
|
+
const tablesResult = await client.query(`SELECT table_schema, table_name, table_type
|
|
62
|
+
FROM information_schema.tables
|
|
63
|
+
WHERE table_schema = ANY($1::text[])
|
|
64
|
+
AND table_type IN ('BASE TABLE', 'VIEW')
|
|
65
|
+
ORDER BY table_schema, table_name`, [schemaList]);
|
|
66
|
+
const columnsResult = await client.query(`SELECT table_schema, table_name, column_name, data_type, is_nullable, ordinal_position
|
|
67
|
+
FROM information_schema.columns
|
|
68
|
+
WHERE table_schema = ANY($1::text[])
|
|
69
|
+
ORDER BY table_schema, table_name, ordinal_position`, [schemaList]);
|
|
70
|
+
const pkResult = await client.query(`SELECT tc.table_schema, tc.table_name, kcu.column_name, kcu.ordinal_position
|
|
71
|
+
FROM information_schema.table_constraints tc
|
|
72
|
+
JOIN information_schema.key_column_usage kcu
|
|
73
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
74
|
+
AND tc.table_schema = kcu.table_schema
|
|
75
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
76
|
+
AND tc.table_schema = ANY($1::text[])
|
|
77
|
+
ORDER BY tc.table_schema, tc.table_name, kcu.ordinal_position`, [schemaList]);
|
|
78
|
+
const uniqueResult = await client.query(`SELECT tc.table_schema, tc.table_name, tc.constraint_name, kcu.column_name, kcu.ordinal_position
|
|
79
|
+
FROM information_schema.table_constraints tc
|
|
80
|
+
JOIN information_schema.key_column_usage kcu
|
|
81
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
82
|
+
AND tc.table_schema = kcu.table_schema
|
|
83
|
+
WHERE tc.constraint_type = 'UNIQUE'
|
|
84
|
+
AND tc.table_schema = ANY($1::text[])
|
|
85
|
+
ORDER BY tc.table_schema, tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schemaList]);
|
|
86
|
+
const fkResult = await client.query(`SELECT
|
|
87
|
+
kcu.table_schema,
|
|
88
|
+
kcu.table_name,
|
|
89
|
+
kcu.constraint_name,
|
|
90
|
+
kcu.column_name,
|
|
91
|
+
kcu.ordinal_position,
|
|
92
|
+
fcu.table_schema AS foreign_table_schema,
|
|
93
|
+
fcu.table_name AS foreign_table_name,
|
|
94
|
+
fcu.column_name AS foreign_column_name
|
|
95
|
+
FROM information_schema.referential_constraints rc
|
|
96
|
+
JOIN information_schema.key_column_usage kcu
|
|
97
|
+
ON kcu.constraint_name = rc.constraint_name
|
|
98
|
+
AND kcu.constraint_schema = rc.constraint_schema
|
|
99
|
+
JOIN information_schema.key_column_usage fcu
|
|
100
|
+
ON fcu.constraint_name = rc.unique_constraint_name
|
|
101
|
+
AND fcu.constraint_schema = rc.unique_constraint_schema
|
|
102
|
+
AND fcu.ordinal_position = kcu.position_in_unique_constraint
|
|
103
|
+
WHERE kcu.table_schema = ANY($1::text[])
|
|
104
|
+
ORDER BY kcu.table_schema, kcu.table_name, kcu.constraint_name, kcu.ordinal_position`, [schemaList]);
|
|
105
|
+
const relations = new Map();
|
|
106
|
+
for (const table of tablesResult.rows) {
|
|
107
|
+
if (!schemas.has(table.table_schema)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
relations.set(relationKey(table.table_schema, table.table_name), {
|
|
111
|
+
schema: table.table_schema,
|
|
112
|
+
name: table.table_name,
|
|
113
|
+
kind: table.table_type === 'VIEW' ? 'view' : 'table',
|
|
114
|
+
columns: [],
|
|
115
|
+
primaryKey: [],
|
|
116
|
+
uniqueKeys: [],
|
|
117
|
+
foreignKeys: [],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
for (const column of columnsResult.rows) {
|
|
121
|
+
const relation = relations.get(relationKey(column.table_schema, column.table_name));
|
|
122
|
+
if (!relation) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
relation.columns.push({
|
|
126
|
+
name: column.column_name,
|
|
127
|
+
dataType: column.data_type,
|
|
128
|
+
isNullable: column.is_nullable === 'YES',
|
|
129
|
+
ordinalPosition: column.ordinal_position,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const pkByRelation = new Map();
|
|
133
|
+
for (const row of pkResult.rows) {
|
|
134
|
+
const key = relationKey(row.table_schema, row.table_name);
|
|
135
|
+
const columns = pkByRelation.get(key) ?? [];
|
|
136
|
+
columns.push(row.column_name);
|
|
137
|
+
pkByRelation.set(key, columns);
|
|
138
|
+
}
|
|
139
|
+
for (const [key, columns] of pkByRelation) {
|
|
140
|
+
const relation = relations.get(key);
|
|
141
|
+
if (relation) {
|
|
142
|
+
relation.primaryKey = columns;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const uniqueByConstraint = new Map();
|
|
146
|
+
for (const row of uniqueResult.rows) {
|
|
147
|
+
const key = `${row.table_schema}.${row.table_name}.${row.constraint_name}`;
|
|
148
|
+
const columns = uniqueByConstraint.get(key) ?? [];
|
|
149
|
+
columns.push(row.column_name);
|
|
150
|
+
uniqueByConstraint.set(key, columns);
|
|
151
|
+
}
|
|
152
|
+
for (const relation of relations.values()) {
|
|
153
|
+
relation.uniqueKeys = Array.from(uniqueByConstraint.entries())
|
|
154
|
+
.filter(([key]) => key.startsWith(`${relation.schema}.${relation.name}.`))
|
|
155
|
+
.map(([, columns]) => columns);
|
|
156
|
+
}
|
|
157
|
+
const fkByConstraint = new Map();
|
|
158
|
+
for (const row of fkResult.rows) {
|
|
159
|
+
const key = `${row.table_schema}.${row.table_name}.${row.constraint_name}`;
|
|
160
|
+
const existing = fkByConstraint.get(key) ?? {
|
|
161
|
+
name: row.constraint_name,
|
|
162
|
+
columns: [],
|
|
163
|
+
referencedSchema: row.foreign_table_schema,
|
|
164
|
+
referencedTable: row.foreign_table_name,
|
|
165
|
+
referencedColumns: [],
|
|
166
|
+
};
|
|
167
|
+
existing.columns.push(row.column_name);
|
|
168
|
+
existing.referencedColumns.push(row.foreign_column_name);
|
|
169
|
+
fkByConstraint.set(key, existing);
|
|
170
|
+
}
|
|
171
|
+
for (const relation of relations.values()) {
|
|
172
|
+
relation.foreignKeys = Array.from(fkByConstraint.entries())
|
|
173
|
+
.filter(([key]) => key.startsWith(`${relation.schema}.${relation.name}.`))
|
|
174
|
+
.map(([, fk]) => fk);
|
|
175
|
+
}
|
|
176
|
+
return { schemas, relations };
|
|
177
|
+
}
|
|
178
|
+
async function loadRelationIndexes(client, schema, relation) {
|
|
179
|
+
const result = await client.query(`SELECT indexname, indexdef
|
|
180
|
+
FROM pg_indexes
|
|
181
|
+
WHERE schemaname = $1 AND tablename = $2
|
|
182
|
+
ORDER BY indexname`, [schema, relation]);
|
|
183
|
+
return result.rows.flatMap((row) => {
|
|
184
|
+
const columns = extractIndexColumns(row.indexdef);
|
|
185
|
+
if (!columns) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
return [
|
|
189
|
+
{
|
|
190
|
+
name: row.indexname,
|
|
191
|
+
columns,
|
|
192
|
+
isUnique: /^CREATE\s+UNIQUE\s+INDEX\b/i.test(row.indexdef),
|
|
193
|
+
},
|
|
194
|
+
];
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function extractIndexColumns(indexDef) {
|
|
198
|
+
if (/\b(?:WHERE|INCLUDE)\b/i.test(indexDef)) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
const open = indexDef.indexOf('(');
|
|
202
|
+
const close = indexDef.indexOf(')', open + 1);
|
|
203
|
+
if (open < 0 || close < 0) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
const definition = indexDef.slice(open + 1, close);
|
|
207
|
+
if (!definition || definition.includes('(')) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
const columns = definition.split(',').map((part) => {
|
|
211
|
+
const identifier = part
|
|
212
|
+
.trim()
|
|
213
|
+
.match(/^"?([a-zA-Z_][a-zA-Z0-9_]*)"?(?:\s+(?:ASC|DESC))?(?:\s+NULLS\s+(?:FIRST|LAST))?$/i);
|
|
214
|
+
return identifier?.[1] ?? undefined;
|
|
215
|
+
});
|
|
216
|
+
return columns.every((column) => column !== undefined) ? columns : undefined;
|
|
217
|
+
}
|
|
218
|
+
function getCatalogRelation(catalog, schema, name) {
|
|
219
|
+
return catalog.relations.get(relationKey(schema, name));
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":";;AAkDA,kDAwBC;AAED,kDAqOC;AAED,kDA8BC;AA4BD,gDAMC;AAjXD,2CAA6C;AAwC7C,SAAS,WAAW,CAAC,MAAc,EAAE,IAAY;IAC/C,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,mBAAmB,CAAC,MAAc;IACtD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B;;;;;;;;;;;;;4BAawB,CACzB,CAAC;IAEF,OAAO,MAAM,CAAC,IAAI;SACf,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,0BAAc,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;SACrD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACb,IAAI,EAAE,GAAG,CAAC,WAAW;QACrB,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;KAC3C,CAAC,CAAC,CAAC;AACR,CAAC;AAEM,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,OAAgC;IAEhC,IAAI,OAAoB,CAAC;IAEzB,IAAI,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,0BAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CACvD,CAAC;QACF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QACtD,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,KAAK,CACtC;;2CAEqC,EACrC,CAAC,SAAS,CAAC,CACZ,CAAC;QACF,OAAO,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,KAAK,CACtC;;;;oDAI8C,CAC/C,CAAC;QAEF,OAAO,GAAG,IAAI,GAAG,CACf,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,0BAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAC7F,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvC,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,KAAK,CAKrC;;;;uCAImC,EACnC,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,KAAK,CAQtC;;;yDAGqD,EACrD,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAMjC;;;;;;;mEAO+D,EAC/D,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,KAAK,CAOrC;;;;;;;uFAOmF,EACnF,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAUjC;;;;;;;;;;;;;;;;;;0FAkBsF,EACtF,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;IAErD,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;YACrC,SAAS;QACX,CAAC;QAED,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE;YAC/D,MAAM,EAAE,KAAK,CAAC,YAAY;YAC1B,IAAI,EAAE,KAAK,CAAC,UAAU;YACtB,IAAI,EAAE,KAAK,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;YACpD,OAAO,EAAE,EAAE;YACX,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,EAAE;YACd,WAAW,EAAE,EAAE;SAChB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;QACpF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACpB,IAAI,EAAE,MAAM,CAAC,WAAW;YACxB,QAAQ,EAAE,MAAM,CAAC,SAAS;YAC1B,UAAU,EAAE,MAAM,CAAC,WAAW,KAAK,KAAK;YACxC,eAAe,EAAE,MAAM,CAAC,gBAAgB;SACzC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;IACjD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9B,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,UAAU,GAAG,OAAO,CAAC;QAChC,CAAC;IACH,CAAC;IAED,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAoB,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QAC3E,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9B,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QAC1C,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,CAAC;aAC3D,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;aACzE,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAS3B,CAAC;IAEJ,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QAC3E,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;YAC1C,IAAI,EAAE,GAAG,CAAC,eAAe;YACzB,OAAO,EAAE,EAAE;YACX,gBAAgB,EAAE,GAAG,CAAC,oBAAoB;YAC1C,eAAe,EAAE,GAAG,CAAC,kBAAkB;YACvC,iBAAiB,EAAE,EAAE;SACtB,CAAC;QACF,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACzD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QAC1C,QAAQ,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;aACxD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;aACzE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAChC,CAAC;AAEM,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,MAAc,EACd,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAI/B;;;wBAGoB,EACpB,CAAC,MAAM,EAAE,QAAQ,CAAC,CACnB,CAAC;IAEF,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL;gBACE,IAAI,EAAE,GAAG,CAAC,SAAS;gBACnB,OAAO;gBACP,QAAQ,EAAE,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;aAC3D;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,IAAI,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;IAC9C,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjD,MAAM,UAAU,GAAG,IAAI;aACpB,IAAI,EAAE;aACN,KAAK,CAAC,mFAAmF,CAAC,CAAC;QAC9F,OAAO,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACjG,CAAC;AAED,SAAgB,kBAAkB,CAChC,OAAwB,EACxB,MAAc,EACd,IAAY;IAEZ,OAAO,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const QUERY_PLAN_VERSION: 1;
|
|
2
|
+
export declare const DEFAULT_POSTGRES_QUERY_LIMIT = 100;
|
|
3
|
+
export declare const MAX_POSTGRES_QUERY_LIMIT = 500;
|
|
4
|
+
export declare const DEFAULT_PREVIEW_LIMIT = 10;
|
|
5
|
+
export declare const MAX_PREVIEW_LIMIT = 50;
|
|
6
|
+
export declare const DEFAULT_STATEMENT_TIMEOUT_MS = 10000;
|
|
7
|
+
export declare const MAX_STATEMENT_TIMEOUT_MS = 120000;
|
|
8
|
+
export declare const DEFAULT_TEMP_FILE_LIMIT_KB: number;
|
|
9
|
+
export declare const MAX_TEMP_FILE_LIMIT_KB: number;
|
|
10
|
+
export declare const DEFAULT_LOCK_TIMEOUT_MS = 2000;
|
|
11
|
+
export declare const DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = 5000;
|
|
12
|
+
export declare const DEFAULT_MAX_RESULT_BYTES = 256000;
|
|
13
|
+
export declare const MAX_RESULT_BYTES = 4194304;
|
|
14
|
+
export declare const DEFAULT_MAX_CELL_BYTES = 8192;
|
|
15
|
+
export declare const CURSOR_BATCH_SIZE = 200;
|
|
16
|
+
export declare const MAX_QUERY_INPUT_DEPTH = 64;
|
|
17
|
+
export declare const MAX_QUERY_INPUT_NODES = 4096;
|
|
18
|
+
export declare const DEFAULT_MAX_JOINS = 5;
|
|
19
|
+
export declare const DEFAULT_MAX_CTES = 3;
|
|
20
|
+
export declare const DEFAULT_MAX_SELECT_ITEMS = 64;
|
|
21
|
+
export declare const DEFAULT_MAX_IN_LIST_SIZE = 100;
|
|
22
|
+
export declare const DEFAULT_MAX_EXPRESSION_DEPTH = 8;
|
|
23
|
+
export declare const DEFAULT_MAX_QUERY_NODES = 200;
|
|
24
|
+
export declare const DEFAULT_EXPLAIN_COST_LIMIT = 50000;
|
|
25
|
+
export declare const SYSTEM_SCHEMAS: Set<string>;
|
|
26
|
+
export declare const COMPARISON_OPERATORS: readonly ["eq", "ne", "lt", "lte", "gt", "gte", "like", "ilike"];
|
|
27
|
+
export declare const AGGREGATE_FUNCTIONS: readonly ["count", "sum", "avg", "min", "max", "count_distinct"];
|
|
28
|
+
export declare const JOIN_TYPES: readonly ["inner", "left", "right", "full"];
|
|
29
|
+
export declare const SET_OPERATIONS: readonly ["union", "union_all", "intersect", "except"];
|
|
30
|
+
export declare const WINDOW_FUNCTIONS: readonly ["count", "sum", "avg", "min", "max", "row_number", "rank", "dense_rank", "lag", "lead"];
|
|
31
|
+
/** Niladic SQL keywords that must not be emitted as "name"(). */
|
|
32
|
+
export declare const NILADIC_KEYWORDS: Set<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Built-in functions that compile as identifier(args).
|
|
35
|
+
* Prefer date_part(field, source) over EXTRACT — EXTRACT needs keyword syntax.
|
|
36
|
+
* Window-only functions live in WINDOW_FUNCTIONS, not here.
|
|
37
|
+
*/
|
|
38
|
+
export declare const BUILTIN_FUNCTIONS: Set<string>;
|
|
39
|
+
export declare const DEFAULT_CATALOG_CACHE_TTL_MS = 30000;
|
|
40
|
+
export declare const DEFAULT_MAX_INSERT_ROWS = 1000;
|
|
41
|
+
export declare const MAX_INSERT_ROWS = 5000;
|
|
42
|
+
export declare const DEFAULT_MAX_INSERT_CSV_BYTES = 1048576;
|
|
43
|
+
export declare const MAX_INSERT_CSV_BYTES = 4194304;
|
|
44
|
+
export declare const DEFAULT_MAX_INSERT_REJECTION_DETAILS = 200;
|
|
45
|
+
export declare const MAX_INSERT_REJECTION_DETAILS = 1000;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_INSERT_REJECTION_DETAILS = exports.DEFAULT_MAX_INSERT_REJECTION_DETAILS = exports.MAX_INSERT_CSV_BYTES = exports.DEFAULT_MAX_INSERT_CSV_BYTES = exports.MAX_INSERT_ROWS = exports.DEFAULT_MAX_INSERT_ROWS = exports.DEFAULT_CATALOG_CACHE_TTL_MS = exports.BUILTIN_FUNCTIONS = exports.NILADIC_KEYWORDS = exports.WINDOW_FUNCTIONS = exports.SET_OPERATIONS = exports.JOIN_TYPES = exports.AGGREGATE_FUNCTIONS = exports.COMPARISON_OPERATORS = exports.SYSTEM_SCHEMAS = exports.DEFAULT_EXPLAIN_COST_LIMIT = exports.DEFAULT_MAX_QUERY_NODES = exports.DEFAULT_MAX_EXPRESSION_DEPTH = exports.DEFAULT_MAX_IN_LIST_SIZE = exports.DEFAULT_MAX_SELECT_ITEMS = exports.DEFAULT_MAX_CTES = exports.DEFAULT_MAX_JOINS = exports.MAX_QUERY_INPUT_NODES = exports.MAX_QUERY_INPUT_DEPTH = exports.CURSOR_BATCH_SIZE = exports.DEFAULT_MAX_CELL_BYTES = exports.MAX_RESULT_BYTES = exports.DEFAULT_MAX_RESULT_BYTES = exports.DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = exports.DEFAULT_LOCK_TIMEOUT_MS = exports.MAX_TEMP_FILE_LIMIT_KB = exports.DEFAULT_TEMP_FILE_LIMIT_KB = exports.MAX_STATEMENT_TIMEOUT_MS = exports.DEFAULT_STATEMENT_TIMEOUT_MS = exports.MAX_PREVIEW_LIMIT = exports.DEFAULT_PREVIEW_LIMIT = exports.MAX_POSTGRES_QUERY_LIMIT = exports.DEFAULT_POSTGRES_QUERY_LIMIT = exports.QUERY_PLAN_VERSION = void 0;
|
|
4
|
+
exports.QUERY_PLAN_VERSION = 1;
|
|
5
|
+
exports.DEFAULT_POSTGRES_QUERY_LIMIT = 100;
|
|
6
|
+
exports.MAX_POSTGRES_QUERY_LIMIT = 500;
|
|
7
|
+
exports.DEFAULT_PREVIEW_LIMIT = 10;
|
|
8
|
+
exports.MAX_PREVIEW_LIMIT = 50;
|
|
9
|
+
exports.DEFAULT_STATEMENT_TIMEOUT_MS = 10_000;
|
|
10
|
+
exports.MAX_STATEMENT_TIMEOUT_MS = 120_000;
|
|
11
|
+
exports.DEFAULT_TEMP_FILE_LIMIT_KB = 64 * 1024;
|
|
12
|
+
exports.MAX_TEMP_FILE_LIMIT_KB = 256 * 1024;
|
|
13
|
+
exports.DEFAULT_LOCK_TIMEOUT_MS = 2_000;
|
|
14
|
+
exports.DEFAULT_IDLE_IN_TRANSACTION_TIMEOUT_MS = 5_000;
|
|
15
|
+
exports.DEFAULT_MAX_RESULT_BYTES = 256_000;
|
|
16
|
+
exports.MAX_RESULT_BYTES = 4_194_304;
|
|
17
|
+
exports.DEFAULT_MAX_CELL_BYTES = 8_192;
|
|
18
|
+
exports.CURSOR_BATCH_SIZE = 200;
|
|
19
|
+
exports.MAX_QUERY_INPUT_DEPTH = 64;
|
|
20
|
+
exports.MAX_QUERY_INPUT_NODES = 4_096;
|
|
21
|
+
exports.DEFAULT_MAX_JOINS = 5;
|
|
22
|
+
exports.DEFAULT_MAX_CTES = 3;
|
|
23
|
+
exports.DEFAULT_MAX_SELECT_ITEMS = 64;
|
|
24
|
+
exports.DEFAULT_MAX_IN_LIST_SIZE = 100;
|
|
25
|
+
exports.DEFAULT_MAX_EXPRESSION_DEPTH = 8;
|
|
26
|
+
exports.DEFAULT_MAX_QUERY_NODES = 200;
|
|
27
|
+
exports.DEFAULT_EXPLAIN_COST_LIMIT = 50_000;
|
|
28
|
+
exports.SYSTEM_SCHEMAS = new Set(['pg_catalog', 'information_schema', 'pg_toast']);
|
|
29
|
+
exports.COMPARISON_OPERATORS = [
|
|
30
|
+
'eq',
|
|
31
|
+
'ne',
|
|
32
|
+
'lt',
|
|
33
|
+
'lte',
|
|
34
|
+
'gt',
|
|
35
|
+
'gte',
|
|
36
|
+
'like',
|
|
37
|
+
'ilike',
|
|
38
|
+
];
|
|
39
|
+
exports.AGGREGATE_FUNCTIONS = ['count', 'sum', 'avg', 'min', 'max', 'count_distinct'];
|
|
40
|
+
exports.JOIN_TYPES = ['inner', 'left', 'right', 'full'];
|
|
41
|
+
exports.SET_OPERATIONS = ['union', 'union_all', 'intersect', 'except'];
|
|
42
|
+
exports.WINDOW_FUNCTIONS = [
|
|
43
|
+
'count',
|
|
44
|
+
'sum',
|
|
45
|
+
'avg',
|
|
46
|
+
'min',
|
|
47
|
+
'max',
|
|
48
|
+
'row_number',
|
|
49
|
+
'rank',
|
|
50
|
+
'dense_rank',
|
|
51
|
+
'lag',
|
|
52
|
+
'lead',
|
|
53
|
+
];
|
|
54
|
+
/** Niladic SQL keywords that must not be emitted as "name"(). */
|
|
55
|
+
exports.NILADIC_KEYWORDS = new Set(['current_date', 'current_timestamp']);
|
|
56
|
+
/**
|
|
57
|
+
* Built-in functions that compile as identifier(args).
|
|
58
|
+
* Prefer date_part(field, source) over EXTRACT — EXTRACT needs keyword syntax.
|
|
59
|
+
* Window-only functions live in WINDOW_FUNCTIONS, not here.
|
|
60
|
+
*/
|
|
61
|
+
exports.BUILTIN_FUNCTIONS = new Set([
|
|
62
|
+
'coalesce',
|
|
63
|
+
'nullif',
|
|
64
|
+
'lower',
|
|
65
|
+
'upper',
|
|
66
|
+
'trim',
|
|
67
|
+
'length',
|
|
68
|
+
'abs',
|
|
69
|
+
'round',
|
|
70
|
+
'floor',
|
|
71
|
+
'ceil',
|
|
72
|
+
'date_trunc',
|
|
73
|
+
'date_part',
|
|
74
|
+
'now',
|
|
75
|
+
'concat',
|
|
76
|
+
'substring',
|
|
77
|
+
'replace',
|
|
78
|
+
'split_part',
|
|
79
|
+
'to_char',
|
|
80
|
+
'to_date',
|
|
81
|
+
'to_timestamp',
|
|
82
|
+
'greatest',
|
|
83
|
+
'least',
|
|
84
|
+
'jsonb_build_object',
|
|
85
|
+
'jsonb_extract_path_text',
|
|
86
|
+
]);
|
|
87
|
+
exports.DEFAULT_CATALOG_CACHE_TTL_MS = 30_000;
|
|
88
|
+
exports.DEFAULT_MAX_INSERT_ROWS = 1000;
|
|
89
|
+
exports.MAX_INSERT_ROWS = 5000;
|
|
90
|
+
exports.DEFAULT_MAX_INSERT_CSV_BYTES = 1_048_576;
|
|
91
|
+
exports.MAX_INSERT_CSV_BYTES = 4_194_304;
|
|
92
|
+
exports.DEFAULT_MAX_INSERT_REJECTION_DETAILS = 200;
|
|
93
|
+
exports.MAX_INSERT_REJECTION_DETAILS = 1000;
|
|
94
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type PostgresToolErrorCode = 'INVALID_INPUT' | 'POLICY_DENIED' | 'UNKNOWN_RELATION' | 'UNKNOWN_COLUMN' | 'COMPLEXITY_EXCEEDED' | 'COMPILATION_ERROR' | 'EXECUTION_ERROR' | 'TIMEOUT' | 'COST_EXCEEDED' | 'CONFIGURATION_ERROR';
|
|
2
|
+
export declare class PostgresToolError extends Error {
|
|
3
|
+
readonly code: PostgresToolErrorCode;
|
|
4
|
+
readonly path?: string;
|
|
5
|
+
readonly hint?: string;
|
|
6
|
+
constructor(code: PostgresToolErrorCode, message: string, options?: {
|
|
7
|
+
path?: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
});
|
|
11
|
+
toJSON(): {
|
|
12
|
+
code: PostgresToolErrorCode;
|
|
13
|
+
message: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
hint?: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare function isPostgresToolError(error: unknown): error is PostgresToolError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresToolError = void 0;
|
|
4
|
+
exports.isPostgresToolError = isPostgresToolError;
|
|
5
|
+
class PostgresToolError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
path;
|
|
8
|
+
hint;
|
|
9
|
+
constructor(code, message, options) {
|
|
10
|
+
super(message, { cause: options?.cause });
|
|
11
|
+
this.name = 'PostgresToolError';
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.path = options?.path;
|
|
14
|
+
this.hint = options?.hint;
|
|
15
|
+
}
|
|
16
|
+
toJSON() {
|
|
17
|
+
return {
|
|
18
|
+
code: this.code,
|
|
19
|
+
message: this.message,
|
|
20
|
+
...(this.path ? { path: this.path } : {}),
|
|
21
|
+
...(this.hint ? { hint: this.hint } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.PostgresToolError = PostgresToolError;
|
|
26
|
+
function isPostgresToolError(error) {
|
|
27
|
+
return error instanceof PostgresToolError;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=errors.js.map
|