@memberjunction/metadata-sync 6.2.0-edge.5 → 6.2.0-edge.6

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.
Files changed (48) hide show
  1. package/README.md +5 -1
  2. package/dist/config.d.ts +13 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/lib/deletion-auditor.d.ts.map +1 -1
  6. package/dist/lib/deletion-auditor.js +1 -1
  7. package/dist/lib/deletion-auditor.js.map +1 -1
  8. package/dist/lib/env-sql-redactor.d.ts +1 -1
  9. package/dist/lib/env-sql-redactor.d.ts.map +1 -1
  10. package/dist/lib/env-sql-redactor.js +7 -72
  11. package/dist/lib/env-sql-redactor.js.map +1 -1
  12. package/dist/lib/lookup-sql.d.ts +108 -0
  13. package/dist/lib/lookup-sql.d.ts.map +1 -0
  14. package/dist/lib/lookup-sql.js +231 -0
  15. package/dist/lib/lookup-sql.js.map +1 -0
  16. package/dist/lib/natural-key-preflight.d.ts +86 -0
  17. package/dist/lib/natural-key-preflight.d.ts.map +1 -0
  18. package/dist/lib/natural-key-preflight.js +173 -0
  19. package/dist/lib/natural-key-preflight.js.map +1 -0
  20. package/dist/lib/record-dependency-analyzer.d.ts +9 -2
  21. package/dist/lib/record-dependency-analyzer.d.ts.map +1 -1
  22. package/dist/lib/record-dependency-analyzer.js +48 -71
  23. package/dist/lib/record-dependency-analyzer.js.map +1 -1
  24. package/dist/lib/schema-placeholders.d.ts +29 -0
  25. package/dist/lib/schema-placeholders.d.ts.map +1 -0
  26. package/dist/lib/schema-placeholders.js +72 -0
  27. package/dist/lib/schema-placeholders.js.map +1 -0
  28. package/dist/lib/sql-logger.d.ts +9 -1
  29. package/dist/lib/sql-logger.d.ts.map +1 -1
  30. package/dist/lib/sql-logger.js +12 -7
  31. package/dist/lib/sql-logger.js.map +1 -1
  32. package/dist/lib/sql-set-line.d.ts +26 -0
  33. package/dist/lib/sql-set-line.d.ts.map +1 -0
  34. package/dist/lib/sql-set-line.js +84 -0
  35. package/dist/lib/sql-set-line.js.map +1 -0
  36. package/dist/lib/sync-engine.d.ts +14 -2
  37. package/dist/lib/sync-engine.d.ts.map +1 -1
  38. package/dist/lib/sync-engine.js +33 -5
  39. package/dist/lib/sync-engine.js.map +1 -1
  40. package/dist/services/PushService.d.ts +21 -0
  41. package/dist/services/PushService.d.ts.map +1 -1
  42. package/dist/services/PushService.js +100 -20
  43. package/dist/services/PushService.js.map +1 -1
  44. package/dist/services/WatchService.d.ts +2 -0
  45. package/dist/services/WatchService.d.ts.map +1 -1
  46. package/dist/services/WatchService.js +19 -2
  47. package/dist/services/WatchService.js.map +1 -1
  48. package/package.json +15 -15
