@memberjunction/codegen-lib 6.1.0-edge.5 → 6.1.0-edge.7
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 +20 -0
- package/dist/Angular/angular-codegen.d.ts +9 -6
- package/dist/Angular/angular-codegen.d.ts.map +1 -1
- package/dist/Angular/angular-codegen.js +80 -51
- package/dist/Angular/angular-codegen.js.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.d.ts.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.js +5 -2
- package/dist/Angular/join-grid-related-entity-component.js.map +1 -1
- package/dist/Angular/related-entity-components.d.ts +11 -0
- package/dist/Angular/related-entity-components.d.ts.map +1 -1
- package/dist/Angular/related-entity-components.js +23 -0
- package/dist/Angular/related-entity-components.js.map +1 -1
- package/dist/Angular/timeline-related-entity-component.d.ts.map +1 -1
- package/dist/Angular/timeline-related-entity-component.js +3 -2
- package/dist/Angular/timeline-related-entity-component.js.map +1 -1
- package/dist/Config/config.d.ts +29 -2
- package/dist/Config/config.d.ts.map +1 -1
- package/dist/Config/config.js +54 -5
- package/dist/Config/config.js.map +1 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts +64 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts.map +1 -1
- package/dist/Database/codeGenDatabaseProvider.js +49 -3
- package/dist/Database/codeGenDatabaseProvider.js.map +1 -1
- package/dist/Database/dbSchema.js +2 -1
- package/dist/Database/dbSchema.js.map +1 -1
- package/dist/Database/entity-field-change-tracking.d.ts +53 -0
- package/dist/Database/entity-field-change-tracking.d.ts.map +1 -0
- package/dist/Database/entity-field-change-tracking.js +120 -0
- package/dist/Database/entity-field-change-tracking.js.map +1 -0
- package/dist/Database/entity-level-tree-cycles.d.ts.map +1 -1
- package/dist/Database/entity-level-tree-cycles.js +3 -2
- package/dist/Database/entity-level-tree-cycles.js.map +1 -1
- package/dist/Database/field-metadata-lock.d.ts +47 -0
- package/dist/Database/field-metadata-lock.d.ts.map +1 -0
- package/dist/Database/field-metadata-lock.js +159 -0
- package/dist/Database/field-metadata-lock.js.map +1 -0
- package/dist/Database/manage-metadata.d.ts +133 -51
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +574 -306
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts +10 -2
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js +113 -42
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/postgresql/metadataSupportObjects.js +31 -8
- package/dist/Database/providers/postgresql/metadataSupportObjects.js.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts +47 -2
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js +176 -30
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.js +15 -2
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.js.map +1 -1
- package/dist/Database/reconcileFieldLevelSecurity.d.ts +22 -0
- package/dist/Database/reconcileFieldLevelSecurity.d.ts.map +1 -0
- package/dist/Database/reconcileFieldLevelSecurity.js +47 -0
- package/dist/Database/reconcileFieldLevelSecurity.js.map +1 -0
- package/dist/Database/sql_codegen.d.ts +34 -0
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +152 -14
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Manifest/GenerateClassRegistrationsManifest.d.ts.map +1 -1
- package/dist/Manifest/GenerateClassRegistrationsManifest.js +3 -2
- package/dist/Manifest/GenerateClassRegistrationsManifest.js.map +1 -1
- package/dist/Misc/action_subclasses_codegen.js +2 -2
- package/dist/Misc/action_subclasses_codegen.js.map +1 -1
- package/dist/Misc/advanced_generation.d.ts +17 -5
- package/dist/Misc/advanced_generation.d.ts.map +1 -1
- package/dist/Misc/advanced_generation.js +69 -23
- package/dist/Misc/advanced_generation.js.map +1 -1
- package/dist/Misc/codegen-reporter.d.ts +2 -0
- package/dist/Misc/codegen-reporter.d.ts.map +1 -1
- package/dist/Misc/codegen-reporter.js +6 -2
- package/dist/Misc/codegen-reporter.js.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.js +30 -20
- package/dist/Misc/entity_subclasses_codegen.js.map +1 -1
- package/dist/Misc/graphql_server_codegen.d.ts +39 -0
- package/dist/Misc/graphql_server_codegen.d.ts.map +1 -1
- package/dist/Misc/graphql_server_codegen.js +63 -9
- package/dist/Misc/graphql_server_codegen.js.map +1 -1
- package/dist/Misc/remote_operations_codegen.d.ts +36 -1
- package/dist/Misc/remote_operations_codegen.d.ts.map +1 -1
- package/dist/Misc/remote_operations_codegen.js +178 -8
- package/dist/Misc/remote_operations_codegen.js.map +1 -1
- package/dist/Misc/schema-emit.d.ts.map +1 -1
- package/dist/Misc/schema-emit.js +2 -1
- package/dist/Misc/schema-emit.js.map +1 -1
- package/dist/Misc/sql_logging.d.ts +63 -8
- package/dist/Misc/sql_logging.d.ts.map +1 -1
- package/dist/Misc/sql_logging.js +169 -42
- package/dist/Misc/sql_logging.js.map +1 -1
- package/dist/Misc/util.d.ts +12 -0
- package/dist/Misc/util.d.ts.map +1 -1
- package/dist/Misc/util.js +71 -8
- package/dist/Misc/util.js.map +1 -1
- package/dist/plugins/index.d.ts +3 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +28 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/runCodeGen.d.ts.map +1 -1
- package/dist/runCodeGen.js +134 -26
- package/dist/runCodeGen.js.map +1 -1
- package/package.json +29 -29
|
@@ -400,7 +400,7 @@ export declare class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider {
|
|
|
400
400
|
routineParams: string;
|
|
401
401
|
};
|
|
402
402
|
/** @inheritdoc */
|
|
403
|
-
callRoutineSQL(schema: string, routineName: string, params: string[],
|
|
403
|
+
callRoutineSQL(schema: string, routineName: string, params: string[], paramNames?: string[], discardResult?: boolean): string;
|
|
404
404
|
/** @inheritdoc */
|
|
405
405
|
conditionalInsertSQL(checkQuery: string, insertSQL: string): string;
|
|
406
406
|
/** @inheritdoc */
|
|
@@ -487,7 +487,7 @@ export declare class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider {
|
|
|
487
487
|
*/
|
|
488
488
|
parseColumnDefaultValue(sqlDefaultValue: string): string | null;
|
|
489
489
|
/** @inheritdoc */
|
|
490
|
-
getPendingEntityFieldsSQL(mjCoreSchema: string, entityIDs?: string[]): string;
|
|
490
|
+
getPendingEntityFieldsSQL(mjCoreSchema: string, entityIDs?: string[], excludeSchemas?: string[]): string;
|
|
491
491
|
/** @inheritdoc */
|
|
492
492
|
getCheckConstraintsSchemaFilter(_excludeSchemas: string[]): string;
|
|
493
493
|
/** @inheritdoc */
|
|
@@ -602,6 +602,14 @@ export declare class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider {
|
|
|
602
602
|
private generateCascadeCursorDelete;
|
|
603
603
|
/** Collects unique role SQL names from permissions that have a role name */
|
|
604
604
|
private collectPermissionRoles;
|
|
605
|
+
/**
|
|
606
|
+
* B3: roles with a blank `SQLName` are app-tier-only BY DESIGN (decision D3a) — the grant
|
|
607
|
+
* emitters skip them, and this makes the skip visible: one INFO line per role per run.
|
|
608
|
+
* (PostgreSQL additionally emits NO field-security DENYs at all, per decision D2 — PG has
|
|
609
|
+
* no DENY primitive, so MJ's Deny-wins semantics cannot be expressed in its DB tier.)
|
|
610
|
+
*/
|
|
611
|
+
private _appTierOnlyRolesLogged;
|
|
612
|
+
private logAppTierOnlyRoleSkip;
|
|
605
613
|
/** @inheritdoc */
|
|
606
614
|
getViewDefinitionSQL(schema: string, viewName: string): string;
|
|
607
615
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgreSQLCodeGenProvider.d.ts","sourceRoot":"","sources":["../../../../src/Database/providers/postgresql/PostgreSQLCodeGenProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAyE,MAAM,sBAAsB,CAAC;AAE1I,OAAO,EACH,uBAAuB,EACvB,QAAQ,EACR,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EACnB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAqB,gBAAgB,EAAE,UAAU,EAA4H,MAAM,6BAA6B,CAAC;AAoBxN;;;;;;;;GAQG;AACH,qBACa,yBAA0B,SAAQ,uBAAuB;IAClE,kBAAkB;IAClB,IAAI,OAAO,IAAI,UAAU,CAExB;IAED,kBAAkB;IAClB,IAAI,WAAW,IAAI,gBAAgB,CAElC;IAED;;;;;;;;;;;;OAYG;IACG,eAAe,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA0ClD;;;;;;;;;;;;;;;;;OAiBG;IACM,kCAAkC,IAAI,OAAO;IAMtD;;;;OAIG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAoBlH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACH,gBAAgB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM;IAyN5D;;;;;;;;;OASG;IACM,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,GAAG,MAAM;IAoBnH;;;;;;OAMG;IACM,kCAAkC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAMxG;;;;OAIG;IACM,kCAAkC,IAAI,MAAM;IAIrD;;;;;OAKG;IACM,sCAAsC,IAAI,MAAM;IAMzD;;;;;;;OAOG;IACH,OAAO,CAAC,6BAA6B;IAkBrC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;;;;;;OAOG;IACH,OAAO,CAAC,wBAAwB;IAqBhC;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAapC;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IA4DjC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB;
|
|
1
|
+
{"version":3,"file":"PostgreSQLCodeGenProvider.d.ts","sourceRoot":"","sources":["../../../../src/Database/providers/postgresql/PostgreSQLCodeGenProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { EntityInfo, ResolveStartupMode, SetProvider, StartupManager } from '@me
|
|
|
8
8
|
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
9
|
import { CodeGenDatabaseProvider, CRUDType, } from '../../codeGenDatabaseProvider.js';
|
|
10
10
|
import { configInfo, mj_core_schema } from '../../../Config/config.js';
|
|
11
|
-
import { logError, startSpinner, succeedSpinner } from '../../../Misc/status_logging.js';
|
|
11
|
+
import { logError, logStatus, logWarning, startSpinner, succeedSpinner } from '../../../Misc/status_logging.js';
|
|
12
12
|
import { buildMetadataSupportObjectsSQL } from './metadataSupportObjects.js';
|
|
13
13
|
import { PostgreSQLDialect, AutoQuotePostgreSQLIdentifiers, restarLayeredOuterView, buildCreateOrReplaceLayeredOuterViewSQL, LayeredOuterRestarError } from '@memberjunction/sql-dialect';
|
|
14
14
|
import { shouldIncludeFieldInParams, useJsonArgShape, UserCache, } from '@memberjunction/generic-database-provider';
|
|
@@ -29,6 +29,16 @@ const pgDialect = new PostgreSQLDialect();
|
|
|
29
29
|
* `ClassFactory.CreateInstance(CodeGenDatabaseProvider, configInfo.dbPlatform)`.
|
|
30
30
|
*/
|
|
31
31
|
let PostgreSQLCodeGenProvider = class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider {
|
|
32
|
+
constructor() {
|
|
33
|
+
super(...arguments);
|
|
34
|
+
/**
|
|
35
|
+
* B3: roles with a blank `SQLName` are app-tier-only BY DESIGN (decision D3a) — the grant
|
|
36
|
+
* emitters skip them, and this makes the skip visible: one INFO line per role per run.
|
|
37
|
+
* (PostgreSQL additionally emits NO field-security DENYs at all, per decision D2 — PG has
|
|
38
|
+
* no DENY primitive, so MJ's Deny-wins semantics cannot be expressed in its DB tier.)
|
|
39
|
+
*/
|
|
40
|
+
this._appTierOnlyRolesLogged = new Set();
|
|
41
|
+
}
|
|
32
42
|
/** @inheritdoc */
|
|
33
43
|
get Dialect() {
|
|
34
44
|
return pgDialect;
|
|
@@ -595,11 +605,22 @@ ${trigger}
|
|
|
595
605
|
const fnName = this.getCRUDRoutineName(entity, CRUDType.Create);
|
|
596
606
|
const viewName = this.getBaseViewName(entity);
|
|
597
607
|
const permissions = this.generateCRUDPermissions(entity, fnName, CRUDType.Create);
|
|
598
|
-
const
|
|
608
|
+
const isSingleKey = entity.PrimaryKeys.length === 1;
|
|
609
|
+
const firstKey = entity.FirstPrimaryKey; // first-pk-ok: read only for the UUID auto-generation strategy, which is gated on isSingleKey; every declaration, list and predicate below iterates entity.PrimaryKeys
|
|
599
610
|
const pkType = firstKey.Type.toLowerCase().trim();
|
|
600
|
-
const pkIsUuidSingle = (pkType === 'uniqueidentifier' || pkType === 'uuid') &&
|
|
601
|
-
|
|
602
|
-
|
|
611
|
+
const pkIsUuidSingle = (pkType === 'uniqueidentifier' || pkType === 'uuid') && isSingleKey;
|
|
612
|
+
// One plpgsql variable per key column. A single-column key keeps the historical `v_id`
|
|
613
|
+
// name; a composite key gets one variable per column so the INSERT lists every key
|
|
614
|
+
// column and the returning SELECT binds all of them (not just the first).
|
|
615
|
+
const pkVars = entity.PrimaryKeys.map((k) => ({
|
|
616
|
+
field: k,
|
|
617
|
+
varName: isSingleKey ? 'v_id' : `v_id_${k.CodeName}`,
|
|
618
|
+
pgType: this.mapSQLType(k.SQLFullType),
|
|
619
|
+
}));
|
|
620
|
+
const pkDeclarations = pkVars.map((v) => ` ${v.varName} ${v.pgType};`).join('\n');
|
|
621
|
+
const pkColListInit = pkVars.map((v) => `quote_ident('${v.field.Name.replace(/'/g, "''")}')`).join(" || ', ' || ");
|
|
622
|
+
const pkValListInit = pkVars.map((v) => `quote_literal(${v.varName}) || '::${v.pgType}'`).join(" || ', ' || ");
|
|
623
|
+
const pkWhere = pkVars.map((v) => `${pgDialect.QuoteIdentifier(v.field.Name)} = ${v.varName}`).join(' AND ');
|
|
603
624
|
// Writable fields participating in the INSERT — exclude PK (handled
|
|
604
625
|
// separately so we can supply a generated UUID when key is absent),
|
|
605
626
|
// exclude virtual / special-date / non-API-writable.
|
|
@@ -629,17 +650,17 @@ ${trigger}
|
|
|
629
650
|
const fieldNamesArrayLiteral = writableFields.map((f) => `'${f.Name}'`).join(', ');
|
|
630
651
|
// ID resolution body: differs by PK strategy. Single-UUID PK is auto-
|
|
631
652
|
// generated when the caller doesn't supply one; everything else (composite,
|
|
632
|
-
// non-UUID) requires the caller to provide
|
|
653
|
+
// non-UUID) requires the caller to provide every key column explicitly.
|
|
633
654
|
const idResolveBody = pkIsUuidSingle
|
|
634
655
|
? ` IF p_data ? '${firstKey.Name}' THEN
|
|
635
|
-
v_id := (p_data->>'${firstKey.Name}')::${
|
|
656
|
+
v_id := (p_data->>'${firstKey.Name}')::${this.mapSQLType(firstKey.SQLFullType)};
|
|
636
657
|
ELSE
|
|
637
658
|
v_id := gen_random_uuid();
|
|
638
659
|
END IF;`
|
|
639
|
-
: ` IF NOT (p_data ? '${
|
|
640
|
-
RAISE EXCEPTION '${fnName}: p_data must include "${
|
|
660
|
+
: pkVars.map((v) => ` IF NOT (p_data ? '${v.field.Name}') THEN
|
|
661
|
+
RAISE EXCEPTION '${fnName}: p_data must include "${v.field.Name}"';
|
|
641
662
|
END IF;
|
|
642
|
-
|
|
663
|
+
${v.varName} := (p_data->>'${v.field.Name}')::${v.pgType};`).join('\n');
|
|
643
664
|
return `
|
|
644
665
|
------------------------------------------------------------
|
|
645
666
|
----- CREATE FUNCTION FOR ${entity.BaseTable} (JSON-arg shape)
|
|
@@ -649,7 +670,7 @@ CREATE OR REPLACE FUNCTION ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(p
|
|
|
649
670
|
RETURNS SETOF ${pgDialect.QuoteSchema(entity.SchemaName, viewName)}
|
|
650
671
|
AS $$
|
|
651
672
|
DECLARE
|
|
652
|
-
|
|
673
|
+
${pkDeclarations}
|
|
653
674
|
v_field_name TEXT;
|
|
654
675
|
v_cast_expr TEXT;
|
|
655
676
|
v_col_list TEXT;
|
|
@@ -658,8 +679,8 @@ DECLARE
|
|
|
658
679
|
BEGIN
|
|
659
680
|
${idResolveBody}
|
|
660
681
|
|
|
661
|
-
v_col_list :=
|
|
662
|
-
v_val_list :=
|
|
682
|
+
v_col_list := ${pkColListInit};
|
|
683
|
+
v_val_list := ${pkValListInit};
|
|
663
684
|
|
|
664
685
|
-- Build column / value lists from keys present in p_data. Absent keys are
|
|
665
686
|
-- omitted entirely so the column's DEFAULT applies (matching the typed-arg
|
|
@@ -686,7 +707,7 @@ ${fieldCastEntries}
|
|
|
686
707
|
|
|
687
708
|
RETURN QUERY
|
|
688
709
|
SELECT * FROM ${pgDialect.QuoteSchema(entity.SchemaName, viewName)}
|
|
689
|
-
WHERE ${
|
|
710
|
+
WHERE ${pkWhere};
|
|
690
711
|
END;
|
|
691
712
|
$$ LANGUAGE plpgsql;
|
|
692
713
|
${permissions}
|
|
@@ -716,7 +737,10 @@ ${permissions}
|
|
|
716
737
|
const viewName = this.getBaseViewName(entity);
|
|
717
738
|
const paramString = this.generateCRUDParamString(entity.Fields, false);
|
|
718
739
|
const permissions = this.generateCRUDPermissions(entity, fnName, CRUDType.Create);
|
|
719
|
-
const firstKey = entity.FirstPrimaryKey;
|
|
740
|
+
const firstKey = entity.FirstPrimaryKey; // first-pk-ok: drives the single-key UUID strategy (guarded by PrimaryKeys.length === 1 in buildCreateInsertStrategy); identity and composite strategies iterate entity.PrimaryKeys
|
|
741
|
+
// v_new_id receives the database-generated key: the identity/serial column when there is
|
|
742
|
+
// one (which on a composite key need not be the first column), else the single UUID key.
|
|
743
|
+
const generatedKey = entity.PrimaryKeys.find((k) => k.AutoIncrement) ?? firstKey;
|
|
720
744
|
// For UUID PKs and AutoIncrement PKs, the strategy below adds the PK
|
|
721
745
|
// column manually (with v_new_id or RETURNING). Excluding it from the
|
|
722
746
|
// auto-generated insertColumns/insertValues avoids the column appearing
|
|
@@ -742,7 +766,7 @@ CREATE OR REPLACE FUNCTION ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(
|
|
|
742
766
|
${paramString}
|
|
743
767
|
) RETURNS SETOF ${pgDialect.QuoteSchema(entity.SchemaName, viewName)} AS $$
|
|
744
768
|
DECLARE
|
|
745
|
-
v_new_id ${this.mapSQLType(
|
|
769
|
+
v_new_id ${this.mapSQLType(generatedKey.SQLFullType)};
|
|
746
770
|
BEGIN
|
|
747
771
|
${strategy.preInsert}INSERT INTO ${pgDialect.QuoteSchema(entity.SchemaName, entity.BaseTable)}
|
|
748
772
|
(
|
|
@@ -1038,8 +1062,8 @@ WHERE ${ftsColName} IS NULL;
|
|
|
1038
1062
|
if (entity.PrimaryKeys.length !== 1) {
|
|
1039
1063
|
throw new Error(`[Hierarchy] Entity '${entity.Name}' has ${entity.PrimaryKeys.length} primary key fields. MemberJunction hierarchy TVF generation requires a single-column primary key.`);
|
|
1040
1064
|
}
|
|
1041
|
-
const primaryKey = entity.FirstPrimaryKey.Name;
|
|
1042
|
-
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType);
|
|
1065
|
+
const primaryKey = entity.FirstPrimaryKey.Name; // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1066
|
+
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType); // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1043
1067
|
const fieldName = field.Name;
|
|
1044
1068
|
const fnName = this.getHierarchyMetaFunctionName(entity, field);
|
|
1045
1069
|
return `
|
|
@@ -1104,8 +1128,8 @@ $$ LANGUAGE sql STABLE;
|
|
|
1104
1128
|
if (entity.PrimaryKeys.length !== 1) {
|
|
1105
1129
|
throw new Error(`[Hierarchy] Entity '${entity.Name}' has ${entity.PrimaryKeys.length} primary key fields. MemberJunction hierarchy TVF generation requires a single-column primary key.`);
|
|
1106
1130
|
}
|
|
1107
|
-
const primaryKey = entity.FirstPrimaryKey.Name;
|
|
1108
|
-
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType);
|
|
1131
|
+
const primaryKey = entity.FirstPrimaryKey.Name; // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1132
|
+
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType); // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1109
1133
|
const fieldName = field.Name;
|
|
1110
1134
|
const fnName = this.getDescendantsFunctionName(entity, field);
|
|
1111
1135
|
return `
|
|
@@ -1166,8 +1190,8 @@ $$ LANGUAGE sql STABLE;
|
|
|
1166
1190
|
if (entity.PrimaryKeys.length !== 1) {
|
|
1167
1191
|
throw new Error(`[Hierarchy] Entity '${entity.Name}' has ${entity.PrimaryKeys.length} primary key fields. MemberJunction hierarchy TVF generation requires a single-column primary key.`);
|
|
1168
1192
|
}
|
|
1169
|
-
const primaryKey = entity.FirstPrimaryKey.Name;
|
|
1170
|
-
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType);
|
|
1193
|
+
const primaryKey = entity.FirstPrimaryKey.Name; // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1194
|
+
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType); // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1171
1195
|
const fieldName = field.Name;
|
|
1172
1196
|
const fnName = this.getAncestorsFunctionName(entity, field);
|
|
1173
1197
|
return `
|
|
@@ -1244,7 +1268,7 @@ $$ LANGUAGE sql STABLE;
|
|
|
1244
1268
|
generateHierarchyFieldJoin(entity, field, alias) {
|
|
1245
1269
|
const fnName = this.getHierarchyMetaFunctionName(entity, field);
|
|
1246
1270
|
const tableAlias = entity.BaseTableCodeName.charAt(0).toLowerCase();
|
|
1247
|
-
return `LEFT JOIN LATERAL ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(${tableAlias}.${pgDialect.QuoteIdentifier(entity.FirstPrimaryKey.Name)}, ${tableAlias}.${pgDialect.QuoteIdentifier(field.Name)}) AS ${alias} ON true`;
|
|
1271
|
+
return `LEFT JOIN LATERAL ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(${tableAlias}.${pgDialect.QuoteIdentifier(entity.FirstPrimaryKey.Name)}, ${tableAlias}.${pgDialect.QuoteIdentifier(field.Name)}) AS ${alias} ON true`; // first-pk-ok: hierarchy TVF argument; sql_codegen.getHierarchyFKs skips composite-key entities and the TVF generator throws for them
|
|
1248
1272
|
}
|
|
1249
1273
|
/**
|
|
1250
1274
|
* Generates a PostgreSQL function that recursively calculates the root record ID for a
|
|
@@ -1254,8 +1278,8 @@ $$ LANGUAGE sql STABLE;
|
|
|
1254
1278
|
if (entity.PrimaryKeys.length !== 1) {
|
|
1255
1279
|
throw new Error(`[Hierarchy] Entity '${entity.Name}' has ${entity.PrimaryKeys.length} primary key fields. MemberJunction hierarchy TVF generation requires a single-column primary key.`);
|
|
1256
1280
|
}
|
|
1257
|
-
const primaryKey = entity.FirstPrimaryKey.Name;
|
|
1258
|
-
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType);
|
|
1281
|
+
const primaryKey = entity.FirstPrimaryKey.Name; // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1282
|
+
const primaryKeyType = this.mapSQLType(entity.FirstPrimaryKey.SQLFullType); // first-pk-ok: guarded by the PrimaryKeys.length !== 1 throw above; hierarchy TVFs are single-column by design
|
|
1259
1283
|
const fieldName = field.Name;
|
|
1260
1284
|
const fnName = this.getRootIDFunctionName(entity, field);
|
|
1261
1285
|
return `
|
|
@@ -1330,8 +1354,9 @@ $$ LANGUAGE sql STABLE;
|
|
|
1330
1354
|
generateRootFieldJoin(entity, field, alias) {
|
|
1331
1355
|
const fnName = this.getRootIDFunctionName(entity, field);
|
|
1332
1356
|
const tableAlias = entity.BaseTableCodeName.charAt(0).toLowerCase();
|
|
1357
|
+
const primaryKey = entity.FirstPrimaryKey.Name; // first-pk-ok: hierarchy TVF argument; sql_codegen.getHierarchyFKs skips composite-key entities and the TVF generator throws for them
|
|
1333
1358
|
return `LEFT JOIN LATERAL (
|
|
1334
|
-
SELECT ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(${tableAlias}.${pgDialect.QuoteIdentifier(
|
|
1359
|
+
SELECT ${pgDialect.QuoteSchema(entity.SchemaName, fnName)}(${tableAlias}.${pgDialect.QuoteIdentifier(primaryKey)}, ${tableAlias}.${pgDialect.QuoteIdentifier(field.Name)}) AS root_id
|
|
1335
1360
|
) AS ${alias} ON true`;
|
|
1336
1361
|
}
|
|
1337
1362
|
// ─── PERMISSIONS ─────────────────────────────────────────────────────
|
|
@@ -1351,8 +1376,10 @@ $$ LANGUAGE sql STABLE;
|
|
|
1351
1376
|
generateCRUDPermissions(entity, routineName, type) {
|
|
1352
1377
|
const roles = [];
|
|
1353
1378
|
for (const ep of entity.Permissions) {
|
|
1354
|
-
if (!ep.RoleSQLName || ep.RoleSQLName.length === 0)
|
|
1379
|
+
if (!ep.RoleSQLName || ep.RoleSQLName.length === 0) {
|
|
1380
|
+
this.logAppTierOnlyRoleSkip(ep.Role);
|
|
1355
1381
|
continue;
|
|
1382
|
+
}
|
|
1356
1383
|
if ((type === CRUDType.Create && ep.CanCreate) ||
|
|
1357
1384
|
(type === CRUDType.Update && ep.CanUpdate) ||
|
|
1358
1385
|
(type === CRUDType.Delete && ep.CanDelete)) {
|
|
@@ -1604,9 +1631,15 @@ END $$;
|
|
|
1604
1631
|
}
|
|
1605
1632
|
// ─── METADATA MANAGEMENT: STORED PROCEDURE CALLS ─────────────────
|
|
1606
1633
|
/** @inheritdoc */
|
|
1607
|
-
callRoutineSQL(schema, routineName, params,
|
|
1634
|
+
callRoutineSQL(schema, routineName, params, paramNames, discardResult) {
|
|
1608
1635
|
const qualifiedName = pgDialect.QuoteSchema(schema, routineName);
|
|
1609
|
-
|
|
1636
|
+
let paramList;
|
|
1637
|
+
if (paramNames && paramNames.length === params.length) {
|
|
1638
|
+
paramList = params.map((p, i) => `p_${paramNames[i]} => ${p}`).join(', ');
|
|
1639
|
+
}
|
|
1640
|
+
else {
|
|
1641
|
+
paramList = params.join(', ');
|
|
1642
|
+
}
|
|
1610
1643
|
if (discardResult) {
|
|
1611
1644
|
// `SELECT * FROM routine(...)` is not universally valid on PostgreSQL: a function
|
|
1612
1645
|
// declared `RETURNS SETOF record` — which spDeleteEntityWithCoreDependencies is — is
|
|
@@ -1892,9 +1925,9 @@ $if_view_exists$;
|
|
|
1892
1925
|
}
|
|
1893
1926
|
// ─── METADATA MANAGEMENT: COMPLEX SQL GENERATION ─────────────────
|
|
1894
1927
|
/** @inheritdoc */
|
|
1895
|
-
getPendingEntityFieldsSQL(mjCoreSchema, entityIDs) {
|
|
1928
|
+
getPendingEntityFieldsSQL(mjCoreSchema, entityIDs, excludeSchemas) {
|
|
1896
1929
|
const qs = pgDialect.QuoteSchema.bind(pgDialect);
|
|
1897
|
-
return this.buildPendingEntityFieldsQuery(mjCoreSchema, qs, entityIDs);
|
|
1930
|
+
return this.buildPendingEntityFieldsQuery(mjCoreSchema, qs, entityIDs, excludeSchemas);
|
|
1898
1931
|
}
|
|
1899
1932
|
/** @inheritdoc */
|
|
1900
1933
|
getCheckConstraintsSchemaFilter(_excludeSchemas) {
|
|
@@ -2288,13 +2321,25 @@ WHERE p.prokind IN ('f', 'p')
|
|
|
2288
2321
|
buildCreateInsertStrategy(entity, firstKey, insertColumns, insertValues) {
|
|
2289
2322
|
const viewName = this.getBaseViewName(entity);
|
|
2290
2323
|
const pkCol = pgDialect.QuoteIdentifier(firstKey.Name);
|
|
2291
|
-
|
|
2324
|
+
const identityKey = entity.PrimaryKeys.find((k) => k.AutoIncrement);
|
|
2325
|
+
if (identityKey) {
|
|
2326
|
+
// Identity/serial key. On a composite key such as (TenantID, ID serial) the remaining key
|
|
2327
|
+
// columns are caller-supplied: they must be inserted and included in the row lookup. For a
|
|
2328
|
+
// single-column identity key callerSuppliedKeys is empty and nothing is added.
|
|
2329
|
+
const identityCol = pgDialect.QuoteIdentifier(identityKey.Name);
|
|
2330
|
+
const callerSuppliedKeys = entity.PrimaryKeys.filter((k) => !k.AutoIncrement);
|
|
2331
|
+
const keyColumns = callerSuppliedKeys.map((k) => pgDialect.QuoteIdentifier(k.Name)).join(',\n ');
|
|
2332
|
+
const keyValues = callerSuppliedKeys.map((k) => pgDialect.ParameterRef(k.CodeName)).join(',\n ');
|
|
2333
|
+
const keyPredicates = callerSuppliedKeys
|
|
2334
|
+
.map((k) => ` AND ${pgDialect.QuoteIdentifier(k.Name)} = ${pgDialect.ParameterRef(k.CodeName)}`)
|
|
2335
|
+
.join('');
|
|
2336
|
+
const hasNonPkColumns = insertColumns.trim().length > 0;
|
|
2292
2337
|
return {
|
|
2293
2338
|
preInsert: '',
|
|
2294
|
-
returningClause: `RETURNING ${
|
|
2295
|
-
selectClause: `SELECT * FROM ${pgDialect.QuoteSchema(entity.SchemaName, viewName)}\n WHERE ${
|
|
2296
|
-
finalColumns: insertColumns,
|
|
2297
|
-
finalValues: insertValues,
|
|
2339
|
+
returningClause: `RETURNING ${identityCol} INTO v_new_id`,
|
|
2340
|
+
selectClause: `SELECT * FROM ${pgDialect.QuoteSchema(entity.SchemaName, viewName)}\n WHERE ${identityCol} = v_new_id${keyPredicates}`,
|
|
2341
|
+
finalColumns: callerSuppliedKeys.length === 0 ? insertColumns : (hasNonPkColumns ? `${keyColumns},\n ${insertColumns}` : keyColumns),
|
|
2342
|
+
finalValues: callerSuppliedKeys.length === 0 ? insertValues : (hasNonPkColumns ? `${keyValues},\n ${insertValues}` : keyValues),
|
|
2298
2343
|
};
|
|
2299
2344
|
}
|
|
2300
2345
|
if ((firstKey.Type.toLowerCase().trim() === 'uniqueidentifier' || firstKey.Type.toLowerCase().trim() === 'uuid') && entity.PrimaryKeys.length === 1) {
|
|
@@ -2380,7 +2425,13 @@ WHERE p.prokind IN ('f', 'p')
|
|
|
2380
2425
|
return ` -- WARNING: Cannot cascade update ${relatedEntity.Name}.${fkField.Name} to NULL - entity does not allow updates`;
|
|
2381
2426
|
}
|
|
2382
2427
|
const updateFnName = this.getCRUDRoutineName(relatedEntity, CRUDType.Update);
|
|
2383
|
-
const
|
|
2428
|
+
const parentKey = this.resolveCascadeParentKeyField(parentEntity, fkField);
|
|
2429
|
+
if (!parentKey) {
|
|
2430
|
+
const warning = this.unresolvedCascadeKeyComment(parentEntity, relatedEntity, fkField);
|
|
2431
|
+
logWarning(`WARNING in ${this.getCRUDRoutineName(parentEntity, CRUDType.Delete)} generation: ${warning.trim()}`);
|
|
2432
|
+
return warning;
|
|
2433
|
+
}
|
|
2434
|
+
const whereClause = `${pgDialect.QuoteIdentifier(fkField.Name)} = ${pgDialect.ParameterRef(parentKey.CodeName)}`;
|
|
2384
2435
|
return ` -- Cascade: Set ${relatedEntity.Name}.${fkField.Name} to NULL
|
|
2385
2436
|
FOR v_rec IN
|
|
2386
2437
|
SELECT ${relatedEntity.PrimaryKeys.map((pk) => pgDialect.QuoteIdentifier(pk.Name)).join(', ')}
|
|
@@ -2400,7 +2451,13 @@ WHERE p.prokind IN ('f', 'p')
|
|
|
2400
2451
|
return ` -- WARNING: Cannot cascade delete ${relatedEntity.Name} records - entity does not allow deletes`;
|
|
2401
2452
|
}
|
|
2402
2453
|
const deleteFnName = this.getCRUDRoutineName(relatedEntity, CRUDType.Delete);
|
|
2403
|
-
const
|
|
2454
|
+
const parentKey = this.resolveCascadeParentKeyField(parentEntity, fkField);
|
|
2455
|
+
if (!parentKey) {
|
|
2456
|
+
const warning = this.unresolvedCascadeKeyComment(parentEntity, relatedEntity, fkField);
|
|
2457
|
+
logWarning(`WARNING in ${this.getCRUDRoutineName(parentEntity, CRUDType.Delete)} generation: ${warning.trim()}`);
|
|
2458
|
+
return warning;
|
|
2459
|
+
}
|
|
2460
|
+
const whereClause = `${pgDialect.QuoteIdentifier(fkField.Name)} = ${pgDialect.ParameterRef(parentKey.CodeName)}`;
|
|
2404
2461
|
return ` -- Cascade: Delete ${relatedEntity.Name} records via ${fkField.Name}
|
|
2405
2462
|
FOR v_rec IN
|
|
2406
2463
|
SELECT ${relatedEntity.PrimaryKeys.map((pk) => pgDialect.QuoteIdentifier(pk.Name)).join(', ')}
|
|
@@ -2418,9 +2475,19 @@ WHERE p.prokind IN ('f', 'p')
|
|
|
2418
2475
|
if (ep.RoleSQLName && ep.RoleSQLName.length > 0 && !roles.includes(ep.RoleSQLName)) {
|
|
2419
2476
|
roles.push(ep.RoleSQLName);
|
|
2420
2477
|
}
|
|
2478
|
+
else if (!ep.RoleSQLName || ep.RoleSQLName.length === 0) {
|
|
2479
|
+
this.logAppTierOnlyRoleSkip(ep.Role);
|
|
2480
|
+
}
|
|
2421
2481
|
}
|
|
2422
2482
|
return roles;
|
|
2423
2483
|
}
|
|
2484
|
+
logAppTierOnlyRoleSkip(roleName) {
|
|
2485
|
+
const name = (roleName ?? '').trim();
|
|
2486
|
+
if (!name || this._appTierOnlyRolesLogged.has(name))
|
|
2487
|
+
return;
|
|
2488
|
+
this._appTierOnlyRolesLogged.add(name);
|
|
2489
|
+
logStatus(` ℹ️ Role '${name}' is app-tier-only (no SQLName); no DB grants emitted.`);
|
|
2490
|
+
}
|
|
2424
2491
|
// ─── DATABASE INTROSPECTION ──────────────────────────────────────────
|
|
2425
2492
|
/** @inheritdoc */
|
|
2426
2493
|
getViewDefinitionSQL(schema, viewName) {
|
|
@@ -2486,12 +2553,15 @@ WHERE p.prokind IN ('f', 'p')
|
|
|
2486
2553
|
* Uses CTEs for FK, PK, and UK caches, then joins against entity metadata
|
|
2487
2554
|
* to find fields that exist in the database but not in MJ metadata.
|
|
2488
2555
|
*/
|
|
2489
|
-
buildPendingEntityFieldsQuery(schema, qs, entityIDs) {
|
|
2556
|
+
buildPendingEntityFieldsQuery(schema, qs, entityIDs, excludeSchemas) {
|
|
2490
2557
|
// PG uses lowercase UUIDs; entity IDs from the metadata cache are already
|
|
2491
2558
|
// normalized so direct string interpolation is safe (internal IDs, not user input).
|
|
2492
2559
|
const scopeFilter = entityIDs && entityIDs.length > 0
|
|
2493
2560
|
? `AND sf."EntityID" IN (${entityIDs.map(id => `'${id}'`).join(',')})`
|
|
2494
2561
|
: '';
|
|
2562
|
+
const schemaFilter = excludeSchemas && excludeSchemas.length > 0
|
|
2563
|
+
? `AND e."SchemaName" NOT IN (${excludeSchemas.map(s => `'${s.replace(/'/g, "''")}'`).join(',')})`
|
|
2564
|
+
: '';
|
|
2495
2565
|
return `
|
|
2496
2566
|
WITH fk_cache AS (
|
|
2497
2567
|
SELECT "column", "table", "schema_name", "referenced_table", "referenced_column", "referenced_schema"
|
|
@@ -2518,9 +2588,9 @@ numbered_rows AS (
|
|
|
2518
2588
|
SELECT
|
|
2519
2589
|
sf."EntityID",
|
|
2520
2590
|
COALESCE(ms."MaxSequence", 0) + 100000 + sf."Sequence" AS "Sequence",
|
|
2521
|
-
-- The RAW schema ordinal
|
|
2522
|
-
--
|
|
2523
|
-
--
|
|
2591
|
+
-- The RAW schema ordinal. The INSERT emitter uses it for DefaultInView only; the emitted
|
|
2592
|
+
-- Sequence is an apply-time MAX()+1 subquery. (Sequence above is only this query's ORDER BY
|
|
2593
|
+
-- key — never inserted — and the renumber pass overwrites every row from the schema.)
|
|
2524
2594
|
sf."Sequence" AS "SourceOrdinal",
|
|
2525
2595
|
sf."FieldName",
|
|
2526
2596
|
sf."Description",
|
|
@@ -2563,6 +2633,7 @@ numbered_rows AS (
|
|
|
2563
2633
|
WHERE
|
|
2564
2634
|
"EntityFieldID" IS NULL
|
|
2565
2635
|
${scopeFilter}
|
|
2636
|
+
${schemaFilter}
|
|
2566
2637
|
)
|
|
2567
2638
|
SELECT *
|
|
2568
2639
|
FROM numbered_rows
|