@pgpmjs/export 0.28.0 → 0.28.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.
@@ -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 that are marked as columnDefaults — their DDL DEFAULT (e.g.
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) {
@@ -1,39 +1,30 @@
1
1
  import { Parser } from 'csv-to-pg';
2
2
  import { getPgPool } from 'pg-cache';
3
- import { META_TABLE_CONFIG, META_TABLE_ORDER, mapPgTypeToFieldType } from './export-utils';
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 getTableColumns(pool, tableConfig.schema, tableConfig.table);
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, udtName] of actualColumns) {
36
- dynamicFields[columnName] = mapPgTypeToFieldType(udtName);
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 that are marked as columnDefaults — their DDL DEFAULT (e.g.
47
- // current_database()) will supply the correct value at deploy time, so the
48
- // exported INSERT must not hardcode an environment-specific literal.
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];
@@ -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
  }
@@ -60,7 +60,21 @@ const buildDynamicFieldsFromGraphQL = async (client, tableConfig) => {
60
60
  }
61
61
  }
62
62
  }
63
- // Omit columns that are marked as columnDefaults — their DDL DEFAULT (e.g.
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 getTableColumns(pool, tableConfig.schema, tableConfig.table);
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, udtName] of actualColumns) {
39
- dynamicFields[columnName] = (0, export_utils_1.mapPgTypeToFieldType)(udtName);
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 that are marked as columnDefaults — their DDL DEFAULT (e.g.
50
- // current_database()) will supply the correct value at deploy time, so the
51
- // exported INSERT must not hardcode an environment-specific literal.
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
  // =============================================================================
@@ -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.28.0",
3
+ "version": "0.28.1",
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,11 +41,11 @@
41
41
  "@pgsql/types": "^17.6.2",
42
42
  "@types/pg": "^8.20.0",
43
43
  "makage": "^0.3.0",
44
- "pgsql-test": "^4.18.6"
44
+ "pgsql-test": "^4.18.7"
45
45
  },
46
46
  "dependencies": {
47
- "@pgpmjs/core": "^6.28.1",
48
- "@pgpmjs/migrate-client": "^0.19.7",
47
+ "@pgpmjs/core": "^6.28.2",
48
+ "@pgpmjs/migrate-client": "^0.19.8",
49
49
  "@pgpmjs/types": "^2.33.1",
50
50
  "csv-to-pg": "^3.20.2",
51
51
  "glob": "^13.0.6",
@@ -55,5 +55,5 @@
55
55
  "pg-cache": "^3.14.3",
56
56
  "pg-env": "^1.17.1"
57
57
  },
58
- "gitHead": "2b5d597855ff00ff478fe0f6f311b6a6f892fb6b"
58
+ "gitHead": "113036fa4fb581e4d8418a9309524495a423b624"
59
59
  }