@@ -0,0 +1,231 @@
1
+ import { GenericDatabaseProvider } from '@memberjunction/generic-database-provider';
2
+ import { IsDateSQLType, IsUuidSQLType } from '@memberjunction/sql-dialect';
3
+ import { IsALevels, OwningLevel, SaveCallHashesIn, SetLinePattern, SqlLiteralsOf } from './sql-set-line.js';
4
+ /**
5
+ * Builds `(SELECT [PK] FROM [schema].[BaseTable] WHERE …)` for a lookup source. Each criterion is
6
+ * matched with `=` on the entity's own table (SQL Server's default collation is case-insensitive,
7
+ * as the push lookup is). `null` matches `IS NULL`. A criterion must be a column of the entity's
8
+ * own table: a virtual field or one an IS-A parent holds has no column there.
9
+ */
10
+ export class LookupSubqueryBuilder {
11
+ constructor(entityInfo) {
12
+ this.entityInfo = entityInfo;
13
+ }
14
+ Build(source) {
15
+ if (source.EnvSourced) {
16
+ return { Problem: 'its @lookup criteria use an @env value, which the log never holds' };
17
+ }
18
+ const info = this.entityInfo(source.EntityName);
19
+ if (!info) {
20
+ return { Problem: `entity '${source.EntityName}' was not found` };
21
+ }
22
+ if (info.PrimaryKeys.length !== 1) {
23
+ return { Problem: `'${source.EntityName}' does not have a single-column primary key` };
24
+ }
25
+ if (source.Criteria.length === 0) {
26
+ return { Problem: 'the @lookup has no criteria' };
27
+ }
28
+ const conditions = [];
29
+ for (const criterion of source.Criteria) {
30
+ const condition = this.condition(info, criterion);
31
+ if (condition.Problem !== undefined) {
32
+ return condition;
33
+ }
34
+ conditions.push(condition.Sql);
35
+ }
36
+ const key = info.FirstPrimaryKey.Name; // first-pk-ok: a single-column key was checked above; a lookup yields one value
37
+ return { Sql: `(SELECT [${key}] FROM [${info.SchemaName}].[${info.BaseTable}] WHERE ${conditions.join(' AND ')})` };
38
+ }
39
+ condition(info, criterion) {
40
+ const wanted = criterion.FieldName.trim().toLowerCase();
41
+ const field = info.Fields.find((candidate) => candidate.Name.toLowerCase() === wanted);
42
+ if (!field) {
43
+ return { Problem: `'${info.Name}' has no field '${criterion.FieldName}'` };
44
+ }
45
+ if (field.IsVirtual || info.ParentEntityFieldNames?.has(field.Name)) {
46
+ return { Problem: `${info.Name}.${field.Name} is not a column of table ${info.BaseTable}` };
47
+ }
48
+ if (typeof criterion.Value !== 'string') {
49
+ const nested = this.Build(criterion.Value);
50
+ return nested.Problem !== undefined ? nested : { Sql: `[${field.Name}] = ${nested.Sql}` };
51
+ }
52
+ if (criterion.Value.trim().toLowerCase() === 'null') {
53
+ return { Sql: `[${field.Name}] IS NULL` };
54
+ }
55
+ const literal = criterionLiteral(field, criterion.Value);
56
+ if (literal === null) {
57
+ return { Problem: `the value of ${info.Name}.${field.Name} cannot be written as a ${field.Type} literal` };
58
+ }
59
+ return { Sql: `[${field.Name}] = ${literal}` };
60
+ }
61
+ }
62
+ /** The SQL Server literal for a criterion value, or null when the value does not fit the field type. */
63
+ function criterionLiteral(field, value) {
64
+ const escaped = value.replace(/'/g, "''");
65
+ if (!field.NeedsQuotes) {
66
+ const type = field.Type.trim().toLowerCase();
67
+ const lower = value.trim().toLowerCase();
68
+ if (type === 'bit' || type === 'boolean') {
69
+ if (lower === 'true' || lower === '1') {
70
+ return '1';
71
+ }
72
+ if (lower === 'false' || lower === '0') {
73
+ return '0';
74
+ }
75
+ return null;
76
+ }
77
+ return /^-?\d+(\.\d+)?$/.test(value.trim()) ? value.trim() : null;
78
+ }
79
+ if (IsUuidSQLType(field.Type) || IsDateSQLType(field.Type)) {
80
+ return `'${escaped}'`;
81
+ }
82
+ return `N'${escaped}'`;
83
+ }
84
+ /**
85
+ * Replaces the logged SET lines of lookup-sourced fields with subqueries, for one push. Registrations
86
+ * are keyed by the save-call hash of the record (`GenericDatabaseProvider.SaveCallVariableHash`), so
87
+ * only the SET line of that record's save is rewritten. A registration stays for the whole push.
88
+ */
89
+ export class LookupSqlRewriter {
90
+ constructor(builder) {
91
+ this.linesByHash = new Map();
92
+ this.warnings = new Set();
93
+ /**
94
+ * The `SqlLoggingOptions.TransformStatement` function. It can run many times on the same text and
95
+ * on text that is never written. On an unexpected error it returns the text unchanged, so the log
96
+ * keeps the literal IDs, and keeps a warning.
97
+ */
98
+ this.Transform = (sql) => {
99
+ try {
100
+ return this.replaceSetLines(sql);
101
+ }
102
+ catch {
103
+ this.warnings.add('SQL log: a statement kept its literal lookup IDs because the rewrite to subqueries failed.');
104
+ return sql;
105
+ }
106
+ };
107
+ this.builder = builder;
108
+ }
109
+ /**
110
+ * Registers one field of one save call. `value` is the resolved ID the statement holds. Returns
111
+ * false (and keeps a warning) when no subquery can be built, so the log keeps the literal ID.
112
+ */
113
+ Register(entityName, fieldName, codeName, value, lookup, saveCallHash) {
114
+ const literals = SqlLiteralsOf(value);
115
+ if (literals.length === 0) {
116
+ return false;
117
+ }
118
+ const subquery = this.builder.Build(lookup);
119
+ if (subquery.Problem !== undefined || subquery.Sql === undefined) {
120
+ this.warnings.add(`SQL log: ${entityName}.${fieldName} is written with this database's ID because ${subquery.Problem} (${lookup.Expression}). A database where that row has another ID will not match it.`);
121
+ return false;
122
+ }
123
+ const hash = saveCallHash.toLowerCase();
124
+ let lines = this.linesByHash.get(hash);
125
+ if (!lines) {
126
+ lines = new Map();
127
+ this.linesByHash.set(hash, lines);
128
+ }
129
+ const key = [codeName, ...literals].join('\u0000');
130
+ // Case-insensitive: SQL Server returns upper-case UUIDs where a lookup can return either case
131
+ lines.set(key, { Pattern: SetLinePattern(codeName, hash, literals, 'gmi'), Subquery: subquery.Sql });
132
+ return true;
133
+ }
134
+ /**
135
+ * Registers each lookup-sourced field of the save statement of `entity`. A primary key is
136
+ * registered at every IS-A level, because each level's save sets it; another field at the level
137
+ * whose table holds it. Call it right before the save, so the hash uses the key values the
138
+ * provider hashes. `lookups` keys are matched without regard to case.
139
+ */
140
+ RegisterEntityLookups(entity, lookups) {
141
+ if (!lookups || lookups.size === 0) {
142
+ return;
143
+ }
144
+ const keyNames = new Set(entity.EntityInfo.PrimaryKeys.map((pk) => pk.Name));
145
+ for (const [key, lookup] of lookups) {
146
+ const fieldName = entity.GetFieldByName(key)?.Name;
147
+ if (!fieldName) {
148
+ continue;
149
+ }
150
+ const levels = keyNames.has(fieldName) ? IsALevels(entity) : [OwningLevel(entity, fieldName)];
151
+ for (const level of levels) {
152
+ this.registerLevelField(level, fieldName, lookup);
153
+ }
154
+ }
155
+ }
156
+ /**
157
+ * Registers the primary key of a record that a `@lookup:…?create` made, keyed by the lookup that
158
+ * made it, and keeps a warning: where no row matches, the replay passes a NULL ID, so the
159
+ * `IF NOT EXISTS` guard inserts the row with an ID that database generates.
160
+ */
161
+ RegisterLookupCreate(created, lookup) {
162
+ if (created.EntityInfo.PrimaryKeys.length !== 1) {
163
+ return;
164
+ }
165
+ // Criteria that were lookups themselves are foreign keys the create sets: they nest too
166
+ const nested = new Map();
167
+ for (const criterion of lookup.Criteria) {
168
+ if (typeof criterion.Value !== 'string') {
169
+ nested.set(criterion.FieldName, criterion.Value);
170
+ }
171
+ }
172
+ this.RegisterEntityLookups(created, nested);
173
+ const keyName = created.EntityInfo.FirstPrimaryKey.Name; // first-pk-ok: a single-column key was checked above
174
+ let registered = false;
175
+ for (const level of IsALevels(created)) {
176
+ registered = this.registerLevelField(level, keyName, lookup) || registered;
177
+ }
178
+ if (registered) {
179
+ this.warnings.add(`SQL log: the ${created.EntityInfo.Name} row that ${lookup.Expression} created is logged keyed by that lookup. On a database with no matching row the replay passes a NULL ID, so the IF NOT EXISTS guard inserts the row with an ID that database generates.`);
180
+ }
181
+ }
182
+ /** The warnings of this run, each once. */
183
+ Warnings() {
184
+ return [...this.warnings];
185
+ }
186
+ registerLevelField(level, fieldName, lookup) {
187
+ const field = level.GetFieldByName(fieldName);
188
+ if (!field) {
189
+ return false;
190
+ }
191
+ const levelInfo = level.EntityInfo;
192
+ const keyValues = level.PrimaryKey?.KeyValuePairs?.map((pair) => pair.Value) ?? [];
193
+ const saveCallHash = GenericDatabaseProvider.SaveCallVariableHash(levelInfo.SchemaName, levelInfo.BaseTable, keyValues);
194
+ return this.Register(levelInfo.Name, fieldName, field.EntityFieldInfo.CodeName, level.Get(fieldName), lookup, saveCallHash);
195
+ }
196
+ replaceSetLines(sql) {
197
+ if (this.linesByHash.size === 0) {
198
+ return sql;
199
+ }
200
+ let result = sql;
201
+ for (const hash of SaveCallHashesIn(sql)) {
202
+ for (const line of this.linesByHash.get(hash)?.values() ?? []) {
203
+ result = result.replace(line.Pattern, (_line, indent, variable) => `${indent}SET ${variable} = ${line.Subquery}`);
204
+ }
205
+ }
206
+ return result;
207
+ }
208
+ }
209
+ /**
210
+ * The lookup rewriter of one open SQL log, with the `SyncEngine.BeforeLookupCreateSaveSource` hook
211
+ * that registers each record a `?create` lookup makes.
212
+ */
213
+ export class LookupSqlLog {
214
+ constructor(engine) {
215
+ this.engine = engine;
216
+ this.Rewriter = new LookupSqlRewriter(new LookupSubqueryBuilder((name) => engine.GetEntityInfo(name)));
217
+ this.hook = (created, lookup) => this.Rewriter.RegisterLookupCreate(created, lookup);
218
+ engine.BeforeLookupCreateSaveSource = this.hook;
219
+ }
220
+ /** Clears the engine's hook when it is still this log's hook. */
221
+ Close() {
222
+ if (this.engine.BeforeLookupCreateSaveSource === this.hook) {
223
+ this.engine.BeforeLookupCreateSaveSource = null;
224
+ }
225
+ }
226
+ }
227
+ /** One `TransformStatement` that runs each transform in turn. */
228
+ export function ComposeStatementTransforms(...transforms) {
229
+ return (sql) => transforms.reduce((text, transform) => transform(text), sql);
230
+ }
231
+ //# sourceMappingURL=lookup-sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup-sql.js","sourceRoot":"","sources":["../../src/lib/lookup-sql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @fileoverview Pre-flight for a create that a unique constraint would reject (#4400).
3
+ *
4
+ * A seed record with a literal primary key that is not in the database is created with that key.
5
+ * When the database already has a row with the same natural key under another ID (CodeGen and
6
+ * other server-side code create rows with database-generated IDs), the create violates the unique
7
+ * constraint and the push stops on a driver error. This check runs first: for each unique key of
8
+ * the table, it looks the record's values up and, on a hit, reports the existing row's key so the
9
+ * seed can be re-keyed with `@lookup`.
10
+ * @module natural-key-preflight
11
+ */
12
+ import { type BaseEntity, type DatabaseProviderBase, type EntityFieldInfo, type EntityInfo, type IMetadataProvider, type UserInfo } from '@memberjunction/core';
13
+ /** One unique key of a table: its name and its columns in key order. */
14
+ export interface UniqueKeyColumns {
15
+ Name: string;
16
+ Columns: string[];
17
+ }
18
+ /** A row that already holds the natural key a create would add. */
19
+ export interface NaturalKeyConflict {
20
+ /** Unique constraint or index name. */
21
+ KeyName: string;
22
+ /** The entity's field names that make up the key. */
23
+ Fields: string[];
24
+ /** The primary key of the existing row. */
25
+ ExistingKey: Record<string, unknown>;
26
+ }
27
+ /** Reads unique keys and finds rows by them. */
28
+ export interface NaturalKeyReader {
29
+ /** The unique keys of the entity's table, other than the primary key. */
30
+ UniqueKeys(info: EntityInfo): Promise<UniqueKeyColumns[]>;
31
+ /** The primary key of a row whose fields equal `values`, or null when there is none. */
32
+ FindKey(info: EntityInfo, values: ReadonlyArray<{
33
+ Field: EntityFieldInfo;
34
+ Value: unknown;
35
+ }>): Promise<Record<string, unknown> | null>;
36
+ }
37
+ /** Finds the existing row, if any, that a create of `entity` would collide with on a unique key. */
38
+ export declare class NaturalKeyPreflight {
39
+ private readonly reader;
40
+ constructor(reader: NaturalKeyReader);
41
+ /**
42
+ * The first unique key whose values another row already holds, or null. A key is checked only
43
+ * when every one of its columns is a field of the entity with a non-null value and no column is
44
+ * part of the primary key.
45
+ */
46
+ Check(entity: BaseEntity): Promise<NaturalKeyConflict | null>;
47
+ private keyValues;
48
+ }
49
+ /** Row shape of the unique-key catalog queries. */
50
+ interface UniqueKeyCatalogRow {
51
+ IndexName: string;
52
+ ColumnName: string;
53
+ }
54
+ /**
55
+ * Reads unique keys from the database catalog (unfiltered unique indexes and unique constraints,
56
+ * not the primary key) and finds rows with `RunView` on the record's provider, so the lookup sees
57
+ * rows the push transaction wrote. Catalog reads go to the pool and are never logged. A catalog
58
+ * read that fails gives no keys, so the check is skipped rather than failing the push.
59
+ */
60
+ export declare class DatabaseNaturalKeyReader implements NaturalKeyReader {
61
+ private readonly provider;
62
+ private readonly contextUser;
63
+ private readonly rowProvider;
64
+ private readonly cache;
65
+ /**
66
+ * `rowProvider` is the provider rows are found on (the record's, so the read joins its
67
+ * transaction); `cache` (entity name → keys) can be shared by readers that find rows on
68
+ * different providers.
69
+ */
70
+ constructor(provider: DatabaseProviderBase, contextUser: UserInfo, rowProvider?: IMetadataProvider, cache?: Map<string, Promise<UniqueKeyColumns[]>>);
71
+ UniqueKeys(info: EntityInfo): Promise<UniqueKeyColumns[]>;
72
+ FindKey(info: EntityInfo, values: ReadonlyArray<{
73
+ Field: EntityFieldInfo;
74
+ Value: unknown;
75
+ }>): Promise<Record<string, unknown> | null>;
76
+ private readUniqueKeys;
77
+ private literal;
78
+ }
79
+ /** The catalog query listing a table's unfiltered unique keys other than the primary key, one row per column in key order. */
80
+ export declare function UniqueKeyCatalogSQL(platformKey: string, schemaName: string, tableName: string): string;
81
+ /** Catalog rows grouped into keys, in row order. */
82
+ export declare function GroupUniqueKeyRows(rows: ReadonlyArray<UniqueKeyCatalogRow>): UniqueKeyColumns[];
83
+ /** The pre-flight error for a conflict. `recordKey` is the record's key as it may be shown. */
84
+ export declare function NaturalKeyConflictMessage(entityName: string, recordKey: string, conflict: NaturalKeyConflict): string;
85
+ export {};
86
+ //# sourceMappingURL=natural-key-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-key-preflight.d.ts","sourceRoot":"","sources":["../../src/lib/natural-key-preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAW,KAAK,UAAU,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEzK,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC1D,wFAAwF;IACxF,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CACvI;AAED,oGAAoG;AACpG,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAE9B,MAAM,EAAE,gBAAgB;IAIpC;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAoBnE,OAAO,CAAC,SAAS;CAkBlB;AASD,mDAAmD;AACnD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAW;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2C;IAEjE;;;;OAIG;gBAED,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,QAAQ,EACrB,WAAW,CAAC,EAAE,iBAAiB,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAa;IAQ7D,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IASnD,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;YAiB7H,cAAc;IAc5B,OAAO,CAAC,OAAO;CAahB;AAED,8HAA8H;AAC9H,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBtG;AAED,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,CAAC,mBAAmB,CAAC,GAAG,gBAAgB,EAAE,CAQ/F;AAED,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAYrH"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * @fileoverview Pre-flight for a create that a unique constraint would reject (#4400).
3
+ *
4
+ * A seed record with a literal primary key that is not in the database is created with that key.
5
+ * When the database already has a row with the same natural key under another ID (CodeGen and
6
+ * other server-side code create rows with database-generated IDs), the create violates the unique
7
+ * constraint and the push stops on a driver error. This check runs first: for each unique key of
8
+ * the table, it looks the record's values up and, on a hit, reports the existing row's key so the
9
+ * seed can be re-keyed with `@lookup`.
10
+ * @module natural-key-preflight
11
+ */
12
+ import { RunView } from '@memberjunction/core';
13
+ /** Finds the existing row, if any, that a create of `entity` would collide with on a unique key. */
14
+ export class NaturalKeyPreflight {
15
+ constructor(reader) {
16
+ this.reader = reader;
17
+ }
18
+ /**
19
+ * The first unique key whose values another row already holds, or null. A key is checked only
20
+ * when every one of its columns is a field of the entity with a non-null value and no column is
21
+ * part of the primary key.
22
+ */
23
+ async Check(entity) {
24
+ const info = entity.EntityInfo;
25
+ const keys = await this.reader.UniqueKeys(info);
26
+ if (keys.length === 0) {
27
+ return null;
28
+ }
29
+ const keyNames = new Set(info.PrimaryKeys.map((pk) => pk.Name.toLowerCase()));
30
+ for (const key of keys) {
31
+ const values = this.keyValues(entity, key, keyNames);
32
+ if (!values) {
33
+ continue;
34
+ }
35
+ const existing = await this.reader.FindKey(info, values);
36
+ if (existing && !samePrimaryKey(entity, existing)) {
37
+ return { KeyName: key.Name, Fields: values.map((value) => value.Field.Name), ExistingKey: existing };
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ keyValues(entity, key, keyNames) {
43
+ if (key.Columns.length === 0) {
44
+ return null;
45
+ }
46
+ const values = [];
47
+ for (const column of key.Columns) {
48
+ if (keyNames.has(column.toLowerCase())) {
49
+ return null;
50
+ }
51
+ const field = entity.EntityInfo.Fields.find((candidate) => candidate.Name.toLowerCase() === column.toLowerCase());
52
+ const value = field ? entity.Get(field.Name) : undefined;
53
+ if (!field || value === null || value === undefined) {
54
+ return null;
55
+ }
56
+ values.push({ Field: field, Value: value });
57
+ }
58
+ return values;
59
+ }
60
+ }
61
+ /** True when `existing` is the entity's own key (compared without regard to case). */
62
+ function samePrimaryKey(entity, existing) {
63
+ return entity.EntityInfo.PrimaryKeys.every((pk) => String(entity.Get(pk.Name) ?? '').trim().toLowerCase() === String(existing[pk.Name] ?? '').trim().toLowerCase());
64
+ }
65
+ /**
66
+ * Reads unique keys from the database catalog (unfiltered unique indexes and unique constraints,
67
+ * not the primary key) and finds rows with `RunView` on the record's provider, so the lookup sees
68
+ * rows the push transaction wrote. Catalog reads go to the pool and are never logged. A catalog
69
+ * read that fails gives no keys, so the check is skipped rather than failing the push.
70
+ */
71
+ export class DatabaseNaturalKeyReader {
72
+ /**
73
+ * `rowProvider` is the provider rows are found on (the record's, so the read joins its
74
+ * transaction); `cache` (entity name → keys) can be shared by readers that find rows on
75
+ * different providers.
76
+ */
77
+ constructor(provider, contextUser, rowProvider, cache = new Map()) {
78
+ this.provider = provider;
79
+ this.contextUser = contextUser;
80
+ this.rowProvider = rowProvider;
81
+ this.cache = cache;
82
+ }
83
+ UniqueKeys(info) {
84
+ let keys = this.cache.get(info.Name);
85
+ if (!keys) {
86
+ keys = this.readUniqueKeys(info);
87
+ this.cache.set(info.Name, keys);
88
+ }
89
+ return keys;
90
+ }
91
+ async FindKey(info, values) {
92
+ // Quoted, so a reserved-word or spaced column name still filters (rather than failing the read)
93
+ const filter = values.map(({ Field, Value }) => `${this.provider.QuoteIdentifier(Field.Name)} = ${this.literal(Field, Value)}`).join(' AND ');
94
+ const rv = this.rowProvider ? RunView.FromMetadataProvider(this.rowProvider) : new RunView();
95
+ const result = await rv.RunView({
96
+ EntityName: info.Name,
97
+ ExtraFilter: filter,
98
+ Fields: info.PrimaryKeys.map((pk) => pk.Name),
99
+ MaxRows: 1,
100
+ ResultType: 'simple',
101
+ }, this.contextUser);
102
+ return result.Success && result.Results.length > 0 ? result.Results[0] : null;
103
+ }
104
+ async readUniqueKeys(info) {
105
+ try {
106
+ const rows = await this.provider.ExecuteSQL(UniqueKeyCatalogSQL(this.provider.PlatformKey, info.SchemaName, info.BaseTable), undefined, { ignoreLogging: true, isMutation: false, ignoreAmbientTransaction: true }, this.contextUser);
107
+ return GroupUniqueKeyRows(rows);
108
+ }
109
+ catch {
110
+ return [];
111
+ }
112
+ }
113
+ literal(field, value) {
114
+ if (value instanceof Date) {
115
+ return `'${value.toISOString()}'`;
116
+ }
117
+ if (typeof value === 'boolean') {
118
+ if (this.provider.PlatformKey === 'postgresql') {
119
+ return value ? 'true' : 'false';
120
+ }
121
+ return value ? '1' : '0';
122
+ }
123
+ const text = String(value).replace(/'/g, "''");
124
+ return field.NeedsQuotes ? `'${text}'` : text;
125
+ }
126
+ }
127
+ /** The catalog query listing a table's unfiltered unique keys other than the primary key, one row per column in key order. */
128
+ export function UniqueKeyCatalogSQL(platformKey, schemaName, tableName) {
129
+ const schema = schemaName.replace(/'/g, "''");
130
+ const table = tableName.replace(/'/g, "''");
131
+ if (platformKey === 'postgresql') {
132
+ return `SELECT ix.relname AS "IndexName", a.attname AS "ColumnName"
133
+ FROM pg_index x
134
+ JOIN pg_class t ON t.oid = x.indrelid
135
+ JOIN pg_namespace n ON n.oid = t.relnamespace
136
+ JOIN pg_class ix ON ix.oid = x.indexrelid
137
+ JOIN LATERAL unnest(x.indkey) WITH ORDINALITY AS k(attnum, ord) ON true
138
+ JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
139
+ WHERE x.indisunique AND NOT x.indisprimary AND x.indpred IS NULL
140
+ AND n.nspname = '${schema}' AND t.relname = '${table}'
141
+ ORDER BY ix.relname, k.ord`;
142
+ }
143
+ return `SELECT i.name AS IndexName, c.name AS ColumnName
144
+ FROM sys.indexes i
145
+ JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
146
+ JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
147
+ WHERE i.object_id = OBJECT_ID(N'[${schema.replace(/]/g, ']]')}].[${table.replace(/]/g, ']]')}]')
148
+ AND i.is_unique = 1 AND i.is_primary_key = 0 AND i.has_filter = 0 AND ic.is_included_column = 0
149
+ ORDER BY i.name, ic.key_ordinal`;
150
+ }
151
+ /** Catalog rows grouped into keys, in row order. */
152
+ export function GroupUniqueKeyRows(rows) {
153
+ const byName = new Map();
154
+ for (const row of rows) {
155
+ const columns = byName.get(row.IndexName) ?? [];
156
+ columns.push(row.ColumnName);
157
+ byName.set(row.IndexName, columns);
158
+ }
159
+ return [...byName].map(([Name, Columns]) => ({ Name, Columns }));
160
+ }
161
+ /** The pre-flight error for a conflict. `recordKey` is the record's key as it may be shown. */
162
+ export function NaturalKeyConflictMessage(entityName, recordKey, conflict) {
163
+ const existing = Object.entries(conflict.ExistingKey)
164
+ .map(([field, value]) => `${field}=${String(value)}`)
165
+ .join(', ');
166
+ const fields = conflict.Fields.join(', ');
167
+ const example = conflict.Fields.map((field) => `${field}=…`).join('&');
168
+ return (`${entityName}: no row has primary key {${recordKey}}, but row {${existing}} already has the same ${fields} ` +
169
+ `(unique key ${conflict.KeyName}), so creating this record would violate it. That row's ID was made by this ` +
170
+ `database, so a literal ID in metadata cannot match it. Re-key the record's primaryKey with @lookup on ` +
171
+ `${fields}, for example "@lookup:${entityName}.${example}".`);
172
+ }
173
+ //# sourceMappingURL=natural-key-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-key-preflight.js","sourceRoot":"","sources":["../../src/lib/natural-key-preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,OAAO,EAA4H,MAAM,sBAAsB,CAAC;AA0BzK,oGAAoG;AACpG,MAAM,OAAO,mBAAmB;IAG9B,YAAY,MAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,MAAkB;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACzD,IAAI,QAAQ,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAClD,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;YACvG,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,SAAS,CAAC,MAAkB,EAAE,GAAqB,EAAE,QAA6B;QACxF,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAsD,EAAE,CAAC;QACrE,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;YAClH,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACzD,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACpD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,sFAAsF;AACtF,SAAS,cAAc,CAAC,MAAkB,EAAE,QAAiC;IAC3E,OAAO,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CACxC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CACxH,CAAC;AACJ,CAAC;AAQD;;;;;GAKG;AACH,MAAM,OAAO,wBAAwB;IAMnC;;;;OAIG;IACH,YACE,QAA8B,EAC9B,WAAqB,EACrB,WAA+B,EAC/B,QAAkD,IAAI,GAAG,EAAE;QAE3D,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,UAAU,CAAC,IAAgB;QACzB,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAgB,EAAE,MAAiE;QAC/F,gGAAgG;QAChG,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9I,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;QAC7F,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAC7B;YACE,UAAU,EAAE,IAAI,CAAC,IAAI;YACrB,WAAW,EAAE,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;YAC7C,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,QAAQ;SACrB,EACD,IAAI,CAAC,WAAW,CACjB,CAAC;QACF,OAAO,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChF,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAgB;QAC3C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CACzC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAC/E,SAAS,EACT,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,wBAAwB,EAAE,IAAI,EAAE,EAC1E,IAAI,CAAC,WAAW,CACjB,CAAC;YACF,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,KAAsB,EAAE,KAAc;QACpD,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;YAC1B,OAAO,IAAI,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;gBAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAClC,CAAC;YACD,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC3B,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;CACF;AAED,8HAA8H;AAC9H,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,UAAkB,EAAE,SAAiB;IAC5F,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,WAAW,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO;;;;;;;;qBAQU,MAAM,sBAAsB,KAAK;2BAC3B,CAAC;IAC1B,CAAC;IACD,OAAO;;;;mCAI0B,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;;gCAE5D,CAAC;AACjC,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,kBAAkB,CAAC,IAAwC;IACzE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,yBAAyB,CAAC,UAAkB,EAAE,SAAiB,EAAE,QAA4B;IAC3G,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;SACpD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvE,OAAO,CACL,GAAG,UAAU,6BAA6B,SAAS,eAAe,QAAQ,0BAA0B,MAAM,GAAG;QAC7G,eAAe,QAAQ,CAAC,OAAO,8EAA8E;QAC7G,wGAAwG;QACxG,GAAG,MAAM,0BAA0B,UAAU,IAAI,OAAO,IAAI,CAC7D,CAAC;AACJ,CAAC"}
@@ -44,6 +44,13 @@ export interface DependencyAnalysisResult {
44
44
  dependencyGraph: Map<string, Set<string>>;
45
45
  dependencyLevels?: FlattenedRecord[][];
46
46
  }
47
+ /**
48
+ * Depth-first topological order: each record comes after every record it depends on that is in
49
+ * `byId`. Records with no dependencies are started first, then the rest in input order. A cycle is
50
+ * broken where the walk meets it (cycles are reported separately); a dependency missing from `byId`
51
+ * is skipped.
52
+ */
53
+ export declare function DependencyOrder(records: FlattenedRecord[], byId: ReadonlyMap<string, FlattenedRecord>): FlattenedRecord[];
47
54
  /**
48
55
  * Analyzes and sorts records based on their dependencies
49
56
  */
@@ -172,9 +179,9 @@ export declare class RecordDependencyAnalyzer {
172
179
  *
173
180
  * This is simply the reverse of the forward topological sort used for creates.
174
181
  */
175
- ReverseTopologicalSort(records: FlattenedRecord[], reverseDependencies: Map<string, ReverseDependency[]>): FlattenedRecord[][];
182
+ ReverseTopologicalSort(records: FlattenedRecord[]): FlattenedRecord[][];
176
183
  /** @deprecated Use {@link ReverseTopologicalSort}. */
177
- reverseTopologicalSort(records: FlattenedRecord[], reverseDependencies: Map<string, ReverseDependency[]>): FlattenedRecord[][];
184
+ reverseTopologicalSort(records: FlattenedRecord[]): FlattenedRecord[][];
178
185
  /**
179
186
  * Find all transitive dependents of a set of records
180
187
  * This is useful for finding all records that must be deleted when deleting a parent
@@ -1 +1 @@
1
- {"version":3,"file":"record-dependency-analyzer.d.ts","sourceRoot":"","sources":["../../src/lib/record-dependency-analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"record-dependency-analyzer.d.ts","sourceRoot":"","sources":["../../src/lib/record-dependency-analyzer.ts"],"names":[],"mappings":"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"}