@memberjunction/core-entities-server 6.2.0-edge.6 → 6.2.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.
Files changed (159) hide show
  1. package/README.md +155 -100
  2. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts +2 -0
  3. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts.map +1 -1
  4. package/dist/custom/MJAIAgentExampleEntityServer.server.js +8 -5
  5. package/dist/custom/MJAIAgentExampleEntityServer.server.js.map +1 -1
  6. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts +2 -0
  7. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts.map +1 -1
  8. package/dist/custom/MJAIAgentNoteEntityServer.server.js +8 -5
  9. package/dist/custom/MJAIAgentNoteEntityServer.server.js.map +1 -1
  10. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts +17 -0
  11. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts.map +1 -0
  12. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js +71 -0
  13. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js.map +1 -0
  14. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts +8 -22
  15. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts.map +1 -1
  16. package/dist/custom/MJAIAgentSessionEntityServer.server.js +24 -1
  17. package/dist/custom/MJAIAgentSessionEntityServer.server.js.map +1 -1
  18. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts +23 -0
  19. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts.map +1 -0
  20. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js +53 -0
  21. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js.map +1 -0
  22. package/dist/custom/MJAIPromptEntityServer.server.d.ts.map +1 -1
  23. package/dist/custom/MJAIPromptEntityServer.server.js +2 -1
  24. package/dist/custom/MJAIPromptEntityServer.server.js.map +1 -1
  25. package/dist/custom/MJBrandKitEntityServer.server.d.ts +14 -0
  26. package/dist/custom/MJBrandKitEntityServer.server.d.ts.map +1 -0
  27. package/dist/custom/MJBrandKitEntityServer.server.js +75 -0
  28. package/dist/custom/MJBrandKitEntityServer.server.js.map +1 -0
  29. package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -1
  30. package/dist/custom/MJCompanyIntegrationEntityServer.server.js +1 -0
  31. package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -1
  32. package/dist/custom/MJComponentEntityServer.server.d.ts +2 -0
  33. package/dist/custom/MJComponentEntityServer.server.d.ts.map +1 -1
  34. package/dist/custom/MJComponentEntityServer.server.js +5 -1
  35. package/dist/custom/MJComponentEntityServer.server.js.map +1 -1
  36. package/dist/custom/MJEntityDocumentEntityServer.server.d.ts.map +1 -1
  37. package/dist/custom/MJEntityDocumentEntityServer.server.js +1 -0
  38. package/dist/custom/MJEntityDocumentEntityServer.server.js.map +1 -1
  39. package/dist/custom/MJListDetailEntityServer.server.d.ts.map +1 -1
  40. package/dist/custom/MJListDetailEntityServer.server.js +1 -0
  41. package/dist/custom/MJListDetailEntityServer.server.js.map +1 -1
  42. package/dist/custom/MJQueryEntityServer.server.d.ts +177 -47
  43. package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
  44. package/dist/custom/MJQueryEntityServer.server.js +465 -162
  45. package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
  46. package/dist/custom/MJQuerySQLEntityServer.server.d.ts +15 -18
  47. package/dist/custom/MJQuerySQLEntityServer.server.d.ts.map +1 -1
  48. package/dist/custom/MJQuerySQLEntityServer.server.js +34 -42
  49. package/dist/custom/MJQuerySQLEntityServer.server.js.map +1 -1
  50. package/dist/custom/MJTagEntityServer.server.d.ts +2 -0
  51. package/dist/custom/MJTagEntityServer.server.d.ts.map +1 -1
  52. package/dist/custom/MJTagEntityServer.server.js +13 -7
  53. package/dist/custom/MJTagEntityServer.server.js.map +1 -1
  54. package/dist/custom/MJUserRoutineEntityServer.server.d.ts.map +1 -1
  55. package/dist/custom/MJUserRoutineEntityServer.server.js +8 -1
  56. package/dist/custom/MJUserRoutineEntityServer.server.js.map +1 -1
  57. package/dist/custom/query-extraction/childRowWriter.d.ts +77 -0
  58. package/dist/custom/query-extraction/childRowWriter.d.ts.map +1 -0
  59. package/dist/custom/query-extraction/childRowWriter.js +277 -0
  60. package/dist/custom/query-extraction/childRowWriter.js.map +1 -0
  61. package/dist/custom/query-extraction/compositionTargets.d.ts +40 -0
  62. package/dist/custom/query-extraction/compositionTargets.d.ts.map +1 -0
  63. package/dist/custom/query-extraction/compositionTargets.js +99 -0
  64. package/dist/custom/query-extraction/compositionTargets.js.map +1 -0
  65. package/dist/custom/query-extraction/declared.d.ts +79 -0
  66. package/dist/custom/query-extraction/declared.d.ts.map +1 -0
  67. package/dist/custom/query-extraction/declared.js +91 -0
  68. package/dist/custom/query-extraction/declared.js.map +1 -0
  69. package/dist/custom/query-extraction/describeFacts.d.ts +40 -0
  70. package/dist/custom/query-extraction/describeFacts.d.ts.map +1 -0
  71. package/dist/custom/query-extraction/describeFacts.js +225 -0
  72. package/dist/custom/query-extraction/describeFacts.js.map +1 -0
  73. package/dist/custom/query-extraction/descriptionPass.d.ts +23 -0
  74. package/dist/custom/query-extraction/descriptionPass.d.ts.map +1 -0
  75. package/dist/custom/query-extraction/descriptionPass.js +95 -0
  76. package/dist/custom/query-extraction/descriptionPass.js.map +1 -0
  77. package/dist/custom/query-extraction/extractQuery.d.ts +25 -0
  78. package/dist/custom/query-extraction/extractQuery.d.ts.map +1 -0
  79. package/dist/custom/query-extraction/extractQuery.js +146 -0
  80. package/dist/custom/query-extraction/extractQuery.js.map +1 -0
  81. package/dist/custom/query-extraction/extractionTypes.d.ts +133 -0
  82. package/dist/custom/query-extraction/extractionTypes.d.ts.map +1 -0
  83. package/dist/custom/query-extraction/extractionTypes.js +2 -0
  84. package/dist/custom/query-extraction/extractionTypes.js.map +1 -0
  85. package/dist/custom/query-extraction/index.d.ts +16 -0
  86. package/dist/custom/query-extraction/index.d.ts.map +1 -1
  87. package/dist/custom/query-extraction/index.js +11 -1
  88. package/dist/custom/query-extraction/index.js.map +1 -1
  89. package/dist/custom/query-extraction/pipeline.d.ts +6 -2
  90. package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
  91. package/dist/custom/query-extraction/pipeline.js +21 -14
  92. package/dist/custom/query-extraction/pipeline.js.map +1 -1
  93. package/dist/custom/query-extraction/resolve.d.ts +7 -2
  94. package/dist/custom/query-extraction/resolve.d.ts.map +1 -1
  95. package/dist/custom/query-extraction/resolve.js +17 -14
  96. package/dist/custom/query-extraction/resolve.js.map +1 -1
  97. package/dist/custom/query-extraction/sourceBinding.d.ts +57 -0
  98. package/dist/custom/query-extraction/sourceBinding.d.ts.map +1 -0
  99. package/dist/custom/query-extraction/sourceBinding.js +104 -0
  100. package/dist/custom/query-extraction/sourceBinding.js.map +1 -0
  101. package/dist/custom/query-extraction/sync.d.ts +27 -3
  102. package/dist/custom/query-extraction/sync.d.ts.map +1 -1
  103. package/dist/custom/query-extraction/sync.js +69 -44
  104. package/dist/custom/query-extraction/sync.js.map +1 -1
  105. package/dist/custom/query-extraction/templateFacts.d.ts +62 -0
  106. package/dist/custom/query-extraction/templateFacts.d.ts.map +1 -0
  107. package/dist/custom/query-extraction/templateFacts.js +229 -0
  108. package/dist/custom/query-extraction/templateFacts.js.map +1 -0
  109. package/dist/custom/query-extraction/types.d.ts +4 -0
  110. package/dist/custom/query-extraction/types.d.ts.map +1 -1
  111. package/dist/custom/query-refresh/QueryExtractionService.d.ts +54 -0
  112. package/dist/custom/query-refresh/QueryExtractionService.d.ts.map +1 -0
  113. package/dist/custom/query-refresh/QueryExtractionService.js +207 -0
  114. package/dist/custom/query-refresh/QueryExtractionService.js.map +1 -0
  115. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts +28 -0
  116. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts.map +1 -0
  117. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js +106 -0
  118. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js.map +1 -0
  119. package/dist/custom/query-refresh/index.d.ts +14 -0
  120. package/dist/custom/query-refresh/index.d.ts.map +1 -0
  121. package/dist/custom/query-refresh/index.js +10 -0
  122. package/dist/custom/query-refresh/index.js.map +1 -0
  123. package/dist/custom/query-refresh/queryRebind.d.ts +33 -0
  124. package/dist/custom/query-refresh/queryRebind.d.ts.map +1 -0
  125. package/dist/custom/query-refresh/queryRebind.js +85 -0
  126. package/dist/custom/query-refresh/queryRebind.js.map +1 -0
  127. package/dist/custom/query-refresh/refreshAuthorization.d.ts +29 -0
  128. package/dist/custom/query-refresh/refreshAuthorization.d.ts.map +1 -0
  129. package/dist/custom/query-refresh/refreshAuthorization.js +66 -0
  130. package/dist/custom/query-refresh/refreshAuthorization.js.map +1 -0
  131. package/dist/custom/query-refresh/refreshFormat.d.ts +16 -0
  132. package/dist/custom/query-refresh/refreshFormat.d.ts.map +1 -0
  133. package/dist/custom/query-refresh/refreshFormat.js +67 -0
  134. package/dist/custom/query-refresh/refreshFormat.js.map +1 -0
  135. package/dist/custom/query-refresh/refreshOrder.d.ts +25 -0
  136. package/dist/custom/query-refresh/refreshOrder.d.ts.map +1 -0
  137. package/dist/custom/query-refresh/refreshOrder.js +95 -0
  138. package/dist/custom/query-refresh/refreshOrder.js.map +1 -0
  139. package/dist/custom/query-refresh/refreshSelection.d.ts +15 -0
  140. package/dist/custom/query-refresh/refreshSelection.d.ts.map +1 -0
  141. package/dist/custom/query-refresh/refreshSelection.js +99 -0
  142. package/dist/custom/query-refresh/refreshSelection.js.map +1 -0
  143. package/dist/custom/query-refresh/refreshTypes.d.ts +81 -0
  144. package/dist/custom/query-refresh/refreshTypes.d.ts.map +1 -0
  145. package/dist/custom/query-refresh/refreshTypes.js +5 -0
  146. package/dist/custom/query-refresh/refreshTypes.js.map +1 -0
  147. package/dist/custom/util.d.ts +8 -0
  148. package/dist/custom/util.d.ts.map +1 -1
  149. package/dist/custom/util.js +18 -1
  150. package/dist/custom/util.js.map +1 -1
  151. package/dist/engines/QueryEngineServer.d.ts +4 -1
  152. package/dist/engines/QueryEngineServer.d.ts.map +1 -1
  153. package/dist/engines/QueryEngineServer.js +10 -7
  154. package/dist/engines/QueryEngineServer.js.map +1 -1
  155. package/dist/index.d.ts +4 -0
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +4 -0
  158. package/dist/index.js.map +1 -1
  159. package/package.json +30 -30
