@memberjunction/codegen-lib 5.41.0 → 5.43.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/README.md +1 -1
- package/dist/Config/config.d.ts +132 -7
- package/dist/Config/config.d.ts.map +1 -1
- package/dist/Config/config.js +193 -15
- package/dist/Config/config.js.map +1 -1
- package/dist/Config/db-connection.d.ts +49 -7
- package/dist/Config/db-connection.d.ts.map +1 -1
- package/dist/Config/db-connection.js +87 -37
- package/dist/Config/db-connection.js.map +1 -1
- package/dist/Config/pg-connection.d.ts +58 -0
- package/dist/Config/pg-connection.d.ts.map +1 -0
- package/dist/Config/pg-connection.js +100 -0
- package/dist/Config/pg-connection.js.map +1 -0
- package/dist/Database/codeGenDatabaseProvider.d.ts +81 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts.map +1 -1
- package/dist/Database/codeGenDatabaseProvider.js +45 -0
- package/dist/Database/codeGenDatabaseProvider.js.map +1 -1
- package/dist/Database/manage-metadata.d.ts +26 -1
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +101 -2
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts +25 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js +80 -6
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/postgresql/metadataSupportObjects.d.ts +24 -0
- package/dist/Database/providers/postgresql/metadataSupportObjects.d.ts.map +1 -0
- package/dist/Database/providers/postgresql/metadataSupportObjects.js +650 -0
- package/dist/Database/providers/postgresql/metadataSupportObjects.js.map +1 -0
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts +13 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js +39 -3
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js.map +1 -1
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +12 -8
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Misc/action_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/action_subclasses_codegen.js +3 -1
- package/dist/Misc/action_subclasses_codegen.js.map +1 -1
- package/dist/Misc/remote_operations_codegen.d.ts +54 -0
- package/dist/Misc/remote_operations_codegen.d.ts.map +1 -0
- package/dist/Misc/remote_operations_codegen.js +186 -0
- package/dist/Misc/remote_operations_codegen.js.map +1 -0
- package/dist/Misc/runCommand.d.ts.map +1 -1
- package/dist/Misc/runCommand.js +8 -3
- package/dist/Misc/runCommand.js.map +1 -1
- package/dist/Misc/status_logging.d.ts +2 -0
- package/dist/Misc/status_logging.d.ts.map +1 -1
- package/dist/Misc/status_logging.js +12 -1
- package/dist/Misc/status_logging.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/index.d.ts +35 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +100 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/runCodeGen.d.ts +42 -25
- package/dist/runCodeGen.d.ts.map +1 -1
- package/dist/runCodeGen.js +140 -86
- package/dist/runCodeGen.js.map +1 -1
- package/package.json +32 -19
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DDL for CodeGen's PostgreSQL metadata-management support objects.
|
|
3
|
+
*
|
|
4
|
+
* These objects (the vwSQLColumnsAndEntityFields introspection view, the
|
|
5
|
+
* default-value helpers, and the five metadata-management routines that
|
|
6
|
+
* manage-metadata invokes via callRoutineSQL) are CodeGen's OWN machinery —
|
|
7
|
+
* only CodeGen calls them. Shipping them through migrations created a
|
|
8
|
+
* sync-by-convention dependency that failed in practice: four of the five
|
|
9
|
+
* routines never existed on PG and CodeGen silently degraded (stale
|
|
10
|
+
* EntityField metadata — e.g. the vwApplicationSettings INNER JOIN bug that
|
|
11
|
+
* hid NULL-ApplicationID rows).
|
|
12
|
+
*
|
|
13
|
+
* Instead, CodeGen ensures these objects itself at the start of every
|
|
14
|
+
* manageMetadata run (DROP IF EXISTS + CREATE OR REPLACE — idempotent,
|
|
15
|
+
* cheap). They can never be missing or version-skewed: they always match
|
|
16
|
+
* the CodeGenLib version that calls them. SQL Server is unaffected (its
|
|
17
|
+
* counterparts ship in the baseline migrations); see
|
|
18
|
+
* CodeGenDatabaseProvider.getMetadataSupportObjectsSQL.
|
|
19
|
+
*
|
|
20
|
+
* The DDL is authored as plain PostgreSQL against the literal __mj schema
|
|
21
|
+
* and parameterized at runtime; String.raw keeps regex backslashes intact.
|
|
22
|
+
*/
|
|
23
|
+
export function buildMetadataSupportObjectsSQL(mjCoreSchema) {
|
|
24
|
+
return METADATA_SUPPORT_OBJECTS_DDL.split('__mj').join(mjCoreSchema);
|
|
25
|
+
}
|
|
26
|
+
const METADATA_SUPPORT_OBJECTS_DDL = String.raw `
|
|
27
|
+
-- ----------------------------------------------------------------------------
|
|
28
|
+
-- 0. Drop the view first — it depends on fnMapPGDefaultToMJ, so on re-apply
|
|
29
|
+
-- the helper DROPs below would otherwise fail with a dependency error.
|
|
30
|
+
-- ----------------------------------------------------------------------------
|
|
31
|
+
DROP VIEW IF EXISTS __mj."vwSQLColumnsAndEntityFields";
|
|
32
|
+
|
|
33
|
+
-- ----------------------------------------------------------------------------
|
|
34
|
+
-- 1. Default-value helpers
|
|
35
|
+
-- ----------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
-- Normalizer used ONLY for change detection. Collapses formatting variance
|
|
38
|
+
-- (paren wrapping, N-prefix, ::casts, current-timestamp function family, uuid
|
|
39
|
+
-- generator family, numeric trailing zeros) so cosmetic differences never
|
|
40
|
+
-- trigger metadata updates. Both sides of every comparison pass through this,
|
|
41
|
+
-- so lossy transforms are safe.
|
|
42
|
+
DROP FUNCTION IF EXISTS __mj."fnNormalizeDefaultValue"(TEXT);
|
|
43
|
+
CREATE OR REPLACE FUNCTION __mj."fnNormalizeDefaultValue"(v TEXT)
|
|
44
|
+
RETURNS TEXT
|
|
45
|
+
LANGUAGE sql IMMUTABLE AS $$
|
|
46
|
+
SELECT CASE WHEN v IS NULL THEN NULL ELSE
|
|
47
|
+
regexp_replace( -- 1.0 / 0.000000 -> 1 / 0
|
|
48
|
+
translate( -- strip parens and quotes
|
|
49
|
+
regexp_replace( -- user-name family -> user
|
|
50
|
+
regexp_replace( -- timestamp family -> now
|
|
51
|
+
regexp_replace( -- uuid family -> newid
|
|
52
|
+
regexp_replace( -- N'x' -> 'x'
|
|
53
|
+
regexp_replace(lower(trim(v)), -- strip ::casts
|
|
54
|
+
'\s*::[a-z_ ]+(\([0-9, ]*\))?', '', 'g'),
|
|
55
|
+
'n''', '''', 'g'),
|
|
56
|
+
'(gen_random_uuid|uuid_generate_v4|newsequentialid|newid)\(\)', 'newid', 'g'),
|
|
57
|
+
'(now\(\)\s+at\s+time\s+zone\s+''utc''|getutcdate\(\)|getdate\(\)|sysdatetimeoffset\(\)|sysutcdatetime\(\)|current_timestamp|now\(\))', 'now', 'g'),
|
|
58
|
+
'(user_name\(\)|suser_name\(\)|suser_sname\(\)|current_user|session_user)', 'user', 'g'),
|
|
59
|
+
'()''', ''),
|
|
60
|
+
'^\s*(-?[0-9]+)\.0+\s*$', '\1')
|
|
61
|
+
END
|
|
62
|
+
$$;
|
|
63
|
+
|
|
64
|
+
-- Maps a pg_get_expr() default expression to MJ-canonical (SS-flavored) text
|
|
65
|
+
-- for storage/emission. Unmappable expressions pass through unchanged — the
|
|
66
|
+
-- normalizer above keeps them from churning metadata.
|
|
67
|
+
DROP FUNCTION IF EXISTS __mj."fnMapPGDefaultToMJ"(TEXT);
|
|
68
|
+
CREATE OR REPLACE FUNCTION __mj."fnMapPGDefaultToMJ"(v TEXT)
|
|
69
|
+
RETURNS TEXT
|
|
70
|
+
LANGUAGE sql IMMUTABLE AS $$
|
|
71
|
+
SELECT CASE
|
|
72
|
+
WHEN v IS NULL THEN NULL
|
|
73
|
+
WHEN v ~* 'now\(\)\s+at\s+time\s+zone\s+''utc''' THEN '(getutcdate())'
|
|
74
|
+
WHEN lower(trim(v)) IN ('now()', 'current_timestamp', 'transaction_timestamp()', 'statement_timestamp()') THEN '(sysdatetimeoffset())'
|
|
75
|
+
WHEN lower(trim(v)) IN ('gen_random_uuid()', 'uuid_generate_v4()') THEN '(newsequentialid())'
|
|
76
|
+
WHEN lower(trim(v)) = 'true' THEN '((1))'
|
|
77
|
+
WHEN lower(trim(v)) = 'false' THEN '((0))'
|
|
78
|
+
WHEN trim(v) ~ '^-?[0-9]+(\.[0-9]+)?$' THEN '((' || trim(v) || '))'
|
|
79
|
+
WHEN trim(v) ~* '^''[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}''::uuid$'
|
|
80
|
+
THEN '(''' || upper(substring(trim(v) from '^''(.*)''::')) || ''')'
|
|
81
|
+
WHEN trim(v) ~ '^''.*''::[a-z_ ]+(\([0-9, ]*\))?$'
|
|
82
|
+
THEN '(N''' || substring(trim(v) from '^''(.*)''::') || ''')'
|
|
83
|
+
ELSE v
|
|
84
|
+
END
|
|
85
|
+
$$;
|
|
86
|
+
|
|
87
|
+
-- ----------------------------------------------------------------------------
|
|
88
|
+
-- 2. Replace vwSQLColumnsAndEntityFields (column set changes: +IsComputed,
|
|
89
|
+
-- Type becomes text) — no dependent views exist on this view.
|
|
90
|
+
-- (dropped in section 0)
|
|
91
|
+
-- ----------------------------------------------------------------------------
|
|
92
|
+
CREATE VIEW __mj."vwSQLColumnsAndEntityFields" AS
|
|
93
|
+
SELECT
|
|
94
|
+
e."EntityID",
|
|
95
|
+
e."EntityName" AS "Entity",
|
|
96
|
+
e."SchemaName",
|
|
97
|
+
e."TableName",
|
|
98
|
+
ef."ID" AS "EntityFieldID",
|
|
99
|
+
ef."Sequence" AS "EntityFieldSequence",
|
|
100
|
+
ef."Name" AS "EntityFieldName",
|
|
101
|
+
a.attnum AS "Sequence",
|
|
102
|
+
bt_a.attnum AS "BaseTableSequence",
|
|
103
|
+
a.attname AS "FieldName",
|
|
104
|
+
-- MJ-canonical type vocabulary (matches EntityField.Type, which is shared
|
|
105
|
+
-- with SQL Server installs). Unknown PG types pass through.
|
|
106
|
+
CASE COALESCE(base_t.typname, t.typname)
|
|
107
|
+
WHEN 'varchar' THEN 'nvarchar'
|
|
108
|
+
WHEN 'text' THEN 'nvarchar'
|
|
109
|
+
WHEN 'bpchar' THEN 'nchar'
|
|
110
|
+
WHEN 'char' THEN 'nchar'
|
|
111
|
+
WHEN 'uuid' THEN 'uniqueidentifier'
|
|
112
|
+
WHEN 'bool' THEN 'bit'
|
|
113
|
+
WHEN 'timestamptz' THEN 'datetimeoffset'
|
|
114
|
+
WHEN 'timestamp' THEN 'datetime'
|
|
115
|
+
WHEN 'int4' THEN 'int'
|
|
116
|
+
WHEN 'int2' THEN 'smallint'
|
|
117
|
+
WHEN 'int8' THEN 'bigint'
|
|
118
|
+
WHEN 'numeric' THEN 'decimal'
|
|
119
|
+
WHEN 'float8' THEN 'float'
|
|
120
|
+
WHEN 'float4' THEN 'real'
|
|
121
|
+
WHEN 'bytea' THEN 'varbinary'
|
|
122
|
+
WHEN 'jsonb' THEN 'nvarchar'
|
|
123
|
+
WHEN 'json' THEN 'nvarchar'
|
|
124
|
+
ELSE COALESCE(base_t.typname, t.typname)::text
|
|
125
|
+
END AS "Type",
|
|
126
|
+
CASE WHEN t.typtype = 'd' THEN t.typname::text ELSE NULL END AS "UserDefinedType",
|
|
127
|
+
-- SS sys.columns max_length semantics: bytes (2x chars for n(var)char),
|
|
128
|
+
-- -1 for MAX/unbounded, decimal storage bytes by precision band.
|
|
129
|
+
CASE
|
|
130
|
+
WHEN COALESCE(base_t.typname, t.typname) IN ('varchar', 'bpchar', 'char') THEN
|
|
131
|
+
CASE WHEN a.atttypmod = -1 THEN -1 ELSE (a.atttypmod - 4) * 2 END
|
|
132
|
+
WHEN COALESCE(base_t.typname, t.typname) IN ('text', 'bytea', 'jsonb', 'json') THEN -1
|
|
133
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'uuid' THEN 16
|
|
134
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'bool' THEN 1
|
|
135
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamptz' THEN 10
|
|
136
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamp' THEN 8
|
|
137
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'numeric' THEN
|
|
138
|
+
CASE
|
|
139
|
+
WHEN a.atttypmod = -1 THEN 17
|
|
140
|
+
WHEN (((a.atttypmod - 4) >> 16) & 65535) <= 9 THEN 5
|
|
141
|
+
WHEN (((a.atttypmod - 4) >> 16) & 65535) <= 19 THEN 9
|
|
142
|
+
WHEN (((a.atttypmod - 4) >> 16) & 65535) <= 28 THEN 13
|
|
143
|
+
ELSE 17
|
|
144
|
+
END
|
|
145
|
+
ELSE a.attlen::integer
|
|
146
|
+
END AS "Length",
|
|
147
|
+
CASE
|
|
148
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'numeric' AND a.atttypmod <> -1 THEN ((a.atttypmod - 4) >> 16) & 65535
|
|
149
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'numeric' THEN 38
|
|
150
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'int4' THEN 10
|
|
151
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'int2' THEN 5
|
|
152
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'int8' THEN 19
|
|
153
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamptz' THEN 34
|
|
154
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamp' THEN 23
|
|
155
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'bool' THEN 1
|
|
156
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'float8' THEN 53
|
|
157
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'float4' THEN 24
|
|
158
|
+
ELSE 0
|
|
159
|
+
END AS "Precision",
|
|
160
|
+
CASE
|
|
161
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'numeric' AND a.atttypmod <> -1 THEN (a.atttypmod - 4) & 65535
|
|
162
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamptz' THEN 7
|
|
163
|
+
WHEN COALESCE(base_t.typname, t.typname) = 'timestamp' THEN 3
|
|
164
|
+
ELSE 0
|
|
165
|
+
END AS "Scale",
|
|
166
|
+
-- Nullability must come from the BASE TABLE attribute when one exists: PG
|
|
167
|
+
-- view columns never carry NOT NULL, which is exactly the bug the previous
|
|
168
|
+
-- definition had. Virtual (view-only) fields fall back to the view attr.
|
|
169
|
+
CASE WHEN bt_a.attnum IS NOT NULL THEN NOT bt_a.attnotnull ELSE NOT a.attnotnull END AS "AllowsNull",
|
|
170
|
+
CASE WHEN COALESCE(bt_a.attidentity, '') IN ('a', 'd') THEN 1 ELSE 0 END AS "AutoIncrement",
|
|
171
|
+
a.attnum AS column_id,
|
|
172
|
+
CASE WHEN bt_a.attnum IS NULL THEN 1 ELSE 0 END AS "IsVirtual",
|
|
173
|
+
CASE WHEN COALESCE(bt_a.attgenerated, '') <> '' THEN 1 ELSE 0 END AS "IsComputed",
|
|
174
|
+
src_cls.oid AS object_id,
|
|
175
|
+
NULL::text AS "DefaultConstraintName",
|
|
176
|
+
__mj."fnMapPGDefaultToMJ"(pg_get_expr(ad.adbin, ad.adrelid)) AS "DefaultValue",
|
|
177
|
+
CASE WHEN COALESCE(bt_a.attgenerated, '') <> '' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE NULL END AS "ComputedColumnDefinition",
|
|
178
|
+
COALESCE(col_description(src_cls.oid, a.attnum::integer), col_description(bt_cls.oid, bt_a.attnum::integer)) AS "Description",
|
|
179
|
+
col_description(src_cls.oid, a.attnum::integer) AS "ViewColumnDescription",
|
|
180
|
+
CASE WHEN bt_a.attnum IS NOT NULL THEN col_description(bt_cls.oid, bt_a.attnum::integer) ELSE NULL END AS "TableColumnDescription"
|
|
181
|
+
FROM __mj."vwSQLTablesAndEntities" e
|
|
182
|
+
JOIN pg_class src_cls ON src_cls.oid = COALESCE(e.view_object_id, e.object_id)
|
|
183
|
+
JOIN pg_attribute a ON a.attrelid = src_cls.oid AND a.attnum > 0 AND NOT a.attisdropped
|
|
184
|
+
JOIN pg_type t ON a.atttypid = t.oid
|
|
185
|
+
LEFT JOIN pg_type base_t ON t.typbasetype = base_t.oid AND t.typtype = 'd'
|
|
186
|
+
JOIN pg_class bt_cls ON bt_cls.oid = e.object_id
|
|
187
|
+
LEFT JOIN pg_attribute bt_a ON bt_a.attrelid = bt_cls.oid AND bt_a.attname = a.attname AND bt_a.attnum > 0 AND NOT bt_a.attisdropped
|
|
188
|
+
LEFT JOIN pg_attrdef ad ON ad.adrelid = bt_cls.oid AND ad.adnum = bt_a.attnum
|
|
189
|
+
LEFT JOIN __mj."EntityField" ef ON e."EntityID" = ef."EntityID" AND a.attname = ef."Name"::text;
|
|
190
|
+
|
|
191
|
+
-- ----------------------------------------------------------------------------
|
|
192
|
+
-- 3. spUpdateExistingEntityFieldsFromSchema
|
|
193
|
+
-- (port of the SQL Server proc of the same name; consumed by CodeGen's
|
|
194
|
+
-- manage-metadata step 3 which reads "EntityName" from the result rows)
|
|
195
|
+
-- ----------------------------------------------------------------------------
|
|
196
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateExistingEntityFieldsFromSchema"(TEXT);
|
|
197
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateExistingEntityFieldsFromSchema"(TEXT, TEXT);
|
|
198
|
+
CREATE OR REPLACE FUNCTION __mj."spUpdateExistingEntityFieldsFromSchema"(
|
|
199
|
+
p_ExcludedSchemaNames TEXT,
|
|
200
|
+
p_EntityIDs TEXT DEFAULT NULL
|
|
201
|
+
)
|
|
202
|
+
RETURNS TABLE(
|
|
203
|
+
"EntityID" UUID,
|
|
204
|
+
"EntityName" TEXT,
|
|
205
|
+
"EntityFieldID" UUID,
|
|
206
|
+
"EntityFieldName" TEXT,
|
|
207
|
+
"AutoUpdateDescription" BOOLEAN,
|
|
208
|
+
"ExistingDescription" TEXT,
|
|
209
|
+
"SQLDescription" TEXT,
|
|
210
|
+
"Type" TEXT,
|
|
211
|
+
"Length" INTEGER,
|
|
212
|
+
"Precision" INTEGER,
|
|
213
|
+
"Scale" INTEGER,
|
|
214
|
+
"AllowsNull" BOOLEAN,
|
|
215
|
+
"DefaultValue" TEXT,
|
|
216
|
+
"AutoIncrement" BOOLEAN,
|
|
217
|
+
"IsVirtual" BOOLEAN,
|
|
218
|
+
"IsComputed" BOOLEAN,
|
|
219
|
+
"Sequence" INTEGER,
|
|
220
|
+
"RelatedEntityID" UUID,
|
|
221
|
+
"RelatedEntityFieldName" TEXT,
|
|
222
|
+
"IsPrimaryKey" BOOLEAN,
|
|
223
|
+
"IsUnique" BOOLEAN
|
|
224
|
+
)
|
|
225
|
+
LANGUAGE plpgsql AS $func$
|
|
226
|
+
DECLARE
|
|
227
|
+
v_is_scoped BOOLEAN := FALSE;
|
|
228
|
+
BEGIN
|
|
229
|
+
DROP TABLE IF EXISTS _uef_excluded;
|
|
230
|
+
CREATE TEMP TABLE _uef_excluded AS
|
|
231
|
+
SELECT TRIM(s) AS schema_name
|
|
232
|
+
FROM unnest(string_to_array(COALESCE(p_ExcludedSchemaNames, ''), ',')) AS s
|
|
233
|
+
WHERE TRIM(s) <> '';
|
|
234
|
+
|
|
235
|
+
DROP TABLE IF EXISTS _uef_scope;
|
|
236
|
+
CREATE TEMP TABLE _uef_scope AS
|
|
237
|
+
SELECT DISTINCT TRIM(v)::uuid AS entity_id
|
|
238
|
+
FROM unnest(string_to_array(COALESCE(p_EntityIDs, ''), ',')) AS v
|
|
239
|
+
WHERE TRIM(v) ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';
|
|
240
|
+
v_is_scoped := EXISTS (SELECT 1 FROM _uef_scope);
|
|
241
|
+
|
|
242
|
+
DROP TABLE IF EXISTS _uef_filtered;
|
|
243
|
+
CREATE TEMP TABLE _uef_filtered AS
|
|
244
|
+
SELECT
|
|
245
|
+
e."ID" AS entity_id,
|
|
246
|
+
e."Name" AS entity_name,
|
|
247
|
+
ef."ID" AS entity_field_id,
|
|
248
|
+
ef."Name" AS entity_field_name,
|
|
249
|
+
ef."AutoUpdateDescription" AS auto_update_description,
|
|
250
|
+
ef."Description" AS existing_description,
|
|
251
|
+
sq."Description" AS sql_description,
|
|
252
|
+
-- numeric/decimal are SS synonyms — keep whichever the metadata already has
|
|
253
|
+
CASE WHEN ef."Type" = 'numeric' AND sq."Type" = 'decimal' THEN ef."Type" ELSE sq."Type" END AS new_type,
|
|
254
|
+
sq."Length" AS new_length,
|
|
255
|
+
sq."Precision" AS new_precision,
|
|
256
|
+
sq."Scale" AS new_scale,
|
|
257
|
+
sq."AllowsNull" AS new_allows_null,
|
|
258
|
+
-- only rewrite a stored default when it differs SEMANTICALLY
|
|
259
|
+
CASE WHEN __mj."fnNormalizeDefaultValue"(ef."DefaultValue") IS NOT DISTINCT FROM __mj."fnNormalizeDefaultValue"(sq."DefaultValue")
|
|
260
|
+
THEN ef."DefaultValue" ELSE sq."DefaultValue" END AS new_default_value,
|
|
261
|
+
(sq."AutoIncrement" <> 0) AS new_auto_increment,
|
|
262
|
+
(sq."IsVirtual" <> 0) AS new_is_virtual,
|
|
263
|
+
(sq."IsComputed" <> 0) AS new_is_computed,
|
|
264
|
+
sq."Sequence" AS new_sequence,
|
|
265
|
+
re."ID" AS related_entity_id,
|
|
266
|
+
fk."referenced_column"::text AS related_entity_field_name,
|
|
267
|
+
(pk."ColumnName" IS NOT NULL) AS new_is_primary_key,
|
|
268
|
+
(pk."ColumnName" IS NOT NULL OR uk."ColumnName" IS NOT NULL) AS new_is_unique
|
|
269
|
+
FROM __mj."EntityField" ef
|
|
270
|
+
INNER JOIN __mj."vwSQLColumnsAndEntityFields" sq
|
|
271
|
+
ON ef."EntityID" = sq."EntityID" AND ef."Name"::text = sq."FieldName"::text
|
|
272
|
+
INNER JOIN __mj."Entity" e ON ef."EntityID" = e."ID"
|
|
273
|
+
LEFT JOIN __mj."vwForeignKeys" fk
|
|
274
|
+
ON ef."Name"::text = fk."column"::text AND e."BaseTable"::text = fk."table"::text AND e."SchemaName"::text = fk."schema_name"::text
|
|
275
|
+
LEFT JOIN __mj."Entity" re
|
|
276
|
+
ON re."BaseTable"::text = fk."referenced_table"::text AND re."SchemaName"::text = fk."referenced_schema"::text
|
|
277
|
+
LEFT JOIN __mj."vwTablePrimaryKeys" pk
|
|
278
|
+
ON e."BaseTable"::text = pk."TableName"::text AND ef."Name"::text = pk."ColumnName"::text AND e."SchemaName"::text = pk."SchemaName"::text
|
|
279
|
+
LEFT JOIN __mj."vwTableUniqueKeys" uk
|
|
280
|
+
ON e."BaseTable"::text = uk."TableName"::text AND ef."Name"::text = uk."ColumnName"::text AND e."SchemaName"::text = uk."SchemaName"::text
|
|
281
|
+
LEFT JOIN _uef_excluded ex ON e."SchemaName"::text = ex.schema_name
|
|
282
|
+
WHERE e."VirtualEntity" = FALSE
|
|
283
|
+
AND ex.schema_name IS NULL
|
|
284
|
+
AND (NOT v_is_scoped OR e."ID" IN (SELECT s.entity_id FROM _uef_scope s))
|
|
285
|
+
AND (
|
|
286
|
+
COALESCE(TRIM(ef."Description"), '') <>
|
|
287
|
+
COALESCE(TRIM(CASE WHEN ef."AutoUpdateDescription" THEN sq."Description" ELSE ef."Description" END), '')
|
|
288
|
+
-- Physical attributes are only compared for REAL columns. PG cannot
|
|
289
|
+
-- derive type facts for view-only (virtual) columns the way SQL Server
|
|
290
|
+
-- can (view columns are unbounded/nullable in pg_attribute), so virtual
|
|
291
|
+
-- fields keep their metadata values; the CodeGen TS pipeline's
|
|
292
|
+
-- getFixVirtualFieldNullabilitySQL step owns virtual-field nullability.
|
|
293
|
+
OR (sq."IsVirtual" = 0 AND (
|
|
294
|
+
(ef."Type" <> sq."Type" AND NOT (ef."Type" = 'numeric' AND sq."Type" = 'decimal'))
|
|
295
|
+
OR ef."Length" <> sq."Length"
|
|
296
|
+
OR ef."Precision" <> sq."Precision"
|
|
297
|
+
OR ef."Scale" <> sq."Scale"
|
|
298
|
+
OR ef."AllowsNull" <> sq."AllowsNull"
|
|
299
|
+
))
|
|
300
|
+
OR __mj."fnNormalizeDefaultValue"(ef."DefaultValue") IS DISTINCT FROM __mj."fnNormalizeDefaultValue"(sq."DefaultValue")
|
|
301
|
+
OR ef."AutoIncrement" <> (sq."AutoIncrement" <> 0)
|
|
302
|
+
OR ef."IsVirtual" <> (sq."IsVirtual" <> 0)
|
|
303
|
+
OR ef."IsComputed" <> (sq."IsComputed" <> 0)
|
|
304
|
+
OR ef."Sequence" <> sq."Sequence"
|
|
305
|
+
OR COALESCE(ef."RelatedEntityID", '00000000-0000-0000-0000-000000000000'::uuid) <>
|
|
306
|
+
COALESCE(re."ID", '00000000-0000-0000-0000-000000000000'::uuid)
|
|
307
|
+
OR COALESCE(TRIM(ef."RelatedEntityFieldName"), '') <> COALESCE(TRIM(fk."referenced_column"::text), '')
|
|
308
|
+
OR ef."IsPrimaryKey" <> (pk."ColumnName" IS NOT NULL)
|
|
309
|
+
OR ef."IsUnique" <> (pk."ColumnName" IS NOT NULL OR uk."ColumnName" IS NOT NULL)
|
|
310
|
+
-- AllowUpdateAPI needs clearing on a real->virtual transition
|
|
311
|
+
OR (ef."AllowUpdateAPI" = TRUE AND sq."IsVirtual" <> 0 AND ef."IsVirtual" = FALSE)
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
-- PG checks UNIQUE row-by-row (SQL Server checks at statement end), so an
|
|
315
|
+
-- in-place renumber can transiently collide on UQ_EntityField_EntityID_Sequence.
|
|
316
|
+
-- Park changing sequences in a collision-free zone first; the real values are
|
|
317
|
+
-- assigned by the main UPDATE below.
|
|
318
|
+
UPDATE __mj."EntityField" tgt SET
|
|
319
|
+
"Sequence" = tgt."Sequence" + 1000000
|
|
320
|
+
FROM _uef_filtered fr
|
|
321
|
+
WHERE tgt."ID" = fr.entity_field_id
|
|
322
|
+
AND tgt."Sequence" IS DISTINCT FROM fr.new_sequence;
|
|
323
|
+
|
|
324
|
+
UPDATE __mj."EntityField" tgt SET
|
|
325
|
+
"Description" = CASE WHEN fr.auto_update_description THEN fr.sql_description ELSE tgt."Description" END,
|
|
326
|
+
-- physical attributes frozen for virtual fields (see WHERE clause comment)
|
|
327
|
+
"Type" = CASE WHEN fr.new_is_virtual THEN tgt."Type" ELSE fr.new_type END,
|
|
328
|
+
"Length" = CASE WHEN fr.new_is_virtual THEN tgt."Length" ELSE fr.new_length END,
|
|
329
|
+
"Precision" = CASE WHEN fr.new_is_virtual THEN tgt."Precision" ELSE fr.new_precision END,
|
|
330
|
+
"Scale" = CASE WHEN fr.new_is_virtual THEN tgt."Scale" ELSE fr.new_scale END,
|
|
331
|
+
"AllowsNull" = CASE WHEN fr.new_is_virtual THEN tgt."AllowsNull" ELSE fr.new_allows_null END,
|
|
332
|
+
"DefaultValue" = fr.new_default_value,
|
|
333
|
+
"AutoIncrement" = fr.new_auto_increment,
|
|
334
|
+
"IsVirtual" = fr.new_is_virtual,
|
|
335
|
+
"IsComputed" = fr.new_is_computed,
|
|
336
|
+
"Sequence" = fr.new_sequence,
|
|
337
|
+
"RelatedEntityID" = CASE WHEN tgt."AutoUpdateRelatedEntityInfo" THEN fr.related_entity_id ELSE tgt."RelatedEntityID" END,
|
|
338
|
+
"RelatedEntityFieldName" = CASE WHEN tgt."AutoUpdateRelatedEntityInfo" THEN fr.related_entity_field_name ELSE tgt."RelatedEntityFieldName" END,
|
|
339
|
+
"IsPrimaryKey" = fr.new_is_primary_key,
|
|
340
|
+
"IsUnique" = fr.new_is_unique,
|
|
341
|
+
-- when a field transitions to virtual it can no longer be written to
|
|
342
|
+
"AllowUpdateAPI" = CASE WHEN fr.new_is_virtual AND NOT tgt."IsVirtual" THEN FALSE ELSE tgt."AllowUpdateAPI" END,
|
|
343
|
+
"__mj_UpdatedAt" = now()
|
|
344
|
+
FROM _uef_filtered fr
|
|
345
|
+
WHERE tgt."ID" = fr.entity_field_id;
|
|
346
|
+
|
|
347
|
+
RETURN QUERY
|
|
348
|
+
SELECT
|
|
349
|
+
fr.entity_id, fr.entity_name::text, fr.entity_field_id, fr.entity_field_name::text,
|
|
350
|
+
fr.auto_update_description, fr.existing_description::text, fr.sql_description::text,
|
|
351
|
+
fr.new_type::text, fr.new_length::integer, fr.new_precision::integer, fr.new_scale::integer,
|
|
352
|
+
fr.new_allows_null, fr.new_default_value::text, fr.new_auto_increment,
|
|
353
|
+
fr.new_is_virtual, fr.new_is_computed, fr.new_sequence::integer,
|
|
354
|
+
fr.related_entity_id, fr.related_entity_field_name::text,
|
|
355
|
+
fr.new_is_primary_key, fr.new_is_unique
|
|
356
|
+
FROM _uef_filtered fr;
|
|
357
|
+
|
|
358
|
+
DROP TABLE IF EXISTS _uef_filtered;
|
|
359
|
+
DROP TABLE IF EXISTS _uef_scope;
|
|
360
|
+
DROP TABLE IF EXISTS _uef_excluded;
|
|
361
|
+
END;
|
|
362
|
+
$func$;
|
|
363
|
+
|
|
364
|
+
-- ----------------------------------------------------------------------------
|
|
365
|
+
-- 4. spUpdateExistingEntitiesFromSchema
|
|
366
|
+
-- (consumer reads "Name" from result rows)
|
|
367
|
+
-- ----------------------------------------------------------------------------
|
|
368
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateExistingEntitiesFromSchema"(TEXT);
|
|
369
|
+
CREATE OR REPLACE FUNCTION __mj."spUpdateExistingEntitiesFromSchema"(p_ExcludedSchemaNames TEXT)
|
|
370
|
+
RETURNS TABLE(
|
|
371
|
+
"ID" UUID,
|
|
372
|
+
"Name" TEXT,
|
|
373
|
+
"CurrentDescription" TEXT,
|
|
374
|
+
"NewDescription" TEXT,
|
|
375
|
+
"EntityDescription" TEXT,
|
|
376
|
+
"SchemaName" TEXT
|
|
377
|
+
)
|
|
378
|
+
LANGUAGE plpgsql AS $func$
|
|
379
|
+
BEGIN
|
|
380
|
+
DROP TABLE IF EXISTS _ues_filtered;
|
|
381
|
+
CREATE TEMP TABLE _ues_filtered AS
|
|
382
|
+
SELECT
|
|
383
|
+
e."ID" AS entity_id,
|
|
384
|
+
e."Name" AS entity_name,
|
|
385
|
+
e."Description" AS current_description,
|
|
386
|
+
CASE WHEN e."AutoUpdateDescription" THEN sq."EntityDescription" ELSE e."Description" END AS new_description,
|
|
387
|
+
sq."EntityDescription" AS entity_description,
|
|
388
|
+
sq."SchemaName"::text AS schema_name
|
|
389
|
+
FROM __mj."Entity" e
|
|
390
|
+
INNER JOIN __mj."vwSQLTablesAndEntities" sq ON e."ID" = sq."EntityID"
|
|
391
|
+
LEFT JOIN unnest(string_to_array(COALESCE(p_ExcludedSchemaNames, ''), ',')) AS ex(v)
|
|
392
|
+
ON sq."SchemaName"::text = TRIM(ex.v)
|
|
393
|
+
WHERE e."VirtualEntity" = FALSE
|
|
394
|
+
AND ex.v IS NULL
|
|
395
|
+
AND COALESCE(CASE WHEN e."AutoUpdateDescription" THEN sq."EntityDescription" ELSE e."Description" END, '')
|
|
396
|
+
<> COALESCE(e."Description", '');
|
|
397
|
+
|
|
398
|
+
UPDATE __mj."Entity" tgt SET
|
|
399
|
+
"Description" = fr.new_description,
|
|
400
|
+
"__mj_UpdatedAt" = now()
|
|
401
|
+
FROM _ues_filtered fr
|
|
402
|
+
WHERE tgt."ID" = fr.entity_id;
|
|
403
|
+
|
|
404
|
+
RETURN QUERY
|
|
405
|
+
SELECT fr.entity_id, fr.entity_name::text, fr.current_description::text,
|
|
406
|
+
fr.new_description::text, fr.entity_description::text, fr.schema_name
|
|
407
|
+
FROM _ues_filtered fr;
|
|
408
|
+
|
|
409
|
+
DROP TABLE IF EXISTS _ues_filtered;
|
|
410
|
+
END;
|
|
411
|
+
$func$;
|
|
412
|
+
|
|
413
|
+
-- ----------------------------------------------------------------------------
|
|
414
|
+
-- 5. spDeleteUnneededEntityFields
|
|
415
|
+
-- Removes EntityField rows whose underlying column no longer exists.
|
|
416
|
+
-- (consumer reads "Entity" — the entity name — from result rows; the SS
|
|
417
|
+
-- version returns the full vwEntityFields row, but only "Entity" is used)
|
|
418
|
+
-- ----------------------------------------------------------------------------
|
|
419
|
+
DROP FUNCTION IF EXISTS __mj."spDeleteUnneededEntityFields"(TEXT);
|
|
420
|
+
DROP FUNCTION IF EXISTS __mj."spDeleteUnneededEntityFields"(TEXT, TEXT);
|
|
421
|
+
CREATE OR REPLACE FUNCTION __mj."spDeleteUnneededEntityFields"(
|
|
422
|
+
p_ExcludedSchemaNames TEXT,
|
|
423
|
+
p_EntityIDs TEXT DEFAULT NULL
|
|
424
|
+
)
|
|
425
|
+
RETURNS TABLE(
|
|
426
|
+
"ID" UUID,
|
|
427
|
+
"EntityID" UUID,
|
|
428
|
+
"Entity" TEXT,
|
|
429
|
+
"Name" TEXT
|
|
430
|
+
)
|
|
431
|
+
LANGUAGE plpgsql AS $func$
|
|
432
|
+
DECLARE
|
|
433
|
+
v_is_scoped BOOLEAN := FALSE;
|
|
434
|
+
BEGIN
|
|
435
|
+
DROP TABLE IF EXISTS _del_scope;
|
|
436
|
+
CREATE TEMP TABLE _del_scope AS
|
|
437
|
+
SELECT DISTINCT TRIM(v)::uuid AS entity_id
|
|
438
|
+
FROM unnest(string_to_array(COALESCE(p_EntityIDs, ''), ',')) AS v
|
|
439
|
+
WHERE TRIM(v) ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';
|
|
440
|
+
v_is_scoped := EXISTS (SELECT 1 FROM _del_scope);
|
|
441
|
+
|
|
442
|
+
-- metadata-side fields for in-scope, non-virtual entities
|
|
443
|
+
DROP TABLE IF EXISTS _del_ef;
|
|
444
|
+
CREATE TEMP TABLE _del_ef AS
|
|
445
|
+
SELECT ef."ID" AS field_id, ef."EntityID" AS entity_id, ef."Entity"::text AS entity_name, ef."Name"::text AS field_name
|
|
446
|
+
FROM __mj."vwEntityFields" ef
|
|
447
|
+
INNER JOIN __mj."vwEntities" e ON ef."EntityID" = e."ID"
|
|
448
|
+
LEFT JOIN unnest(string_to_array(COALESCE(p_ExcludedSchemaNames, ''), ',')) AS ex(v)
|
|
449
|
+
ON e."SchemaName"::text = TRIM(ex.v)
|
|
450
|
+
WHERE e."VirtualEntity" = FALSE
|
|
451
|
+
AND ex.v IS NULL
|
|
452
|
+
AND (NOT v_is_scoped OR ef."EntityID" IN (SELECT s.entity_id FROM _del_scope s));
|
|
453
|
+
|
|
454
|
+
-- actual columns present in the database
|
|
455
|
+
DROP TABLE IF EXISTS _del_actual;
|
|
456
|
+
CREATE TEMP TABLE _del_actual AS
|
|
457
|
+
SELECT sq."EntityID" AS entity_id, sq."FieldName"::text AS field_name
|
|
458
|
+
FROM __mj."vwSQLColumnsAndEntityFields" sq
|
|
459
|
+
WHERE (NOT v_is_scoped OR sq."EntityID" IN (SELECT s.entity_id FROM _del_scope s));
|
|
460
|
+
|
|
461
|
+
-- orphans: metadata field with no matching DB column
|
|
462
|
+
DROP TABLE IF EXISTS _del_deleted;
|
|
463
|
+
CREATE TEMP TABLE _del_deleted AS
|
|
464
|
+
SELECT ef.field_id, ef.entity_id, ef.entity_name, ef.field_name
|
|
465
|
+
FROM _del_ef ef
|
|
466
|
+
LEFT JOIN _del_actual actual
|
|
467
|
+
ON ef.entity_id = actual.entity_id AND ef.field_name = actual.field_name
|
|
468
|
+
WHERE actual.field_name IS NULL;
|
|
469
|
+
|
|
470
|
+
UPDATE __mj."Entity" ent SET "__mj_UpdatedAt" = now()
|
|
471
|
+
WHERE ent."ID" IN (SELECT DISTINCT d.entity_id FROM _del_deleted d);
|
|
472
|
+
|
|
473
|
+
DELETE FROM __mj."EntityFieldValue" efv
|
|
474
|
+
WHERE efv."EntityFieldID" IN (SELECT d.field_id FROM _del_deleted d);
|
|
475
|
+
|
|
476
|
+
DELETE FROM __mj."EntityField" delf
|
|
477
|
+
WHERE delf."ID" IN (SELECT d.field_id FROM _del_deleted d);
|
|
478
|
+
|
|
479
|
+
RETURN QUERY
|
|
480
|
+
SELECT d.field_id, d.entity_id, d.entity_name, d.field_name FROM _del_deleted d;
|
|
481
|
+
|
|
482
|
+
DROP TABLE IF EXISTS _del_deleted;
|
|
483
|
+
DROP TABLE IF EXISTS _del_actual;
|
|
484
|
+
DROP TABLE IF EXISTS _del_ef;
|
|
485
|
+
DROP TABLE IF EXISTS _del_scope;
|
|
486
|
+
END;
|
|
487
|
+
$func$;
|
|
488
|
+
|
|
489
|
+
-- ----------------------------------------------------------------------------
|
|
490
|
+
-- 6. spSetDefaultColumnWidthWhereNeeded
|
|
491
|
+
-- ----------------------------------------------------------------------------
|
|
492
|
+
DROP FUNCTION IF EXISTS __mj."spSetDefaultColumnWidthWhereNeeded"(TEXT);
|
|
493
|
+
CREATE OR REPLACE FUNCTION __mj."spSetDefaultColumnWidthWhereNeeded"(p_ExcludedSchemaNames TEXT)
|
|
494
|
+
RETURNS void
|
|
495
|
+
LANGUAGE plpgsql AS $func$
|
|
496
|
+
BEGIN
|
|
497
|
+
UPDATE __mj."EntityField" ef SET
|
|
498
|
+
"DefaultColumnWidth" =
|
|
499
|
+
CASE ef."Type"
|
|
500
|
+
WHEN 'int' THEN 50
|
|
501
|
+
WHEN 'datetimeoffset' THEN 100
|
|
502
|
+
WHEN 'money' THEN 100
|
|
503
|
+
WHEN 'nchar' THEN 75
|
|
504
|
+
ELSE 150
|
|
505
|
+
END,
|
|
506
|
+
"__mj_UpdatedAt" = now()
|
|
507
|
+
FROM __mj."Entity" e
|
|
508
|
+
LEFT JOIN unnest(string_to_array(COALESCE(p_ExcludedSchemaNames, ''), ',')) AS ex(v)
|
|
509
|
+
ON e."SchemaName"::text = TRIM(ex.v)
|
|
510
|
+
WHERE ef."EntityID" = e."ID"
|
|
511
|
+
AND ef."DefaultColumnWidth" IS NULL
|
|
512
|
+
AND ex.v IS NULL;
|
|
513
|
+
END;
|
|
514
|
+
$func$;
|
|
515
|
+
|
|
516
|
+
-- ----------------------------------------------------------------------------
|
|
517
|
+
-- 7. spUpdateSchemaInfoFromDatabase
|
|
518
|
+
-- (consumer caches the returned SchemaInfo rows)
|
|
519
|
+
-- ----------------------------------------------------------------------------
|
|
520
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateSchemaInfoFromDatabase"(TEXT);
|
|
521
|
+
CREATE OR REPLACE FUNCTION __mj."spUpdateSchemaInfoFromDatabase"(p_ExcludedSchemaNames TEXT DEFAULT NULL)
|
|
522
|
+
RETURNS SETOF __mj."SchemaInfo"
|
|
523
|
+
LANGUAGE plpgsql AS $func$
|
|
524
|
+
BEGIN
|
|
525
|
+
DROP TABLE IF EXISTS _usi_excluded;
|
|
526
|
+
CREATE TEMP TABLE _usi_excluded AS
|
|
527
|
+
SELECT TRIM(s) AS schema_name
|
|
528
|
+
FROM unnest(string_to_array(COALESCE(p_ExcludedSchemaNames, ''), ',')) AS s
|
|
529
|
+
WHERE TRIM(s) <> '';
|
|
530
|
+
|
|
531
|
+
UPDATE __mj."SchemaInfo" si SET
|
|
532
|
+
"Description" = ss."SchemaDescription",
|
|
533
|
+
"__mj_UpdatedAt" = now()
|
|
534
|
+
FROM __mj."vwSQLSchemas" ss
|
|
535
|
+
WHERE si."SchemaName" = ss."SchemaName"
|
|
536
|
+
AND (si."Description" IS NULL OR si."Description" <> COALESCE(ss."SchemaDescription", ''))
|
|
537
|
+
AND ss."SchemaName" NOT IN (SELECT x.schema_name FROM _usi_excluded x);
|
|
538
|
+
|
|
539
|
+
INSERT INTO __mj."SchemaInfo" ("SchemaName", "EntityIDMin", "EntityIDMax", "Comments", "Description")
|
|
540
|
+
SELECT
|
|
541
|
+
ss."SchemaName",
|
|
542
|
+
1,
|
|
543
|
+
999999999,
|
|
544
|
+
'Auto-created by CodeGen. Please update EntityIDMin and EntityIDMax to appropriate values for this schema.',
|
|
545
|
+
ss."SchemaDescription"
|
|
546
|
+
FROM __mj."vwSQLSchemas" ss
|
|
547
|
+
LEFT JOIN __mj."SchemaInfo" si ON ss."SchemaName" = si."SchemaName"
|
|
548
|
+
WHERE si."ID" IS NULL
|
|
549
|
+
AND ss."SchemaName" NOT IN (SELECT x.schema_name FROM _usi_excluded x);
|
|
550
|
+
|
|
551
|
+
RETURN QUERY
|
|
552
|
+
SELECT si.*
|
|
553
|
+
FROM __mj."SchemaInfo" si
|
|
554
|
+
INNER JOIN __mj."vwSQLSchemas" ss ON si."SchemaName" = ss."SchemaName"
|
|
555
|
+
WHERE ss."SchemaName" NOT IN (SELECT x.schema_name FROM _usi_excluded x);
|
|
556
|
+
|
|
557
|
+
DROP TABLE IF EXISTS _usi_excluded;
|
|
558
|
+
END;
|
|
559
|
+
$func$;
|
|
560
|
+
|
|
561
|
+
-- ----------------------------------------------------------------------------
|
|
562
|
+
-- 8. Fix spUpdateEntityFieldRelatedEntityNameFieldMap
|
|
563
|
+
-- The previous PG port had a one-parameter signature and a body that
|
|
564
|
+
-- referenced an undefined p_EntityFieldID — it could never match CodeGen's
|
|
565
|
+
-- two-argument call nor run. Drop it and create the faithful port.
|
|
566
|
+
-- ----------------------------------------------------------------------------
|
|
567
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateEntityFieldRelatedEntityNameFieldMap"(CHARACTER VARYING);
|
|
568
|
+
DROP FUNCTION IF EXISTS __mj."spUpdateEntityFieldRelatedEntityNameFieldMap"(UUID, CHARACTER VARYING);
|
|
569
|
+
CREATE OR REPLACE FUNCTION __mj."spUpdateEntityFieldRelatedEntityNameFieldMap"(
|
|
570
|
+
p_EntityFieldID UUID,
|
|
571
|
+
p_RelatedEntityNameFieldMap VARCHAR
|
|
572
|
+
)
|
|
573
|
+
RETURNS void
|
|
574
|
+
LANGUAGE plpgsql AS $func$
|
|
575
|
+
BEGIN
|
|
576
|
+
UPDATE __mj."EntityField"
|
|
577
|
+
SET "RelatedEntityNameFieldMap" = p_RelatedEntityNameFieldMap
|
|
578
|
+
WHERE "ID" = p_EntityFieldID;
|
|
579
|
+
END;
|
|
580
|
+
$func$;
|
|
581
|
+
|
|
582
|
+
-- ----------------------------------------------------------------------------
|
|
583
|
+
-- spGetPrimaryKeyForTable — PG port of the SQL Server proc used by
|
|
584
|
+
-- ManageMetadataBase.shouldCreateNewEntity to confirm a new table has a PK
|
|
585
|
+
-- before creating an Entity for it. Self-ensured here (rather than relying on
|
|
586
|
+
-- a migration having run) so a fresh PG database always has it available;
|
|
587
|
+
-- without it, every new entity fails validation with
|
|
588
|
+
-- "function __mj.spGetPrimaryKeyForTable(unknown, unknown) does not exist".
|
|
589
|
+
-- ----------------------------------------------------------------------------
|
|
590
|
+
DROP FUNCTION IF EXISTS __mj."spGetPrimaryKeyForTable"(VARCHAR, VARCHAR);
|
|
591
|
+
CREATE OR REPLACE FUNCTION __mj."spGetPrimaryKeyForTable"(
|
|
592
|
+
p_TableName VARCHAR(255),
|
|
593
|
+
p_SchemaName VARCHAR(255)
|
|
594
|
+
)
|
|
595
|
+
RETURNS TABLE(
|
|
596
|
+
"SchemaName" VARCHAR,
|
|
597
|
+
"TableName" VARCHAR,
|
|
598
|
+
"ColumnName" VARCHAR,
|
|
599
|
+
"DataType" VARCHAR,
|
|
600
|
+
"max_length" INTEGER,
|
|
601
|
+
"precision" INTEGER,
|
|
602
|
+
"scale" INTEGER,
|
|
603
|
+
"is_nullable" BOOLEAN
|
|
604
|
+
) AS
|
|
605
|
+
$spgetpk$
|
|
606
|
+
BEGIN
|
|
607
|
+
RETURN QUERY
|
|
608
|
+
SELECT
|
|
609
|
+
n.nspname::VARCHAR AS "SchemaName",
|
|
610
|
+
c.relname::VARCHAR AS "TableName",
|
|
611
|
+
a.attname::VARCHAR AS "ColumnName",
|
|
612
|
+
COALESCE(base_t.typname, t.typname)::VARCHAR
|
|
613
|
+
AS "DataType",
|
|
614
|
+
CASE
|
|
615
|
+
WHEN t.typname IN ('varchar', 'bpchar', 'char')
|
|
616
|
+
THEN CASE WHEN a.atttypmod = -1 THEN -1 ELSE a.atttypmod - 4 END
|
|
617
|
+
WHEN t.typname = 'text' THEN -1
|
|
618
|
+
ELSE a.attlen::integer
|
|
619
|
+
END AS "max_length",
|
|
620
|
+
CASE
|
|
621
|
+
WHEN t.typname = 'numeric' AND a.atttypmod <> -1
|
|
622
|
+
THEN ((a.atttypmod - 4) >> 16) & 65535
|
|
623
|
+
ELSE 0
|
|
624
|
+
END AS "precision",
|
|
625
|
+
CASE
|
|
626
|
+
WHEN t.typname = 'numeric' AND a.atttypmod <> -1
|
|
627
|
+
THEN (a.atttypmod - 4) & 65535
|
|
628
|
+
ELSE 0
|
|
629
|
+
END AS "scale",
|
|
630
|
+
(NOT a.attnotnull) AS "is_nullable"
|
|
631
|
+
FROM
|
|
632
|
+
pg_catalog.pg_index i
|
|
633
|
+
INNER JOIN pg_catalog.pg_class c ON c.oid = i.indrelid
|
|
634
|
+
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
635
|
+
CROSS JOIN LATERAL unnest(i.indkey) AS cols(col_num)
|
|
636
|
+
INNER JOIN pg_catalog.pg_attribute a
|
|
637
|
+
ON a.attrelid = c.oid AND a.attnum = cols.col_num
|
|
638
|
+
INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid
|
|
639
|
+
LEFT JOIN pg_catalog.pg_type base_t
|
|
640
|
+
ON base_t.oid = t.typbasetype AND t.typtype = 'd'
|
|
641
|
+
WHERE
|
|
642
|
+
i.indisprimary = true
|
|
643
|
+
AND c.relname = p_TableName
|
|
644
|
+
AND n.nspname = p_SchemaName
|
|
645
|
+
AND a.attnum > 0
|
|
646
|
+
AND NOT a.attisdropped;
|
|
647
|
+
END;
|
|
648
|
+
$spgetpk$ LANGUAGE plpgsql;
|
|
649
|
+
`;
|
|
650
|
+
//# sourceMappingURL=metadataSupportObjects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadataSupportObjects.js","sourceRoot":"","sources":["../../../../src/Database/providers/postgresql/metadataSupportObjects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,8BAA8B,CAAC,YAAoB;IAC/D,OAAO,4BAA4B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACzE,CAAC;AACD,MAAM,4BAA4B,GAAW,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+mBtD,CAAC"}
|