@pgpmjs/export 0.28.0 → 0.29.0
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/esm/export-graphql-meta.js +16 -2
- package/esm/export-meta.js +25 -24
- package/esm/export-utils.js +42 -2
- package/esm/meta-export-tables.json +91 -6
- package/export-graphql-meta.js +15 -1
- package/export-meta.js +24 -23
- package/export-utils.d.ts +26 -1
- package/export-utils.js +46 -3
- package/meta-export-tables.json +91 -6
- package/package.json +9 -9
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Parser } from 'csv-to-pg';
|
|
9
9
|
import { toSnakeCase } from 'inflekt';
|
|
10
|
-
import { META_TABLE_CONFIG, META_TABLE_ORDER } from './export-utils';
|
|
10
|
+
import { getTimestampDefaultColumnsForTable, META_TABLE_CONFIG, META_TABLE_ORDER } from './export-utils';
|
|
11
11
|
import { buildFieldsFragment, getGraphQLQueryName, getGraphQLTypeName, graphqlRowToPostgresRow, intervalToPostgres, mapGraphQLTypeToFieldType } from './graphql-naming';
|
|
12
12
|
import { lookupByGqlType } from './type-map';
|
|
13
13
|
/**
|
|
@@ -57,7 +57,21 @@ const buildDynamicFieldsFromGraphQL = async (client, tableConfig) => {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
// Omit columns
|
|
60
|
+
// Omit timestamptz columns whose default supplies the current time. Their
|
|
61
|
+
// DDL DEFAULT will apply at deploy time, keeping generated INSERT rows
|
|
62
|
+
// free of literal environment-specific timestamps.
|
|
63
|
+
const timestampDefaultColumns = getTimestampDefaultColumnsForTable(tableConfig.schema, tableConfig.table);
|
|
64
|
+
if (timestampDefaultColumns.length > 0) {
|
|
65
|
+
tableConfig.columnDefaults = tableConfig.columnDefaults || {};
|
|
66
|
+
for (const colName of timestampDefaultColumns) {
|
|
67
|
+
if (dynamicFields[colName] === 'timestamptz') {
|
|
68
|
+
delete dynamicFields[colName];
|
|
69
|
+
enumFields.delete(colName);
|
|
70
|
+
tableConfig.columnDefaults[colName] = '';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Omit columns that are explicitly marked as columnDefaults — their DDL DEFAULT (e.g.
|
|
61
75
|
// current_database()) will supply the correct value at deploy time, so the
|
|
62
76
|
// exported INSERT must not hardcode an environment-specific literal.
|
|
63
77
|
if (tableConfig.columnDefaults) {
|
package/esm/export-meta.js
CHANGED
|
@@ -1,39 +1,30 @@
|
|
|
1
1
|
import { Parser } from 'csv-to-pg';
|
|
2
2
|
import { getPgPool } from 'pg-cache';
|
|
3
|
-
import {
|
|
4
|
-
/**
|
|
5
|
-
* Query actual columns from information_schema for a given table.
|
|
6
|
-
* Returns a map of column_name -> udt_name (PostgreSQL type).
|
|
7
|
-
*/
|
|
8
|
-
const getTableColumns = async (pool, schemaName, tableName) => {
|
|
9
|
-
const result = await pool.query(`
|
|
10
|
-
SELECT column_name, udt_name
|
|
11
|
-
FROM information_schema.columns
|
|
12
|
-
WHERE table_schema = $1 AND table_name = $2
|
|
13
|
-
ORDER BY ordinal_position
|
|
14
|
-
`, [schemaName, tableName]);
|
|
15
|
-
const columns = new Map();
|
|
16
|
-
for (const row of result.rows) {
|
|
17
|
-
columns.set(row.column_name, row.udt_name);
|
|
18
|
-
}
|
|
19
|
-
return columns;
|
|
20
|
-
};
|
|
3
|
+
import { getTableColumnsWithDefaults, isTimestampDefaultColumn, mapPgTypeToFieldType, META_TABLE_CONFIG, META_TABLE_ORDER } from './export-utils';
|
|
21
4
|
/**
|
|
22
5
|
* Build dynamic fields config from the database via information_schema.
|
|
23
6
|
* - All fields are derived from `information_schema.columns` + `mapPgTypeToFieldType`.
|
|
24
7
|
* - `typeOverrides` from the config are applied on top for special types
|
|
25
8
|
* (image, upload, url) that cannot be inferred from PG types alone.
|
|
9
|
+
* - `timestamptz` columns with non-deterministic timestamp defaults (now(),
|
|
10
|
+
* CURRENT_TIMESTAMP, clock_timestamp(), or now() + interval) are omitted so
|
|
11
|
+
* their DDL DEFAULT supplies the value at deploy time.
|
|
26
12
|
*/
|
|
27
13
|
const buildDynamicFields = async (pool, tableConfig) => {
|
|
28
|
-
const actualColumns = await
|
|
14
|
+
const actualColumns = await getTableColumnsWithDefaults(pool, tableConfig.schema, tableConfig.table);
|
|
29
15
|
if (actualColumns.size === 0) {
|
|
30
16
|
// Table doesn't exist, return empty fields
|
|
31
17
|
return {};
|
|
32
18
|
}
|
|
33
19
|
const dynamicFields = {};
|
|
20
|
+
const timestampDefaultColumns = [];
|
|
34
21
|
// Derive all fields from information_schema
|
|
35
|
-
for (const [columnName,
|
|
36
|
-
|
|
22
|
+
for (const [columnName, { udt_name, column_default }] of actualColumns) {
|
|
23
|
+
const fieldType = mapPgTypeToFieldType(udt_name);
|
|
24
|
+
dynamicFields[columnName] = fieldType;
|
|
25
|
+
if (fieldType === 'timestamptz' && isTimestampDefaultColumn(column_default)) {
|
|
26
|
+
timestampDefaultColumns.push(columnName);
|
|
27
|
+
}
|
|
37
28
|
}
|
|
38
29
|
// Apply type overrides (image, upload, url)
|
|
39
30
|
if (tableConfig.typeOverrides) {
|
|
@@ -43,9 +34,19 @@ const buildDynamicFields = async (pool, tableConfig) => {
|
|
|
43
34
|
}
|
|
44
35
|
}
|
|
45
36
|
}
|
|
46
|
-
// Omit columns
|
|
47
|
-
//
|
|
48
|
-
//
|
|
37
|
+
// Omit timestamptz columns whose default supplies the current time. Their
|
|
38
|
+
// DDL DEFAULT will apply at deploy time, keeping generated INSERT rows
|
|
39
|
+
// free of literal environment-specific timestamps.
|
|
40
|
+
if (timestampDefaultColumns.length > 0) {
|
|
41
|
+
tableConfig.columnDefaults = tableConfig.columnDefaults || {};
|
|
42
|
+
for (const colName of timestampDefaultColumns) {
|
|
43
|
+
delete dynamicFields[colName];
|
|
44
|
+
tableConfig.columnDefaults[colName] = actualColumns.get(colName)?.column_default || '';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Omit columns that are explicitly marked as columnDefaults — their DDL
|
|
48
|
+
// DEFAULT (e.g. current_database()) will supply the correct value at deploy
|
|
49
|
+
// time, so the exported INSERT must not hardcode an environment-specific literal.
|
|
49
50
|
if (tableConfig.columnDefaults) {
|
|
50
51
|
for (const colName of Object.keys(tableConfig.columnDefaults)) {
|
|
51
52
|
delete dynamicFields[colName];
|
package/esm/export-utils.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { getMissingInstallableModules, parseAuthor, PgpmPackage } from '@pgpmjs/core';
|
|
1
2
|
import { mkdirSync, rmSync } from 'fs';
|
|
2
3
|
import { sync as glob } from 'glob';
|
|
3
4
|
import { toSnakeCase } from 'inflekt';
|
|
4
5
|
import path from 'path';
|
|
5
|
-
import { PgpmPackage, getMissingInstallableModules, parseAuthor } from '@pgpmjs/core';
|
|
6
|
-
import { lookupByPgUdt } from './type-map';
|
|
7
6
|
import metaExportTables from './meta-export-tables.json';
|
|
7
|
+
import { lookupByPgUdt } from './type-map';
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// Shared constants
|
|
10
10
|
// =============================================================================
|
|
@@ -47,6 +47,38 @@ export const mapPgTypeToFieldType = (udtName) => {
|
|
|
47
47
|
const entry = lookupByPgUdt(udtName);
|
|
48
48
|
return entry?.fieldType ?? 'text';
|
|
49
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Query actual columns from information_schema for a given table.
|
|
52
|
+
* Returns a map of column_name -> { udt_name, column_default }.
|
|
53
|
+
*/
|
|
54
|
+
export const getTableColumnsWithDefaults = async (pool, schemaName, tableName) => {
|
|
55
|
+
const result = await pool.query(`
|
|
56
|
+
SELECT column_name, udt_name, column_default
|
|
57
|
+
FROM information_schema.columns
|
|
58
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
59
|
+
ORDER BY ordinal_position
|
|
60
|
+
`, [schemaName, tableName]);
|
|
61
|
+
const columns = new Map();
|
|
62
|
+
for (const row of result.rows) {
|
|
63
|
+
columns.set(row.column_name, {
|
|
64
|
+
udt_name: row.udt_name,
|
|
65
|
+
column_default: row.column_default
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return columns;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Detect whether a column default expression is a non-deterministic timestamp
|
|
72
|
+
* default (now(), CURRENT_TIMESTAMP, clock_timestamp(), or now() + interval).
|
|
73
|
+
* Exported INSERT rows must omit these columns so the DDL DEFAULT applies at
|
|
74
|
+
* deploy time, keeping generated migrations deterministic.
|
|
75
|
+
*/
|
|
76
|
+
export const isTimestampDefaultColumn = (columnDefault) => {
|
|
77
|
+
if (!columnDefault)
|
|
78
|
+
return false;
|
|
79
|
+
const normalized = columnDefault.trim().toLowerCase();
|
|
80
|
+
return /^(now\s*\(\s*\)|current_timestamp(?:\s*\(\s*\d*\s*\))?|clock_timestamp\s*\(\s*\))(?:\s*\+\s*'[^']*'\s*::\s*interval)?$/i.test(normalized);
|
|
81
|
+
};
|
|
50
82
|
/**
|
|
51
83
|
* Required extensions for service/meta exports.
|
|
52
84
|
* Includes native PostgreSQL extensions and pgpm modules for metadata management.
|
|
@@ -145,6 +177,14 @@ export const META_TABLE_CONFIG = Object.fromEntries(metaExportTables.tables.map(
|
|
|
145
177
|
t.key,
|
|
146
178
|
{ schema: t.schema, table: t.table, ...META_TABLE_OVERRIDES[t.key] }
|
|
147
179
|
]));
|
|
180
|
+
/**
|
|
181
|
+
* Per-table timestamptz columns whose DDL default is non-deterministic
|
|
182
|
+
* (now(), CURRENT_TIMESTAMP, clock_timestamp(), now() + interval).
|
|
183
|
+
* Generated by constructive-db and propagated here via constructive-hub.
|
|
184
|
+
* The GraphQL export path uses this to omit those columns without a DB pool.
|
|
185
|
+
*/
|
|
186
|
+
export const META_TABLE_TIMESTAMP_DEFAULTS = metaExportTables.timestampDefaultColumns || {};
|
|
187
|
+
export const getTimestampDefaultColumnsForTable = (schema, table) => META_TABLE_TIMESTAMP_DEFAULTS[`${schema}.${table}`] || [];
|
|
148
188
|
// =============================================================================
|
|
149
189
|
// Shared functions
|
|
150
190
|
// =============================================================================
|
|
@@ -281,6 +281,11 @@
|
|
|
281
281
|
"schema": "metaschema_modules_public",
|
|
282
282
|
"table": "infra_secrets_module"
|
|
283
283
|
},
|
|
284
|
+
{
|
|
285
|
+
"key": "integration_providers_module",
|
|
286
|
+
"schema": "metaschema_modules_public",
|
|
287
|
+
"table": "integration_providers_module"
|
|
288
|
+
},
|
|
284
289
|
{
|
|
285
290
|
"key": "internal_secrets_module",
|
|
286
291
|
"schema": "metaschema_modules_public",
|
|
@@ -436,11 +441,6 @@
|
|
|
436
441
|
"schema": "metaschema_public",
|
|
437
442
|
"table": "embedding_chunks"
|
|
438
443
|
},
|
|
439
|
-
{
|
|
440
|
-
"key": "partition",
|
|
441
|
-
"schema": "metaschema_public",
|
|
442
|
-
"table": "partition"
|
|
443
|
-
},
|
|
444
444
|
{
|
|
445
445
|
"key": "spatial_relation",
|
|
446
446
|
"schema": "metaschema_public",
|
|
@@ -501,5 +501,90 @@
|
|
|
501
501
|
"schema": "metaschema_modules_public",
|
|
502
502
|
"table": "graph_execution_module"
|
|
503
503
|
}
|
|
504
|
-
]
|
|
504
|
+
],
|
|
505
|
+
"timestampDefaultColumns": {
|
|
506
|
+
"metaschema_modules_public.db_preset_module": [
|
|
507
|
+
"created_at"
|
|
508
|
+
],
|
|
509
|
+
"metaschema_modules_public.graph_execution_module": [
|
|
510
|
+
"created_at"
|
|
511
|
+
],
|
|
512
|
+
"metaschema_modules_public.graph_module": [
|
|
513
|
+
"created_at"
|
|
514
|
+
],
|
|
515
|
+
"metaschema_modules_public.hierarchy_module": [
|
|
516
|
+
"created_at"
|
|
517
|
+
],
|
|
518
|
+
"metaschema_modules_public.merkle_store_module": [
|
|
519
|
+
"created_at"
|
|
520
|
+
],
|
|
521
|
+
"metaschema_public.check_constraint": [
|
|
522
|
+
"created_at",
|
|
523
|
+
"updated_at"
|
|
524
|
+
],
|
|
525
|
+
"metaschema_public.database": [
|
|
526
|
+
"created_at",
|
|
527
|
+
"updated_at"
|
|
528
|
+
],
|
|
529
|
+
"metaschema_public.embedding_chunks": [
|
|
530
|
+
"created_at",
|
|
531
|
+
"updated_at"
|
|
532
|
+
],
|
|
533
|
+
"metaschema_public.field": [
|
|
534
|
+
"created_at",
|
|
535
|
+
"updated_at"
|
|
536
|
+
],
|
|
537
|
+
"metaschema_public.foreign_key_constraint": [
|
|
538
|
+
"created_at",
|
|
539
|
+
"updated_at"
|
|
540
|
+
],
|
|
541
|
+
"metaschema_public.full_text_search": [
|
|
542
|
+
"created_at",
|
|
543
|
+
"updated_at"
|
|
544
|
+
],
|
|
545
|
+
"metaschema_public.index": [
|
|
546
|
+
"created_at",
|
|
547
|
+
"updated_at"
|
|
548
|
+
],
|
|
549
|
+
"metaschema_public.policy": [
|
|
550
|
+
"created_at",
|
|
551
|
+
"updated_at"
|
|
552
|
+
],
|
|
553
|
+
"metaschema_public.primary_key_constraint": [
|
|
554
|
+
"created_at",
|
|
555
|
+
"updated_at"
|
|
556
|
+
],
|
|
557
|
+
"metaschema_public.schema": [
|
|
558
|
+
"created_at",
|
|
559
|
+
"updated_at"
|
|
560
|
+
],
|
|
561
|
+
"metaschema_public.schema_grant": [
|
|
562
|
+
"created_at",
|
|
563
|
+
"updated_at"
|
|
564
|
+
],
|
|
565
|
+
"metaschema_public.spatial_relation": [
|
|
566
|
+
"created_at",
|
|
567
|
+
"updated_at"
|
|
568
|
+
],
|
|
569
|
+
"metaschema_public.table": [
|
|
570
|
+
"created_at",
|
|
571
|
+
"updated_at"
|
|
572
|
+
],
|
|
573
|
+
"metaschema_public.table_grant": [
|
|
574
|
+
"created_at",
|
|
575
|
+
"updated_at"
|
|
576
|
+
],
|
|
577
|
+
"metaschema_public.trigger": [
|
|
578
|
+
"created_at",
|
|
579
|
+
"updated_at"
|
|
580
|
+
],
|
|
581
|
+
"metaschema_public.trigger_function": [
|
|
582
|
+
"created_at",
|
|
583
|
+
"updated_at"
|
|
584
|
+
],
|
|
585
|
+
"metaschema_public.unique_constraint": [
|
|
586
|
+
"created_at",
|
|
587
|
+
"updated_at"
|
|
588
|
+
]
|
|
589
|
+
}
|
|
505
590
|
}
|
package/export-graphql-meta.js
CHANGED
|
@@ -60,7 +60,21 @@ const buildDynamicFieldsFromGraphQL = async (client, tableConfig) => {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
// Omit columns
|
|
63
|
+
// Omit timestamptz columns whose default supplies the current time. Their
|
|
64
|
+
// DDL DEFAULT will apply at deploy time, keeping generated INSERT rows
|
|
65
|
+
// free of literal environment-specific timestamps.
|
|
66
|
+
const timestampDefaultColumns = (0, export_utils_1.getTimestampDefaultColumnsForTable)(tableConfig.schema, tableConfig.table);
|
|
67
|
+
if (timestampDefaultColumns.length > 0) {
|
|
68
|
+
tableConfig.columnDefaults = tableConfig.columnDefaults || {};
|
|
69
|
+
for (const colName of timestampDefaultColumns) {
|
|
70
|
+
if (dynamicFields[colName] === 'timestamptz') {
|
|
71
|
+
delete dynamicFields[colName];
|
|
72
|
+
enumFields.delete(colName);
|
|
73
|
+
tableConfig.columnDefaults[colName] = '';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Omit columns that are explicitly marked as columnDefaults — their DDL DEFAULT (e.g.
|
|
64
78
|
// current_database()) will supply the correct value at deploy time, so the
|
|
65
79
|
// exported INSERT must not hardcode an environment-specific literal.
|
|
66
80
|
if (tableConfig.columnDefaults) {
|
package/export-meta.js
CHANGED
|
@@ -4,39 +4,30 @@ exports.exportMeta = void 0;
|
|
|
4
4
|
const csv_to_pg_1 = require("csv-to-pg");
|
|
5
5
|
const pg_cache_1 = require("pg-cache");
|
|
6
6
|
const export_utils_1 = require("./export-utils");
|
|
7
|
-
/**
|
|
8
|
-
* Query actual columns from information_schema for a given table.
|
|
9
|
-
* Returns a map of column_name -> udt_name (PostgreSQL type).
|
|
10
|
-
*/
|
|
11
|
-
const getTableColumns = async (pool, schemaName, tableName) => {
|
|
12
|
-
const result = await pool.query(`
|
|
13
|
-
SELECT column_name, udt_name
|
|
14
|
-
FROM information_schema.columns
|
|
15
|
-
WHERE table_schema = $1 AND table_name = $2
|
|
16
|
-
ORDER BY ordinal_position
|
|
17
|
-
`, [schemaName, tableName]);
|
|
18
|
-
const columns = new Map();
|
|
19
|
-
for (const row of result.rows) {
|
|
20
|
-
columns.set(row.column_name, row.udt_name);
|
|
21
|
-
}
|
|
22
|
-
return columns;
|
|
23
|
-
};
|
|
24
7
|
/**
|
|
25
8
|
* Build dynamic fields config from the database via information_schema.
|
|
26
9
|
* - All fields are derived from `information_schema.columns` + `mapPgTypeToFieldType`.
|
|
27
10
|
* - `typeOverrides` from the config are applied on top for special types
|
|
28
11
|
* (image, upload, url) that cannot be inferred from PG types alone.
|
|
12
|
+
* - `timestamptz` columns with non-deterministic timestamp defaults (now(),
|
|
13
|
+
* CURRENT_TIMESTAMP, clock_timestamp(), or now() + interval) are omitted so
|
|
14
|
+
* their DDL DEFAULT supplies the value at deploy time.
|
|
29
15
|
*/
|
|
30
16
|
const buildDynamicFields = async (pool, tableConfig) => {
|
|
31
|
-
const actualColumns = await
|
|
17
|
+
const actualColumns = await (0, export_utils_1.getTableColumnsWithDefaults)(pool, tableConfig.schema, tableConfig.table);
|
|
32
18
|
if (actualColumns.size === 0) {
|
|
33
19
|
// Table doesn't exist, return empty fields
|
|
34
20
|
return {};
|
|
35
21
|
}
|
|
36
22
|
const dynamicFields = {};
|
|
23
|
+
const timestampDefaultColumns = [];
|
|
37
24
|
// Derive all fields from information_schema
|
|
38
|
-
for (const [columnName,
|
|
39
|
-
|
|
25
|
+
for (const [columnName, { udt_name, column_default }] of actualColumns) {
|
|
26
|
+
const fieldType = (0, export_utils_1.mapPgTypeToFieldType)(udt_name);
|
|
27
|
+
dynamicFields[columnName] = fieldType;
|
|
28
|
+
if (fieldType === 'timestamptz' && (0, export_utils_1.isTimestampDefaultColumn)(column_default)) {
|
|
29
|
+
timestampDefaultColumns.push(columnName);
|
|
30
|
+
}
|
|
40
31
|
}
|
|
41
32
|
// Apply type overrides (image, upload, url)
|
|
42
33
|
if (tableConfig.typeOverrides) {
|
|
@@ -46,9 +37,19 @@ const buildDynamicFields = async (pool, tableConfig) => {
|
|
|
46
37
|
}
|
|
47
38
|
}
|
|
48
39
|
}
|
|
49
|
-
// Omit columns
|
|
50
|
-
//
|
|
51
|
-
//
|
|
40
|
+
// Omit timestamptz columns whose default supplies the current time. Their
|
|
41
|
+
// DDL DEFAULT will apply at deploy time, keeping generated INSERT rows
|
|
42
|
+
// free of literal environment-specific timestamps.
|
|
43
|
+
if (timestampDefaultColumns.length > 0) {
|
|
44
|
+
tableConfig.columnDefaults = tableConfig.columnDefaults || {};
|
|
45
|
+
for (const colName of timestampDefaultColumns) {
|
|
46
|
+
delete dynamicFields[colName];
|
|
47
|
+
tableConfig.columnDefaults[colName] = actualColumns.get(colName)?.column_default || '';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Omit columns that are explicitly marked as columnDefaults — their DDL
|
|
51
|
+
// DEFAULT (e.g. current_database()) will supply the correct value at deploy
|
|
52
|
+
// time, so the exported INSERT must not hardcode an environment-specific literal.
|
|
52
53
|
if (tableConfig.columnDefaults) {
|
|
53
54
|
for (const colName of Object.keys(tableConfig.columnDefaults)) {
|
|
54
55
|
delete dynamicFields[colName];
|
package/export-utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Inquirerer } from 'inquirerer';
|
|
2
1
|
import { PgpmPackage } from '@pgpmjs/core';
|
|
2
|
+
import { Inquirerer } from 'inquirerer';
|
|
3
|
+
import type { Pool } from 'pg';
|
|
3
4
|
/**
|
|
4
5
|
* Required extensions for database schema exports.
|
|
5
6
|
* Includes native PostgreSQL extensions and pgpm modules.
|
|
@@ -11,6 +12,22 @@ export declare const DB_REQUIRED_EXTENSIONS: readonly ["plpgsql", "uuid-ossp", "
|
|
|
11
12
|
* Delegates to the canonical PG_TYPE_MAP in type-map.ts.
|
|
12
13
|
*/
|
|
13
14
|
export declare const mapPgTypeToFieldType: (udtName: string) => FieldType;
|
|
15
|
+
export interface TableColumnInfo {
|
|
16
|
+
udt_name: string;
|
|
17
|
+
column_default: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Query actual columns from information_schema for a given table.
|
|
21
|
+
* Returns a map of column_name -> { udt_name, column_default }.
|
|
22
|
+
*/
|
|
23
|
+
export declare const getTableColumnsWithDefaults: (pool: Pool, schemaName: string, tableName: string) => Promise<Map<string, TableColumnInfo>>;
|
|
24
|
+
/**
|
|
25
|
+
* Detect whether a column default expression is a non-deterministic timestamp
|
|
26
|
+
* default (now(), CURRENT_TIMESTAMP, clock_timestamp(), or now() + interval).
|
|
27
|
+
* Exported INSERT rows must omit these columns so the DDL DEFAULT applies at
|
|
28
|
+
* deploy time, keeping generated migrations deterministic.
|
|
29
|
+
*/
|
|
30
|
+
export declare const isTimestampDefaultColumn: (columnDefault: string | null) => boolean;
|
|
14
31
|
/**
|
|
15
32
|
* Required extensions for service/meta exports.
|
|
16
33
|
* Includes native PostgreSQL extensions and pgpm modules for metadata management.
|
|
@@ -75,6 +92,14 @@ export declare const META_TABLE_ORDER: string[];
|
|
|
75
92
|
* that cannot be inferred from database/GraphQL types alone.
|
|
76
93
|
*/
|
|
77
94
|
export declare const META_TABLE_CONFIG: Record<string, TableConfig>;
|
|
95
|
+
/**
|
|
96
|
+
* Per-table timestamptz columns whose DDL default is non-deterministic
|
|
97
|
+
* (now(), CURRENT_TIMESTAMP, clock_timestamp(), now() + interval).
|
|
98
|
+
* Generated by constructive-db and propagated here via constructive-hub.
|
|
99
|
+
* The GraphQL export path uses this to omit those columns without a DB pool.
|
|
100
|
+
*/
|
|
101
|
+
export declare const META_TABLE_TIMESTAMP_DEFAULTS: Record<string, string[]>;
|
|
102
|
+
export declare const getTimestampDefaultColumnsForTable: (schema: string, table: string) => string[];
|
|
78
103
|
export interface Schema {
|
|
79
104
|
name: string;
|
|
80
105
|
schema_name: string;
|
package/export-utils.js
CHANGED
|
@@ -3,14 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.normalizeOutdir = exports.preparePackage = exports.makeReplacer = exports.installMissingModules = exports.detectMissingModules = exports.META_TABLE_CONFIG = exports.META_TABLE_ORDER = exports.META_TABLE_OVERRIDES = exports.META_COMMON_FOOTER = exports.META_COMMON_HEADER = exports.SERVICE_REQUIRED_EXTENSIONS = exports.mapPgTypeToFieldType = exports.DB_REQUIRED_EXTENSIONS = void 0;
|
|
6
|
+
exports.normalizeOutdir = exports.preparePackage = exports.makeReplacer = exports.installMissingModules = exports.detectMissingModules = exports.getTimestampDefaultColumnsForTable = exports.META_TABLE_TIMESTAMP_DEFAULTS = exports.META_TABLE_CONFIG = exports.META_TABLE_ORDER = exports.META_TABLE_OVERRIDES = exports.META_COMMON_FOOTER = exports.META_COMMON_HEADER = exports.SERVICE_REQUIRED_EXTENSIONS = exports.isTimestampDefaultColumn = exports.getTableColumnsWithDefaults = exports.mapPgTypeToFieldType = exports.DB_REQUIRED_EXTENSIONS = void 0;
|
|
7
|
+
const core_1 = require("@pgpmjs/core");
|
|
7
8
|
const fs_1 = require("fs");
|
|
8
9
|
const glob_1 = require("glob");
|
|
9
10
|
const inflekt_1 = require("inflekt");
|
|
10
11
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const core_1 = require("@pgpmjs/core");
|
|
12
|
-
const type_map_1 = require("./type-map");
|
|
13
12
|
const meta_export_tables_json_1 = __importDefault(require("./meta-export-tables.json"));
|
|
13
|
+
const type_map_1 = require("./type-map");
|
|
14
14
|
// =============================================================================
|
|
15
15
|
// Shared constants
|
|
16
16
|
// =============================================================================
|
|
@@ -54,6 +54,40 @@ const mapPgTypeToFieldType = (udtName) => {
|
|
|
54
54
|
return entry?.fieldType ?? 'text';
|
|
55
55
|
};
|
|
56
56
|
exports.mapPgTypeToFieldType = mapPgTypeToFieldType;
|
|
57
|
+
/**
|
|
58
|
+
* Query actual columns from information_schema for a given table.
|
|
59
|
+
* Returns a map of column_name -> { udt_name, column_default }.
|
|
60
|
+
*/
|
|
61
|
+
const getTableColumnsWithDefaults = async (pool, schemaName, tableName) => {
|
|
62
|
+
const result = await pool.query(`
|
|
63
|
+
SELECT column_name, udt_name, column_default
|
|
64
|
+
FROM information_schema.columns
|
|
65
|
+
WHERE table_schema = $1 AND table_name = $2
|
|
66
|
+
ORDER BY ordinal_position
|
|
67
|
+
`, [schemaName, tableName]);
|
|
68
|
+
const columns = new Map();
|
|
69
|
+
for (const row of result.rows) {
|
|
70
|
+
columns.set(row.column_name, {
|
|
71
|
+
udt_name: row.udt_name,
|
|
72
|
+
column_default: row.column_default
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return columns;
|
|
76
|
+
};
|
|
77
|
+
exports.getTableColumnsWithDefaults = getTableColumnsWithDefaults;
|
|
78
|
+
/**
|
|
79
|
+
* Detect whether a column default expression is a non-deterministic timestamp
|
|
80
|
+
* default (now(), CURRENT_TIMESTAMP, clock_timestamp(), or now() + interval).
|
|
81
|
+
* Exported INSERT rows must omit these columns so the DDL DEFAULT applies at
|
|
82
|
+
* deploy time, keeping generated migrations deterministic.
|
|
83
|
+
*/
|
|
84
|
+
const isTimestampDefaultColumn = (columnDefault) => {
|
|
85
|
+
if (!columnDefault)
|
|
86
|
+
return false;
|
|
87
|
+
const normalized = columnDefault.trim().toLowerCase();
|
|
88
|
+
return /^(now\s*\(\s*\)|current_timestamp(?:\s*\(\s*\d*\s*\))?|clock_timestamp\s*\(\s*\))(?:\s*\+\s*'[^']*'\s*::\s*interval)?$/i.test(normalized);
|
|
89
|
+
};
|
|
90
|
+
exports.isTimestampDefaultColumn = isTimestampDefaultColumn;
|
|
57
91
|
/**
|
|
58
92
|
* Required extensions for service/meta exports.
|
|
59
93
|
* Includes native PostgreSQL extensions and pgpm modules for metadata management.
|
|
@@ -152,6 +186,15 @@ exports.META_TABLE_CONFIG = Object.fromEntries(meta_export_tables_json_1.default
|
|
|
152
186
|
t.key,
|
|
153
187
|
{ schema: t.schema, table: t.table, ...exports.META_TABLE_OVERRIDES[t.key] }
|
|
154
188
|
]));
|
|
189
|
+
/**
|
|
190
|
+
* Per-table timestamptz columns whose DDL default is non-deterministic
|
|
191
|
+
* (now(), CURRENT_TIMESTAMP, clock_timestamp(), now() + interval).
|
|
192
|
+
* Generated by constructive-db and propagated here via constructive-hub.
|
|
193
|
+
* The GraphQL export path uses this to omit those columns without a DB pool.
|
|
194
|
+
*/
|
|
195
|
+
exports.META_TABLE_TIMESTAMP_DEFAULTS = meta_export_tables_json_1.default.timestampDefaultColumns || {};
|
|
196
|
+
const getTimestampDefaultColumnsForTable = (schema, table) => exports.META_TABLE_TIMESTAMP_DEFAULTS[`${schema}.${table}`] || [];
|
|
197
|
+
exports.getTimestampDefaultColumnsForTable = getTimestampDefaultColumnsForTable;
|
|
155
198
|
// =============================================================================
|
|
156
199
|
// Shared functions
|
|
157
200
|
// =============================================================================
|
package/meta-export-tables.json
CHANGED
|
@@ -281,6 +281,11 @@
|
|
|
281
281
|
"schema": "metaschema_modules_public",
|
|
282
282
|
"table": "infra_secrets_module"
|
|
283
283
|
},
|
|
284
|
+
{
|
|
285
|
+
"key": "integration_providers_module",
|
|
286
|
+
"schema": "metaschema_modules_public",
|
|
287
|
+
"table": "integration_providers_module"
|
|
288
|
+
},
|
|
284
289
|
{
|
|
285
290
|
"key": "internal_secrets_module",
|
|
286
291
|
"schema": "metaschema_modules_public",
|
|
@@ -436,11 +441,6 @@
|
|
|
436
441
|
"schema": "metaschema_public",
|
|
437
442
|
"table": "embedding_chunks"
|
|
438
443
|
},
|
|
439
|
-
{
|
|
440
|
-
"key": "partition",
|
|
441
|
-
"schema": "metaschema_public",
|
|
442
|
-
"table": "partition"
|
|
443
|
-
},
|
|
444
444
|
{
|
|
445
445
|
"key": "spatial_relation",
|
|
446
446
|
"schema": "metaschema_public",
|
|
@@ -501,5 +501,90 @@
|
|
|
501
501
|
"schema": "metaschema_modules_public",
|
|
502
502
|
"table": "graph_execution_module"
|
|
503
503
|
}
|
|
504
|
-
]
|
|
504
|
+
],
|
|
505
|
+
"timestampDefaultColumns": {
|
|
506
|
+
"metaschema_modules_public.db_preset_module": [
|
|
507
|
+
"created_at"
|
|
508
|
+
],
|
|
509
|
+
"metaschema_modules_public.graph_execution_module": [
|
|
510
|
+
"created_at"
|
|
511
|
+
],
|
|
512
|
+
"metaschema_modules_public.graph_module": [
|
|
513
|
+
"created_at"
|
|
514
|
+
],
|
|
515
|
+
"metaschema_modules_public.hierarchy_module": [
|
|
516
|
+
"created_at"
|
|
517
|
+
],
|
|
518
|
+
"metaschema_modules_public.merkle_store_module": [
|
|
519
|
+
"created_at"
|
|
520
|
+
],
|
|
521
|
+
"metaschema_public.check_constraint": [
|
|
522
|
+
"created_at",
|
|
523
|
+
"updated_at"
|
|
524
|
+
],
|
|
525
|
+
"metaschema_public.database": [
|
|
526
|
+
"created_at",
|
|
527
|
+
"updated_at"
|
|
528
|
+
],
|
|
529
|
+
"metaschema_public.embedding_chunks": [
|
|
530
|
+
"created_at",
|
|
531
|
+
"updated_at"
|
|
532
|
+
],
|
|
533
|
+
"metaschema_public.field": [
|
|
534
|
+
"created_at",
|
|
535
|
+
"updated_at"
|
|
536
|
+
],
|
|
537
|
+
"metaschema_public.foreign_key_constraint": [
|
|
538
|
+
"created_at",
|
|
539
|
+
"updated_at"
|
|
540
|
+
],
|
|
541
|
+
"metaschema_public.full_text_search": [
|
|
542
|
+
"created_at",
|
|
543
|
+
"updated_at"
|
|
544
|
+
],
|
|
545
|
+
"metaschema_public.index": [
|
|
546
|
+
"created_at",
|
|
547
|
+
"updated_at"
|
|
548
|
+
],
|
|
549
|
+
"metaschema_public.policy": [
|
|
550
|
+
"created_at",
|
|
551
|
+
"updated_at"
|
|
552
|
+
],
|
|
553
|
+
"metaschema_public.primary_key_constraint": [
|
|
554
|
+
"created_at",
|
|
555
|
+
"updated_at"
|
|
556
|
+
],
|
|
557
|
+
"metaschema_public.schema": [
|
|
558
|
+
"created_at",
|
|
559
|
+
"updated_at"
|
|
560
|
+
],
|
|
561
|
+
"metaschema_public.schema_grant": [
|
|
562
|
+
"created_at",
|
|
563
|
+
"updated_at"
|
|
564
|
+
],
|
|
565
|
+
"metaschema_public.spatial_relation": [
|
|
566
|
+
"created_at",
|
|
567
|
+
"updated_at"
|
|
568
|
+
],
|
|
569
|
+
"metaschema_public.table": [
|
|
570
|
+
"created_at",
|
|
571
|
+
"updated_at"
|
|
572
|
+
],
|
|
573
|
+
"metaschema_public.table_grant": [
|
|
574
|
+
"created_at",
|
|
575
|
+
"updated_at"
|
|
576
|
+
],
|
|
577
|
+
"metaschema_public.trigger": [
|
|
578
|
+
"created_at",
|
|
579
|
+
"updated_at"
|
|
580
|
+
],
|
|
581
|
+
"metaschema_public.trigger_function": [
|
|
582
|
+
"created_at",
|
|
583
|
+
"updated_at"
|
|
584
|
+
],
|
|
585
|
+
"metaschema_public.unique_constraint": [
|
|
586
|
+
"created_at",
|
|
587
|
+
"updated_at"
|
|
588
|
+
]
|
|
589
|
+
}
|
|
505
590
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgpmjs/export",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "PGPM export tools for SQL and GraphQL database migration extraction",
|
|
6
6
|
"main": "index.js",
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
"@pgsql/types": "^17.6.2",
|
|
42
42
|
"@types/pg": "^8.20.0",
|
|
43
43
|
"makage": "^0.3.0",
|
|
44
|
-
"pgsql-test": "^4.
|
|
44
|
+
"pgsql-test": "^4.19.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@pgpmjs/core": "^6.
|
|
48
|
-
"@pgpmjs/migrate-client": "^0.
|
|
49
|
-
"@pgpmjs/types": "^2.
|
|
50
|
-
"csv-to-pg": "^3.
|
|
47
|
+
"@pgpmjs/core": "^6.29.0",
|
|
48
|
+
"@pgpmjs/migrate-client": "^0.20.0",
|
|
49
|
+
"@pgpmjs/types": "^2.34.0",
|
|
50
|
+
"csv-to-pg": "^3.21.0",
|
|
51
51
|
"glob": "^13.0.6",
|
|
52
52
|
"inflekt": "^0.7.1",
|
|
53
53
|
"inquirerer": "^4.9.1",
|
|
54
54
|
"pg": "^8.21.0",
|
|
55
|
-
"pg-cache": "^3.
|
|
56
|
-
"pg-env": "^1.
|
|
55
|
+
"pg-cache": "^3.15.0",
|
|
56
|
+
"pg-env": "^1.18.0"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "7eb34a3baa10ba3476575967b87ff51b606e042a"
|
|
59
59
|
}
|