@@ -0,0 +1,277 @@
1
+ import { RunInEntityTransaction, RunMaybeSerial } from "@memberjunction/core";
2
+ import { EscapeSQLString, NormalizeUUID, UUIDsEqual } from "@memberjunction/global";
3
+ /**
4
+ * Brings a query's child rows in line with its extracted facts, keeping what people authored.
5
+ *
6
+ * **Facts** are corrected on every row, including declared and `Manual` ones: a field's name
7
+ * casing, sequence, types, nullability, source and computed flag; whether a parameter exists
8
+ * (and its name casing); which entities and dependencies the query has.
9
+ *
10
+ * **Annotations** are never overwritten when authored (`DetectionMethod` `Manual`, or a
11
+ * non-empty value): descriptions, `ComputationDescription`, `IsSummary` / `SummaryDescription`,
12
+ * and a `Manual` parameter's type, required flag, default, sample, validation filters and
13
+ * server-set flag. A doc-comment description is authored too: it fills an empty description and
14
+ * replaces one extraction or an LLM wrote.
15
+ *
16
+ * An authored parameter the SQL no longer uses is kept (extraction flags it on the query); an
17
+ * auto-detected one is deleted. Rows keep their IDs. A `null` fact collection leaves its rows as
18
+ * they are. Existing rows are read from the database on the caller's provider, never a cache, so
19
+ * rows written earlier in the same transaction are seen.
20
+ *
21
+ * The writes are one unit of work: they run in an entity transaction on the caller's provider,
22
+ * which joins the caller's transaction when one is open (a nested scope), so a failed write rolls
23
+ * every write of this call back and throws. A provider without entity transactions (a client)
24
+ * writes without one.
25
+ *
26
+ * With `DryRun` the same changes are worked out and reported, and nothing is written.
27
+ */
28
+ export async function WriteExtractedChildRows(context, result) {
29
+ const stored = await loadStoredChildRows(context);
30
+ const summary = { Added: 0, Updated: 0, Removed: 0, Changes: [], FlaggedParameters: [], FieldsWithoutDescription: [], ParametersWithoutDescription: [] };
31
+ const writes = [];
32
+ if (result.Fields)
33
+ writes.push(...await fieldWrites(context, stored.Fields, result.Fields, summary));
34
+ writes.push(...await parameterWrites(context, stored.Parameters, result.Parameters, summary));
35
+ if (result.Entities)
36
+ writes.push(...await entityWrites(context, stored.Entities, result.Entities, summary));
37
+ if (result.Dependencies)
38
+ writes.push(...await dependencyWrites(context, stored.Dependencies, result.Dependencies, summary));
39
+ if (context.DryRun || writes.length === 0)
40
+ return summary;
41
+ await RunInEntityTransaction(context.Provider, () => runWrites(context, writes));
42
+ return summary;
43
+ }
44
+ /** Runs the writes; throws when any of them failed, so the enclosing transaction rolls them all back. */
45
+ async function runWrites(context, writes) {
46
+ const outcomes = await RunMaybeSerial(context.Provider, [...writes]);
47
+ const failed = outcomes.filter(ok => !ok).length;
48
+ if (failed > 0)
49
+ throw new Error(`Query ${context.QueryID}: ${failed} of ${writes.length} child-row writes failed; none of them were kept.`);
50
+ }
51
+ async function loadStoredChildRows(context) {
52
+ const filter = `QueryID='${EscapeSQLString(context.QueryID)}'`;
53
+ const load = async (entityName) => {
54
+ const result = await context.Provider.RunView({ EntityName: entityName, ExtraFilter: filter, ResultType: 'entity_object', BypassCache: true, IgnoreMaxRows: true }, context.User);
55
+ if (!result.Success)
56
+ throw new Error(`Could not read the stored ${entityName} of query ${context.QueryID}: ${result.ErrorMessage}`);
57
+ return result.Results ?? [];
58
+ };
59
+ const [fields, parameters, entities, dependencies] = await Promise.all([
60
+ load('MJ: Query Fields'),
61
+ load('MJ: Query Parameters'),
62
+ load('MJ: Query Entities'),
63
+ load('MJ: Query Dependencies'),
64
+ ]);
65
+ return { Fields: fields, Parameters: parameters, Entities: entities, Dependencies: dependencies };
66
+ }
67
+ /**
68
+ * A write for `row` when it has unsaved changes; counts and records it as added or updated.
69
+ *
70
+ * `alsoChanged` names columns that changed although the entity's dirty check does not see it: a
71
+ * nullable bit column going between `null` and `false` reads as unchanged there. Such a row is
72
+ * still written (ignoring the dirty state) and the column is reported.
73
+ */
74
+ function saveIfDirty(row, summary, label, alsoChanged = []) {
75
+ if (row.IsSaved && !row.Dirty && alsoChanged.length === 0)
76
+ return [];
77
+ const action = row.IsSaved ? 'Updated' : 'Added';
78
+ if (row.IsSaved)
79
+ summary.Updated++;
80
+ else
81
+ summary.Added++;
82
+ const dirtyColumns = row.IsSaved ? row.Fields.filter(f => f.Dirty).map(f => f.Name) : [];
83
+ const changedColumns = row.IsSaved ? [...dirtyColumns, ...alsoChanged.filter(c => !dirtyColumns.includes(c))] : [];
84
+ summary.Changes.push({ ...changeOf(label, action), ChangedColumns: changedColumns });
85
+ const ignoreDirtyState = row.IsSaved && !row.Dirty;
86
+ return [() => row.Save(ignoreDirtyState ? { IgnoreDirtyState: true } : undefined)];
87
+ }
88
+ function deleteRows(rows, summary, labelOf) {
89
+ summary.Removed += rows.length;
90
+ for (const row of rows)
91
+ summary.Changes.push(changeOf(labelOf(row), 'Removed'));
92
+ return rows.map(row => () => row.Delete());
93
+ }
94
+ function changeOf(label, action) {
95
+ return { Collection: label.Collection, Action: action, Name: label.Name, ChangedColumns: [], SourceEntityFieldID: label.SourceEntityFieldID ?? null };
96
+ }
97
+ function fieldLabel(row) {
98
+ return { Collection: 'Fields', Name: row.Name, SourceEntityFieldID: row.SourceEntityFieldID };
99
+ }
100
+ function parameterLabel(row) {
101
+ return { Collection: 'Parameters', Name: row.Name };
102
+ }
103
+ function byLowerName(rows) {
104
+ return new Map(rows.map(r => [r.Name.toLowerCase(), r]));
105
+ }
106
+ function isEmpty(value) {
107
+ return !value || value.trim().length === 0;
108
+ }
109
+ // ─── Fields ─────────────────────────────────────────────────────────────────
110
+ async function fieldWrites(context, stored, facts, summary) {
111
+ const existing = byLowerName(stored);
112
+ const writes = [];
113
+ for (const fact of facts) {
114
+ let row = existing.get(fact.Name.toLowerCase());
115
+ existing.delete(fact.Name.toLowerCase());
116
+ if (!row)
117
+ row = await newRow(context, 'MJ: Query Fields', r => newField(r, context.QueryID, fact));
118
+ else
119
+ applyFieldAnnotations(row, fact);
120
+ const nullabilityChanged = row.IsSaved && (row.IsNullable ?? null) !== (fact.IsNullable ?? null);
121
+ ApplyFieldFacts(row, fact);
122
+ writes.push(...saveIfDirty(row, summary, fieldLabel(row), nullabilityChanged ? ['IsNullable'] : []));
123
+ if (isEmpty(row.Description))
124
+ summary.FieldsWithoutDescription.push(row.Name);
125
+ }
126
+ return [...writes, ...deleteRows([...existing.values()], summary, fieldLabel)];
127
+ }
128
+ function newField(row, queryID, fact) {
129
+ row.QueryID = queryID;
130
+ row.Description = fact.DocDescription ?? fact.SourceDescription;
131
+ row.IsSummary = false;
132
+ row.DetectionMethod = 'Database';
133
+ }
134
+ /**
135
+ * Sets a field row's facts (name casing, sequence, types, nullability, computed flag, source) from
136
+ * the extracted fact, leaving its annotations alone.
137
+ */
138
+ export function ApplyFieldFacts(row, fact) {
139
+ row.Name = fact.Name;
140
+ row.Sequence = fact.Sequence;
141
+ row.SQLBaseType = fact.SQLBaseType;
142
+ row.SQLFullType = fact.SQLFullType;
143
+ row.IsNullable = fact.IsNullable;
144
+ row.IsComputed = fact.IsComputed;
145
+ row.SourceEntityID = fact.SourceEntityID;
146
+ row.SourceEntityFieldID = fact.SourceEntityFieldID;
147
+ row.SourceFieldName = fact.SourceFieldName;
148
+ row.SourceObjectName = fact.SourceObjectName;
149
+ }
150
+ /** A stored field's description and detection method: authored ones kept, a doc comment applied. */
151
+ function applyFieldAnnotations(row, fact) {
152
+ const authored = row.DetectionMethod === 'Manual';
153
+ if (fact.DocDescription !== null && (!authored || isEmpty(row.Description)))
154
+ row.Description = fact.DocDescription;
155
+ if (!authored && row.DetectionMethod !== 'AI')
156
+ row.DetectionMethod = 'Database';
157
+ if (row.DetectionMethod === 'AI' && fact.DocDescription !== null)
158
+ row.DetectionMethod = 'Database';
159
+ }
160
+ // ─── Parameters ─────────────────────────────────────────────────────────────
161
+ async function parameterWrites(context, stored, facts, summary) {
162
+ const existing = byLowerName(stored);
163
+ const writes = [];
164
+ for (const fact of facts) {
165
+ let row = existing.get(fact.Name.toLowerCase());
166
+ existing.delete(fact.Name.toLowerCase());
167
+ if (!row)
168
+ row = await newRow(context, 'MJ: Query Parameters', r => newParameter(r, context.QueryID, fact));
169
+ else
170
+ applyParameterAnnotations(row, fact);
171
+ row.Name = fact.Name;
172
+ writes.push(...saveIfDirty(row, summary, parameterLabel(row)));
173
+ if (isEmpty(row.Description))
174
+ summary.ParametersWithoutDescription.push(row.Name);
175
+ }
176
+ const leftover = [...existing.values()];
177
+ summary.FlaggedParameters.push(...leftover.filter(row => row.DetectionMethod === 'Manual').map(row => row.Name));
178
+ const unused = leftover.filter(row => row.DetectionMethod !== 'Manual');
179
+ return [...writes, ...deleteRows(unused, summary, parameterLabel)];
180
+ }
181
+ function newParameter(row, queryID, fact) {
182
+ row.QueryID = queryID;
183
+ row.Type = fact.Type ?? 'string';
184
+ row.IsRequired = fact.IsRequired;
185
+ row.DefaultValue = fact.DefaultValue;
186
+ row.SampleValue = fact.SampleValue;
187
+ row.Description = fact.DocDescription ?? fact.InheritedDescription;
188
+ row.IsServerSet = false;
189
+ row.DetectionMethod = 'Parser';
190
+ }
191
+ /**
192
+ * A stored parameter: a `Manual` row keeps every annotation (only an empty description is filled);
193
+ * an auto-detected row takes the template's type, required flag and default, keeps a non-empty
194
+ * sample and description, and takes a doc comment's description.
195
+ */
196
+ function applyParameterAnnotations(row, fact) {
197
+ if (row.DetectionMethod === 'Manual') {
198
+ if (isEmpty(row.Description))
199
+ row.Description = fact.DocDescription ?? fact.InheritedDescription ?? row.Description;
200
+ return;
201
+ }
202
+ if (fact.Type !== null)
203
+ row.Type = fact.Type;
204
+ row.IsRequired = fact.IsRequired;
205
+ row.DefaultValue = fact.DefaultValue;
206
+ if (isEmpty(row.SampleValue))
207
+ row.SampleValue = fact.SampleValue;
208
+ if (fact.DocDescription !== null)
209
+ row.Description = fact.DocDescription;
210
+ else if (isEmpty(row.Description))
211
+ row.Description = fact.InheritedDescription;
212
+ row.DetectionMethod = 'Parser';
213
+ }
214
+ // ─── Entities ───────────────────────────────────────────────────────────────
215
+ async function entityWrites(context, stored, facts, summary) {
216
+ const remaining = [...stored];
217
+ const writes = [];
218
+ const unmatched = facts.filter(fact => !takeRow(remaining, r => sameEntityLink(r, fact)));
219
+ for (const fact of unmatched) {
220
+ const row = takeRow(remaining, r => UUIDsEqual(r.EntityID, fact.EntityID))
221
+ ?? await newRow(context, 'MJ: Query Entities', r => newEntityLink(r, context.QueryID, fact));
222
+ row.AlternateBaseViewID = fact.AlternateBaseViewID;
223
+ writes.push(...saveIfDirty(row, summary, entityLabel(context, row)));
224
+ }
225
+ return [...writes, ...deleteRows(remaining, summary, row => entityLabel(context, row))];
226
+ }
227
+ function entityLabel(context, row) {
228
+ return { Collection: 'Entities', Name: context.EntityName ? context.EntityName(row.EntityID) : (row.Entity || row.EntityID) };
229
+ }
230
+ function sameEntityLink(row, fact) {
231
+ const abv = (id) => (id ? NormalizeUUID(id) : '');
232
+ return UUIDsEqual(row.EntityID, fact.EntityID) && abv(row.AlternateBaseViewID) === abv(fact.AlternateBaseViewID);
233
+ }
234
+ function newEntityLink(row, queryID, fact) {
235
+ row.QueryID = queryID;
236
+ row.EntityID = fact.EntityID;
237
+ row.DetectionMethod = 'Parser';
238
+ row.AutoDetectConfidenceScore = 1;
239
+ }
240
+ /** Removes and returns the first row matching `test`. */
241
+ function takeRow(rows, test) {
242
+ const index = rows.findIndex(test);
243
+ return index < 0 ? undefined : rows.splice(index, 1)[0];
244
+ }
245
+ // ─── Dependencies ───────────────────────────────────────────────────────────
246
+ async function dependencyWrites(context, stored, facts, summary) {
247
+ const remaining = [...stored];
248
+ const writes = [];
249
+ const seen = new Set();
250
+ for (const fact of facts) {
251
+ const key = `${NormalizeUUID(fact.DependsOnQueryID)}|${fact.ReferencePath.toLowerCase()}`;
252
+ if (seen.has(key))
253
+ continue;
254
+ seen.add(key);
255
+ const row = takeRow(remaining, r => UUIDsEqual(r.DependsOnQueryID, fact.DependsOnQueryID) && r.ReferencePath.toLowerCase() === fact.ReferencePath.toLowerCase())
256
+ ?? await newRow(context, 'MJ: Query Dependencies', r => newDependency(r, context.QueryID, fact));
257
+ row.ReferencePath = fact.ReferencePath;
258
+ row.Alias = fact.Alias;
259
+ row.ParameterMapping = fact.ParameterMapping;
260
+ writes.push(...saveIfDirty(row, summary, dependencyLabel(row)));
261
+ }
262
+ return [...writes, ...deleteRows(remaining, summary, dependencyLabel)];
263
+ }
264
+ function dependencyLabel(row) {
265
+ return { Collection: 'Dependencies', Name: row.ReferencePath };
266
+ }
267
+ function newDependency(row, queryID, fact) {
268
+ row.QueryID = queryID;
269
+ row.DependsOnQueryID = fact.DependsOnQueryID;
270
+ row.DetectionMethod = 'Auto';
271
+ }
272
+ async function newRow(context, entityName, init) {
273
+ const row = await context.Provider.GetEntityObject(entityName, context.User);
274
+ init(row);
275
+ return row;
276
+ }
277
+ //# sourceMappingURL=childRowWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"childRowWriter.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/childRowWriter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQ9E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiEpF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAA6B,EAAE,MAA6B;IACtG,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,OAAO,GAAyB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,wBAAwB,EAAE,EAAE,EAAE,4BAA4B,EAAE,EAAE,EAAE,CAAC;IAC/K,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrG,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9F,IAAI,MAAM,CAAC,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5G,IAAI,MAAM,CAAC,YAAY;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5H,IAAI,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1D,MAAM,sBAAsB,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IACjF,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,yGAAyG;AACzG,KAAK,UAAU,SAAS,CAAC,OAA6B,EAAE,MAAwB;IAC5E,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;IACjD,IAAI,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,SAAS,OAAO,CAAC,OAAO,KAAK,MAAM,OAAO,MAAM,CAAC,MAAM,mDAAmD,CAAC,CAAC;AAChJ,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,OAA6B;IAC5D,MAAM,MAAM,GAAG,YAAY,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;IAC/D,MAAM,IAAI,GAAG,KAAK,EAAwB,UAAkB,EAAgB,EAAE;QAC1E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACrL,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,aAAa,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACpI,OAAO,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IAChC,CAAC,CAAC;IACF,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnE,IAAI,CAAqB,kBAAkB,CAAC;QAC5C,IAAI,CAAyB,sBAAsB,CAAC;QACpD,IAAI,CAAsB,oBAAoB,CAAC;QAC/C,IAAI,CAA0B,wBAAwB,CAAC;KAC1D,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AACtG,CAAC;AASD;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,GAAe,EAAE,OAA6B,EAAE,KAAe,EAAE,cAAiC,EAAE;IACrH,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IACjD,IAAI,GAAG,CAAC,OAAO;QAAE,OAAO,CAAC,OAAO,EAAE,CAAC;;QAC9B,OAAO,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnH,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;IACrF,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,SAAS,UAAU,CAAuB,IAAkB,EAAE,OAA6B,EAAE,OAA6B;IACtH,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAe,EAAE,MAAgC;IAC/D,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,IAAI,IAAI,EAAE,CAAC;AAC1J,CAAC;AAED,SAAS,UAAU,CAAC,GAAuB;IACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,CAAC,mBAAmB,EAAE,CAAC;AAClG,CAAC;AAED,SAAS,cAAc,CAAC,GAA2B;IAC/C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,WAAW,CAA6B,IAAkB;IAC/D,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,OAAO,CAAC,KAAgC;IAC7C,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,WAAW,CAAC,OAA6B,EAAE,MAA4B,EAAE,KAAgC,EAAE,OAA6B;IACnJ,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,GAAG,GAAG,MAAM,MAAM,CAAqB,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;;YAClH,qBAAqB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,kBAAkB,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;QACjG,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrG,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAAE,OAAO,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,QAAQ,CAAC,GAAuB,EAAE,OAAe,EAAE,IAAoB;IAC5E,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,iBAAiB,CAAC;IAChE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;IACtB,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAuB,EAAE,IAAoB;IACzE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACrB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC7B,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACnC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACnC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;IACzC,GAAG,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC;IACnD,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;IAC3C,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;AACjD,CAAC;AAED,oGAAoG;AACpG,SAAS,qBAAqB,CAAC,GAAuB,EAAE,IAAoB;IACxE,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,KAAK,QAAQ,CAAC;IAClD,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC;IACnH,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,eAAe,KAAK,IAAI;QAAE,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC;IAChF,IAAI,GAAG,CAAC,eAAe,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI;QAAE,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC;AACvG,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,eAAe,CAAC,OAA6B,EAAE,MAAgC,EAAE,KAAoC,EAAE,OAA6B;IAC/J,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,GAAG,GAAG,MAAM,MAAM,CAAyB,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;;YAC9H,yBAAyB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1C,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAAE,OAAO,CAAC,4BAA4B,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACjH,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,YAAY,CAAC,GAA2B,EAAE,OAAe,EAAE,IAAwB;IACxF,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC;IACjC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACrC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACnC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,oBAAoB,CAAC;IACnE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC;IACxB,GAAG,CAAC,eAAe,GAAG,QAAQ,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,SAAS,yBAAyB,CAAC,GAA2B,EAAE,IAAwB;IACpF,IAAI,GAAG,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC,WAAW,CAAC;QACpH,OAAO;IACX,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IAC7C,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACrC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACjE,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC;SACnE,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,oBAAoB,CAAC;IAC/E,GAAG,CAAC,eAAe,GAAG,QAAQ,CAAC;AACnC,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,YAAY,CAAC,OAA6B,EAAE,MAA6B,EAAE,KAAiC,EAAE,OAA6B;IACtJ,MAAM,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1F,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;eACnE,MAAM,MAAM,CAAsB,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACtH,GAAG,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,WAAW,CAAC,OAA6B,EAAE,GAAwB;IACxE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;AAClI,CAAC;AAED,SAAS,cAAc,CAAC,GAAwB,EAAE,IAAqB;IACnE,MAAM,GAAG,GAAG,CAAC,EAAiB,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjE,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACrH,CAAC;AAED,SAAS,aAAa,CAAC,GAAwB,EAAE,OAAe,EAAE,IAAqB;IACnF,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC7B,GAAG,CAAC,eAAe,GAAG,QAAQ,CAAC;IAC/B,GAAG,CAAC,yBAAyB,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,yDAAyD;AACzD,SAAS,OAAO,CAAI,IAAS,EAAE,IAAyB;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,gBAAgB,CAAC,OAA6B,EAAE,MAAiC,EAAE,KAAqC,EAAE,OAA6B;IAClK,MAAM,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC;QAC1F,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;eACzJ,MAAM,MAAM,CAA0B,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9H,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACvC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACvB,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,eAAe,CAAC,GAA4B;IACjD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,GAA4B,EAAE,OAAe,EAAE,IAAyB;IAC3F,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;IAC7C,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,MAAM,CAAuB,OAA6B,EAAE,UAAkB,EAAE,IAAsB;IACjH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAI,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,GAAG,CAAC;AACf,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { DatabasePlatform, IRunViewProvider, QueryDependencySpec, UserInfo } from "@memberjunction/core";
2
+ import type { MJQueryDependencyEntity, MJQueryParameterEntity, MJSQLDialectEntity } from "@memberjunction/core-entities";
3
+ /** A composed query's parameter, as extraction reads it. */
4
+ export type CompositionCandidateParameter = Pick<MJQueryParameterEntity, 'Name' | 'Type' | 'IsRequired' | 'IsServerSet' | 'SampleValue' | 'Description' | 'Query'>;
5
+ /**
6
+ * A query a composition may name, as extraction reads it: identity and path, whether it may be
7
+ * composed, its parameters and the queries it composes in turn. A cached `MJQueryEntityExtended`
8
+ * is one; so is a query read from the database during a save.
9
+ */
10
+ export interface CompositionCandidate {
11
+ readonly ID: string;
12
+ readonly Name: string;
13
+ readonly CategoryPath: string;
14
+ readonly Reusable: boolean;
15
+ readonly QueryParameters: readonly CompositionCandidateParameter[];
16
+ readonly QueryDependencies: readonly Pick<MJQueryDependencyEntity, 'DependsOnQueryID'>[];
17
+ }
18
+ /** The composed queries a save read from its own provider. */
19
+ export interface CompositionTargetRead {
20
+ /** Every query named by a composition in the SQL, as stored now (in the save's transaction). */
21
+ readonly Candidates: readonly CompositionCandidate[];
22
+ /**
23
+ * Render specs for the candidates the given cache does not hold yet (saved earlier in the same
24
+ * transaction), so the describe renders can compose them before the cache hears of them.
25
+ */
26
+ readonly InlineDependencies: readonly QueryDependencySpec[];
27
+ }
28
+ /**
29
+ * Reads the queries the compositions in `sql` name from `provider`, bypassing every cache, so a
30
+ * query saved earlier in the same transaction (a metadata push that creates a query and one that
31
+ * composes it) is found. Queries are matched by name; the caller matches category paths.
32
+ * @param cachedIDs - IDs of the queries the shared cache already holds; the others get render specs.
33
+ */
34
+ export declare function ReadCompositionTargetsAsync(sql: string, platform: DatabasePlatform, provider: Pick<IRunViewProvider, 'RunViews'>, user: UserInfo, cachedIDs: ReadonlySet<string>, dialects: readonly MJSQLDialectEntity[]): Promise<CompositionTargetRead>;
35
+ /**
36
+ * The candidates extraction resolves against: the ones read from the database, then every cached
37
+ * query the read did not return (a query read from the database replaces its cached copy).
38
+ */
39
+ export declare function MergeCompositionCandidates(read: readonly CompositionCandidate[], cached: readonly CompositionCandidate[]): CompositionCandidate[];
40
+ //# sourceMappingURL=compositionTargets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compositionTargets.d.ts","sourceRoot":"","sources":["../../../src/custom/query-extraction/compositionTargets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,mBAAmB,EAAiB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7H,OAAO,KAAK,EAER,uBAAuB,EAEvB,sBAAsB,EAEtB,kBAAkB,EACrB,MAAM,+BAA+B,CAAC;AAKvC,4DAA4D;AAC5D,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC,CAAC;AAEnK;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACnE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,IAAI,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,EAAE,CAAC;CAC5F;AAED,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IAClC,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACrD;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC/D;AAaD;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC7C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAC5C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAC9B,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACxC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,oBAAoB,EAAE,EAAE,MAAM,EAAE,SAAS,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CAGjJ"}
@@ -0,0 +1,99 @@
1
+ import { QueryParameterInfo } from "@memberjunction/core";
2
+ import { GetQueryDialect } from "@memberjunction/sql-dialect";
3
+ import { QueryTemplate } from "@memberjunction/sql-parser";
4
+ import { EscapeSQLString, IndexByUUID, UUIDsEqual } from "@memberjunction/global";
5
+ const EMPTY_READ = { Candidates: [], InlineDependencies: [] };
6
+ /**
7
+ * Reads the queries the compositions in `sql` name from `provider`, bypassing every cache, so a
8
+ * query saved earlier in the same transaction (a metadata push that creates a query and one that
9
+ * composes it) is found. Queries are matched by name; the caller matches category paths.
10
+ * @param cachedIDs - IDs of the queries the shared cache already holds; the others get render specs.
11
+ */
12
+ export async function ReadCompositionTargetsAsync(sql, platform, provider, user, cachedIDs, dialects) {
13
+ const names = [...new Set(QueryTemplate.Parse(sql, GetQueryDialect(platform)).CompositionReferences().Value.map(r => r.Name.trim().toLowerCase()))];
14
+ if (names.length === 0)
15
+ return EMPTY_READ;
16
+ const rows = await readTargetRows(names, provider, user);
17
+ if (!rows)
18
+ return EMPTY_READ;
19
+ const candidates = rows.Queries.map(q => candidateOf(q, rows));
20
+ const dialectID = dialects.find(d => d.PlatformKey === platform)?.ID ?? null;
21
+ const inline = rows.Queries
22
+ .filter(q => !cachedIDs.has(q.ID.toLowerCase()))
23
+ .map(q => inlineSpecOf(q, rows, dialectID));
24
+ return { Candidates: candidates, InlineDependencies: inline };
25
+ }
26
+ /**
27
+ * The candidates extraction resolves against: the ones read from the database, then every cached
28
+ * query the read did not return (a query read from the database replaces its cached copy).
29
+ */
30
+ export function MergeCompositionCandidates(read, cached) {
31
+ const readIDs = new Set(read.map(q => q.ID.toLowerCase()));
32
+ return [...read, ...cached.filter(q => !readIDs.has(q.ID.toLowerCase()))];
33
+ }
34
+ async function readTargetRows(names, provider, user) {
35
+ const nameList = names.map(n => `'${EscapeSQLString(n)}'`).join(', ');
36
+ const [queries, categories] = await provider.RunViews([
37
+ bypassing('MJ: Queries', `LOWER(Name) IN (${nameList})`),
38
+ bypassing('MJ: Query Categories', ''),
39
+ ], user);
40
+ if (!queries.Success || !categories.Success || queries.Results.length === 0)
41
+ return null;
42
+ const queryRows = queries.Results;
43
+ const idList = queryRows.map(q => `'${EscapeSQLString(q.ID)}'`).join(', ');
44
+ const [parameters, dependencies, sqls] = await provider.RunViews([
45
+ bypassing('MJ: Query Parameters', `QueryID IN (${idList})`),
46
+ bypassing('MJ: Query Dependencies', `QueryID IN (${idList})`),
47
+ bypassing('MJ: Query SQLs', `QueryID IN (${idList})`),
48
+ ], user);
49
+ if (!parameters.Success || !dependencies.Success || !sqls.Success)
50
+ return null;
51
+ return {
52
+ Queries: queryRows,
53
+ Categories: categories.Results,
54
+ Parameters: parameters.Results,
55
+ Dependencies: dependencies.Results,
56
+ SQLs: sqls.Results,
57
+ };
58
+ }
59
+ function bypassing(entityName, filter) {
60
+ return { EntityName: entityName, ExtraFilter: filter, ResultType: 'entity_object', BypassCache: true, IgnoreMaxRows: true };
61
+ }
62
+ function candidateOf(query, rows) {
63
+ return {
64
+ ID: query.ID,
65
+ Name: query.Name,
66
+ CategoryPath: categoryPathOf(query.CategoryID, rows.Categories),
67
+ Reusable: query.Reusable,
68
+ QueryParameters: rows.Parameters.filter(p => UUIDsEqual(p.QueryID, query.ID)),
69
+ QueryDependencies: rows.Dependencies.filter(d => UUIDsEqual(d.QueryID, query.ID)),
70
+ };
71
+ }
72
+ /** The `/`-joined names from the root category down to `categoryID`; `''` for no category. */
73
+ function categoryPathOf(categoryID, categories) {
74
+ const byID = IndexByUUID(categories);
75
+ const segments = [];
76
+ const seen = new Set();
77
+ let current = categoryID;
78
+ while (current && !seen.has(current.toLowerCase())) {
79
+ seen.add(current.toLowerCase());
80
+ const category = byID.Get(current);
81
+ if (!category)
82
+ break;
83
+ segments.unshift(category.Name);
84
+ current = category.ParentID;
85
+ }
86
+ return segments.join('/');
87
+ }
88
+ /** A render spec for a query the cache does not hold: its SQL for the platform and its parameter definitions. */
89
+ function inlineSpecOf(query, rows, dialectID) {
90
+ const variant = dialectID ? rows.SQLs.find(s => UUIDsEqual(s.QueryID, query.ID) && UUIDsEqual(s.SQLDialectID, dialectID)) : undefined;
91
+ return {
92
+ Name: query.Name,
93
+ CategoryPath: categoryPathOf(query.CategoryID, rows.Categories),
94
+ SQL: variant?.SQL ?? query.SQL ?? '',
95
+ UsesTemplate: query.UsesTemplate,
96
+ ParameterDefinitions: rows.Parameters.filter(p => UUIDsEqual(p.QueryID, query.ID)).map(p => new QueryParameterInfo(p.GetAll())),
97
+ };
98
+ }
99
+ //# sourceMappingURL=compositionTargets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compositionTargets.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/compositionTargets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import type { BaseEntity, RelatedRecordCollection } from "@memberjunction/core";
2
+ import type { MJQueryEntityEntity, MJQueryFieldEntity, MJQueryParameterEntity } from "@memberjunction/core-entities";
3
+ /**
4
+ * The child rows a query save declares, as the keys extraction matches rows by.
5
+ *
6
+ * A row is *declared* when the save writes it from one of the query's declared collections
7
+ * (`Parameters`, `Fields`, `Entities` on `MJQueryEntityExtended`): it is new, or it was edited.
8
+ * Keys are lower-cased so they compare the way the database does.
9
+ *
10
+ * Extraction treats a declared row as the caller's decision and leaves it alone: it does not add a
11
+ * row with the same key, update it, or delete it, even when the SQL no longer mentions it. That is
12
+ * how a declared row "wins" over what extraction would have written for the same key in the same
13
+ * save. Any later extraction (an extraction service, a refresh) that replaces the current one must
14
+ * honour these sets the same way; the facts it would compute for a declared row can be reported, but
15
+ * not written.
16
+ */
17
+ export interface DeclaredQueryChildren {
18
+ /** Declared parameter names. */
19
+ ParameterNames: ReadonlySet<string>;
20
+ /** Declared output field names. */
21
+ FieldNames: ReadonlySet<string>;
22
+ /** Declared entity links, keyed by {@link QueryEntityKey} (the entity ID). */
23
+ EntityKeys: ReadonlySet<string>;
24
+ }
25
+ /** A declared set with nothing in it, for saves that declare no children. */
26
+ export declare const NO_DECLARED_QUERY_CHILDREN: DeclaredQueryChildren;
27
+ /** The three declared collections of a query, as `MJQueryEntityExtended` exposes them. */
28
+ export interface DeclaredQueryCollections {
29
+ Parameters: RelatedRecordCollection<MJQueryParameterEntity>;
30
+ Fields: RelatedRecordCollection<MJQueryFieldEntity>;
31
+ Entities: RelatedRecordCollection<MJQueryEntityEntity>;
32
+ }
33
+ /**
34
+ * The key a Query Entity row is matched by: the entity it links. Extraction keeps at most one row
35
+ * per entity (it updates the alternate base view on that row), so a declared row for an entity
36
+ * stands for every link to it.
37
+ */
38
+ export declare function QueryEntityKey(row: Pick<MJQueryEntityEntity, 'EntityID'>): string;
39
+ /** The key a parameter or field row is matched by: its name, trimmed and lower-cased. */
40
+ export declare function QueryChildNameKey(name: string | null | undefined): string;
41
+ /**
42
+ * The child rows a save of the query declares, read from its declared collections before the save.
43
+ *
44
+ * @param collections - The query's declared collections.
45
+ * @returns The declared keys; empty sets when the collections hold nothing to write.
46
+ */
47
+ export declare function CollectDeclaredQueryChildren(collections: DeclaredQueryCollections): DeclaredQueryChildren;
48
+ /** True when the declared set holds at least one row. */
49
+ export declare function HasDeclaredQueryChildren(declared: DeclaredQueryChildren): boolean;
50
+ /** A stored row and its detection method, as conflict detection reads it. */
51
+ type DetectedRow = BaseEntity & {
52
+ ID: string;
53
+ DetectionMethod: string;
54
+ };
55
+ /**
56
+ * The stored rows a declared collection item replaces: rows with the same key as a NEW item but a
57
+ * different ID, that extraction (not a person) created. A row whose `DetectionMethod` is `Manual`
58
+ * was authored and is never selected, so authored rows are never touched.
59
+ *
60
+ * @param newItems - The collection's unsaved items.
61
+ * @param stored - The rows stored for the query, read from the database.
62
+ * @param key - How rows are matched.
63
+ * @returns The stored rows to delete in the same save, before the new items are inserted.
64
+ */
65
+ export declare function FindReplacedRows<T extends DetectedRow>(newItems: readonly T[], stored: readonly T[], key: (row: T) => string): T[];
66
+ /**
67
+ * Queues a stored row for deletion through the collection, so the delete runs inside the query's
68
+ * graph save, before the collection's inserts (a collection's removals run first). The row is
69
+ * removed from the collection when the collection already holds it; otherwise it is attached and
70
+ * removed, which queues the same delete.
71
+ *
72
+ * @param collection - The declared collection.
73
+ * @param row - The stored row to delete.
74
+ */
75
+ export declare function QueueReplacedRowDeletion<T extends BaseEntity & {
76
+ ID: string;
77
+ }>(collection: RelatedRecordCollection<T>, row: T): void;
78
+ export {};
79
+ //# sourceMappingURL=declared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declared.d.ts","sourceRoot":"","sources":["../../../src/custom/query-extraction/declared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAGrH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAqB;IAClC,gCAAgC;IAChC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,mCAAmC;IACnC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,8EAA8E;IAC9E,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,EAAE,qBAIxC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,uBAAuB,CAAC,sBAAsB,CAAC,CAAC;IAC5D,MAAM,EAAE,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;IACpD,QAAQ,EAAE,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;CAC1D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,GAAG,MAAM,CAEjF;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEzE;AAkBD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,wBAAwB,GAAG,qBAAqB,CAMzG;AAED,yDAAyD;AACzD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAEjF;AAED,6EAA6E;AAC7E,KAAK,WAAW,GAAG,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAWlI;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAQpI"}
@@ -0,0 +1,91 @@
1
+ import { NormalizeUUID, UUIDsEqual } from "@memberjunction/global";
2
+ /** A declared set with nothing in it, for saves that declare no children. */
3
+ export const NO_DECLARED_QUERY_CHILDREN = {
4
+ ParameterNames: new Set(),
5
+ FieldNames: new Set(),
6
+ EntityKeys: new Set(),
7
+ };
8
+ /**
9
+ * The key a Query Entity row is matched by: the entity it links. Extraction keeps at most one row
10
+ * per entity (it updates the alternate base view on that row), so a declared row for an entity
11
+ * stands for every link to it.
12
+ */
13
+ export function QueryEntityKey(row) {
14
+ return row.EntityID ? NormalizeUUID(row.EntityID) : '';
15
+ }
16
+ /** The key a parameter or field row is matched by: its name, trimmed and lower-cased. */
17
+ export function QueryChildNameKey(name) {
18
+ return (name ?? '').trim().toLowerCase();
19
+ }
20
+ /** True when the save will write this collection item: it is new, or it has unsaved edits. */
21
+ function isWrittenBySave(item) {
22
+ return !item.IsSaved || item.Dirty;
23
+ }
24
+ /** The keys of the items a save writes from one collection. */
25
+ function writtenKeys(items, key) {
26
+ const keys = new Set();
27
+ for (const item of items) {
28
+ if (isWrittenBySave(item)) {
29
+ keys.add(key(item));
30
+ }
31
+ }
32
+ return keys;
33
+ }
34
+ /**
35
+ * The child rows a save of the query declares, read from its declared collections before the save.
36
+ *
37
+ * @param collections - The query's declared collections.
38
+ * @returns The declared keys; empty sets when the collections hold nothing to write.
39
+ */
40
+ export function CollectDeclaredQueryChildren(collections) {
41
+ return {
42
+ ParameterNames: writtenKeys(collections.Parameters.Items, p => QueryChildNameKey(p.Name)),
43
+ FieldNames: writtenKeys(collections.Fields.Items, f => QueryChildNameKey(f.Name)),
44
+ EntityKeys: writtenKeys(collections.Entities.Items, QueryEntityKey),
45
+ };
46
+ }
47
+ /** True when the declared set holds at least one row. */
48
+ export function HasDeclaredQueryChildren(declared) {
49
+ return declared.ParameterNames.size > 0 || declared.FieldNames.size > 0 || declared.EntityKeys.size > 0;
50
+ }
51
+ /**
52
+ * The stored rows a declared collection item replaces: rows with the same key as a NEW item but a
53
+ * different ID, that extraction (not a person) created. A row whose `DetectionMethod` is `Manual`
54
+ * was authored and is never selected, so authored rows are never touched.
55
+ *
56
+ * @param newItems - The collection's unsaved items.
57
+ * @param stored - The rows stored for the query, read from the database.
58
+ * @param key - How rows are matched.
59
+ * @returns The stored rows to delete in the same save, before the new items are inserted.
60
+ */
61
+ export function FindReplacedRows(newItems, stored, key) {
62
+ const newByKey = new Map();
63
+ for (const item of newItems) {
64
+ newByKey.set(key(item), item);
65
+ }
66
+ return stored.filter(row => {
67
+ const declared = newByKey.get(key(row));
68
+ return declared !== undefined
69
+ && !UUIDsEqual(row.ID, declared.ID)
70
+ && row.DetectionMethod !== 'Manual';
71
+ });
72
+ }
73
+ /**
74
+ * Queues a stored row for deletion through the collection, so the delete runs inside the query's
75
+ * graph save, before the collection's inserts (a collection's removals run first). The row is
76
+ * removed from the collection when the collection already holds it; otherwise it is attached and
77
+ * removed, which queues the same delete.
78
+ *
79
+ * @param collection - The declared collection.
80
+ * @param row - The stored row to delete.
81
+ */
82
+ export function QueueReplacedRowDeletion(collection, row) {
83
+ const held = collection.Items.find(item => item.IsSaved && UUIDsEqual(item.ID, row.ID));
84
+ if (held) {
85
+ collection.Remove(held);
86
+ return;
87
+ }
88
+ collection.Add(row);
89
+ collection.Remove(row);
90
+ }
91
+ //# sourceMappingURL=declared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/declared.ts"],"names":[],"mappings":"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"}