@memberjunction/metadata-sync 6.2.0-edge.4 → 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.
- package/README.md +120 -52
- package/dist/config.d.ts +18 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/RecordProcessor.d.ts +98 -0
- package/dist/lib/RecordProcessor.d.ts.map +1 -1
- package/dist/lib/RecordProcessor.js +424 -22
- package/dist/lib/RecordProcessor.js.map +1 -1
- package/dist/lib/RelatedEntityHandler.d.ts +4 -1
- package/dist/lib/RelatedEntityHandler.d.ts.map +1 -1
- package/dist/lib/RelatedEntityHandler.js +49 -11
- package/dist/lib/RelatedEntityHandler.js.map +1 -1
- package/dist/lib/created-record-key.d.ts +34 -0
- package/dist/lib/created-record-key.d.ts.map +1 -0
- package/dist/lib/created-record-key.js +46 -0
- package/dist/lib/created-record-key.js.map +1 -0
- package/dist/lib/deletion-auditor.d.ts.map +1 -1
- package/dist/lib/deletion-auditor.js +34 -3
- package/dist/lib/deletion-auditor.js.map +1 -1
- package/dist/lib/entity-field-names.d.ts +11 -0
- package/dist/lib/entity-field-names.d.ts.map +1 -0
- package/dist/lib/entity-field-names.js +15 -0
- package/dist/lib/entity-field-names.js.map +1 -0
- package/dist/lib/env-derived-fields.d.ts +23 -0
- package/dist/lib/env-derived-fields.d.ts.map +1 -0
- package/dist/lib/env-derived-fields.js +53 -0
- package/dist/lib/env-derived-fields.js.map +1 -0
- package/dist/lib/env-display.d.ts +54 -0
- package/dist/lib/env-display.d.ts.map +1 -0
- package/dist/lib/env-display.js +156 -0
- package/dist/lib/env-display.js.map +1 -0
- package/dist/lib/env-reference.d.ts +104 -0
- package/dist/lib/env-reference.d.ts.map +1 -0
- package/dist/lib/env-reference.js +241 -0
- package/dist/lib/env-reference.js.map +1 -0
- package/dist/lib/env-sql-redactor.d.ts +74 -0
- package/dist/lib/env-sql-redactor.d.ts.map +1 -0
- package/dist/lib/env-sql-redactor.js +232 -0
- package/dist/lib/env-sql-redactor.js.map +1 -0
- package/dist/lib/existing-record-index.d.ts +70 -0
- package/dist/lib/existing-record-index.d.ts.map +1 -0
- package/dist/lib/existing-record-index.js +158 -0
- package/dist/lib/existing-record-index.js.map +1 -0
- package/dist/lib/ignore-directories.d.ts +10 -0
- package/dist/lib/ignore-directories.d.ts.map +1 -0
- package/dist/lib/ignore-directories.js +12 -0
- package/dist/lib/ignore-directories.js.map +1 -0
- package/dist/lib/json-record-lines.d.ts +17 -0
- package/dist/lib/json-record-lines.d.ts.map +1 -0
- package/dist/lib/json-record-lines.js +170 -0
- package/dist/lib/json-record-lines.js.map +1 -0
- package/dist/lib/json-subproperty-externalization.d.ts.map +1 -1
- package/dist/lib/json-subproperty-externalization.js +3 -1
- package/dist/lib/json-subproperty-externalization.js.map +1 -1
- package/dist/lib/lookup-reference.d.ts +38 -0
- package/dist/lib/lookup-reference.d.ts.map +1 -0
- package/dist/lib/lookup-reference.js +62 -0
- package/dist/lib/lookup-reference.js.map +1 -0
- package/dist/lib/lookup-sql.d.ts +108 -0
- package/dist/lib/lookup-sql.d.ts.map +1 -0
- package/dist/lib/lookup-sql.js +231 -0
- package/dist/lib/lookup-sql.js.map +1 -0
- package/dist/lib/natural-key-preflight.d.ts +86 -0
- package/dist/lib/natural-key-preflight.d.ts.map +1 -0
- package/dist/lib/natural-key-preflight.js +173 -0
- package/dist/lib/natural-key-preflight.js.map +1 -0
- package/dist/lib/provider-utils.d.ts.map +1 -1
- package/dist/lib/provider-utils.js +2 -4
- package/dist/lib/provider-utils.js.map +1 -1
- package/dist/lib/pull-option-overrides.d.ts +24 -0
- package/dist/lib/pull-option-overrides.d.ts.map +1 -0
- package/dist/lib/pull-option-overrides.js +39 -0
- package/dist/lib/pull-option-overrides.js.map +1 -0
- package/dist/lib/push-directories.d.ts +42 -0
- package/dist/lib/push-directories.d.ts.map +1 -0
- package/dist/lib/push-directories.js +71 -0
- package/dist/lib/push-directories.js.map +1 -0
- package/dist/lib/push-when.d.ts +38 -0
- package/dist/lib/push-when.d.ts.map +1 -0
- package/dist/lib/push-when.js +84 -0
- package/dist/lib/push-when.js.map +1 -0
- package/dist/lib/record-dependency-analyzer.d.ts +11 -2
- package/dist/lib/record-dependency-analyzer.d.ts.map +1 -1
- package/dist/lib/record-dependency-analyzer.js +48 -71
- package/dist/lib/record-dependency-analyzer.js.map +1 -1
- package/dist/lib/record-file-glob.d.ts +11 -0
- package/dist/lib/record-file-glob.d.ts.map +1 -0
- package/dist/lib/record-file-glob.js +10 -0
- package/dist/lib/record-file-glob.js.map +1 -0
- package/dist/lib/reference-parser.d.ts +3 -2
- package/dist/lib/reference-parser.d.ts.map +1 -1
- package/dist/lib/reference-parser.js +27 -27
- package/dist/lib/reference-parser.js.map +1 -1
- package/dist/lib/schema-placeholders.d.ts +29 -0
- package/dist/lib/schema-placeholders.d.ts.map +1 -0
- package/dist/lib/schema-placeholders.js +72 -0
- package/dist/lib/schema-placeholders.js.map +1 -0
- package/dist/lib/sql-logger.d.ts +9 -1
- package/dist/lib/sql-logger.d.ts.map +1 -1
- package/dist/lib/sql-logger.js +12 -7
- package/dist/lib/sql-logger.js.map +1 -1
- package/dist/lib/sql-set-line.d.ts +26 -0
- package/dist/lib/sql-set-line.d.ts.map +1 -0
- package/dist/lib/sql-set-line.js +84 -0
- package/dist/lib/sql-set-line.js.map +1 -0
- package/dist/lib/sync-engine.d.ts +58 -4
- package/dist/lib/sync-engine.d.ts.map +1 -1
- package/dist/lib/sync-engine.js +243 -59
- package/dist/lib/sync-engine.js.map +1 -1
- package/dist/lib/sync-state-manager.d.ts +7 -3
- package/dist/lib/sync-state-manager.d.ts.map +1 -1
- package/dist/lib/sync-state-manager.js +19 -4
- package/dist/lib/sync-state-manager.js.map +1 -1
- package/dist/lib/watch-file-filter.d.ts +31 -0
- package/dist/lib/watch-file-filter.d.ts.map +1 -0
- package/dist/lib/watch-file-filter.js +64 -0
- package/dist/lib/watch-file-filter.js.map +1 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +44 -14
- package/dist/plugins/index.js.map +1 -1
- package/dist/services/PullService.d.ts +41 -1
- package/dist/services/PullService.d.ts.map +1 -1
- package/dist/services/PullService.js +261 -101
- package/dist/services/PullService.js.map +1 -1
- package/dist/services/PushService.d.ts +80 -0
- package/dist/services/PushService.d.ts.map +1 -1
- package/dist/services/PushService.js +531 -189
- package/dist/services/PushService.js.map +1 -1
- package/dist/services/ValidationService.d.ts +43 -8
- package/dist/services/ValidationService.d.ts.map +1 -1
- package/dist/services/ValidationService.js +338 -127
- package/dist/services/ValidationService.js.map +1 -1
- package/dist/services/WatchService.d.ts +28 -0
- package/dist/services/WatchService.d.ts.map +1 -1
- package/dist/services/WatchService.js +226 -74
- package/dist/services/WatchService.js.map +1 -1
- package/dist/types/validation.d.ts +6 -0
- package/dist/types/validation.d.ts.map +1 -1
- package/package.json +17 -16
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Parsing and checks for `@env:` references in metadata files.
|
|
3
|
+
* @module env-reference
|
|
4
|
+
*/
|
|
5
|
+
import { METADATA_KEYWORDS } from '../constants/metadata-keywords.js';
|
|
6
|
+
import { MIN_MASKED_VALUE_LENGTH } from './env-display.js';
|
|
7
|
+
/** Matches `@env:VARIABLE`, with an optional `?optional` modifier. */
|
|
8
|
+
export const ENV_REFERENCE_PATTERN = /^@env:([^?]+)(\?optional)?$/;
|
|
9
|
+
/**
|
|
10
|
+
* Parses an `@env:` reference.
|
|
11
|
+
* @returns The parsed reference, or null when the value is not a valid `@env:` reference
|
|
12
|
+
*/
|
|
13
|
+
export function ParseEnvReference(value) {
|
|
14
|
+
if (typeof value !== 'string' || !value.startsWith(METADATA_KEYWORDS.ENV)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const match = value.match(ENV_REFERENCE_PATTERN);
|
|
18
|
+
if (!match) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return { VariableName: match[1], Optional: match[2] !== undefined };
|
|
22
|
+
}
|
|
23
|
+
/** True when an environment value is `true` or `1`, ignoring case and surrounding spaces. */
|
|
24
|
+
export function IsEnvFlagTrue(value) {
|
|
25
|
+
const normalized = value?.trim().toLowerCase();
|
|
26
|
+
return normalized === 'true' || normalized === '1';
|
|
27
|
+
}
|
|
28
|
+
/** Thrown when an `@env:VAR?optional` reference names a variable that is not set. */
|
|
29
|
+
export class OptionalEnvMissingError extends Error {
|
|
30
|
+
constructor(variableName) {
|
|
31
|
+
super(`Optional environment variable not set: ${variableName}`);
|
|
32
|
+
this.name = 'OptionalEnvMissingError';
|
|
33
|
+
this.VariableName = variableName;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Thrown when a non-optional `@env:` reference names a variable that is not set. Holds names only. */
|
|
37
|
+
export class EnvVariableNotSetError extends Error {
|
|
38
|
+
constructor(variableName, field, entityName) {
|
|
39
|
+
super(`Environment variable not found: ${variableName}`);
|
|
40
|
+
this.name = 'EnvVariableNotSetError';
|
|
41
|
+
this.VariableName = variableName;
|
|
42
|
+
this.Field = field;
|
|
43
|
+
this.EntityName = entityName;
|
|
44
|
+
}
|
|
45
|
+
/** The same error for the given field (and entity, when given). */
|
|
46
|
+
ForField(field, entityName) {
|
|
47
|
+
return new EnvVariableNotSetError(this.VariableName, field, entityName ?? this.EntityName);
|
|
48
|
+
}
|
|
49
|
+
/** The same error inside a composition path, such as `collections.Lines[0]`; an entity already named is kept. */
|
|
50
|
+
Within(compositionPath, entityName) {
|
|
51
|
+
const field = this.Field ? `${compositionPath}.${this.Field}` : compositionPath;
|
|
52
|
+
return new EnvVariableNotSetError(this.VariableName, field, this.EntityName ?? entityName);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** The warning push gives when it leaves out a field whose optional variable is not set. */
|
|
56
|
+
export function OptionalEnvSkipMessage(entityName, fieldName, variableName) {
|
|
57
|
+
return `${entityName}.${fieldName} was not pushed: optional variable ${variableName} is not set`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Decides whether pull keeps an existing `@env:` reference instead of the database value.
|
|
61
|
+
* The result never contains the variable's value.
|
|
62
|
+
* @returns The reference to keep, or null when the existing value is not a valid `@env:` reference
|
|
63
|
+
*/
|
|
64
|
+
export function KeepEnvReference(existingValue, databaseValue, env = process.env) {
|
|
65
|
+
if (typeof existingValue !== 'string') {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const reference = ParseEnvReference(existingValue);
|
|
69
|
+
if (!reference) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const envValue = env[reference.VariableName];
|
|
73
|
+
let check = 'Unset';
|
|
74
|
+
if (envValue !== undefined) {
|
|
75
|
+
check = comparable(envValue) === comparable(databaseValue) ? 'Match' : 'Drift';
|
|
76
|
+
}
|
|
77
|
+
return { Reference: existingValue, VariableName: reference.VariableName, Check: check };
|
|
78
|
+
}
|
|
79
|
+
function comparable(value) {
|
|
80
|
+
return value === null || value === undefined ? null : String(value).trim();
|
|
81
|
+
}
|
|
82
|
+
/** True for a plain object or an array. */
|
|
83
|
+
export function IsJsonContainer(value) {
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype;
|
|
88
|
+
}
|
|
89
|
+
/** True when an object or array holds a valid `@env:` string at any depth. */
|
|
90
|
+
export function HasNestedEnvReference(value) {
|
|
91
|
+
return IsJsonContainer(value) && containsEnvLeaf(value);
|
|
92
|
+
}
|
|
93
|
+
function containsEnvLeaf(value) {
|
|
94
|
+
if (typeof value === 'string') {
|
|
95
|
+
return ParseEnvReference(value) !== null;
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
return value.some(containsEnvLeaf);
|
|
99
|
+
}
|
|
100
|
+
if (IsJsonContainer(value)) {
|
|
101
|
+
return Object.values(value).some(containsEnvLeaf);
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Keeps `@env:` references inside a JSON field. The database value decides the structure and every
|
|
107
|
+
* other leaf. A reference is put back only at a path that also exists in the database value; arrays
|
|
108
|
+
* match by index. When the merged JSON would still hold the value (6 or more characters) of a variable
|
|
109
|
+
* that the existing value references, the existing value is kept as is.
|
|
110
|
+
* @returns null when the existing value is not an object or array, or holds no valid `@env:` string
|
|
111
|
+
*/
|
|
112
|
+
export function KeepNestedEnvReferences(existingValue, databaseValue, env = process.env) {
|
|
113
|
+
if (!IsJsonContainer(existingValue) || !containsEnvLeaf(existingValue)) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const parsed = parseJsonContainer(databaseValue);
|
|
117
|
+
if (parsed === null) {
|
|
118
|
+
return { Value: structuredClone(existingValue), Kept: [], KeptFileValue: true, LeftValueVariables: [] };
|
|
119
|
+
}
|
|
120
|
+
const value = structuredClone(parsed);
|
|
121
|
+
const kept = [];
|
|
122
|
+
putBackReferences(existingValue, value, '', kept, env);
|
|
123
|
+
const leftValueVariables = findLeftValueVariables(existingValue, value, env);
|
|
124
|
+
if (leftValueVariables.length > 0) {
|
|
125
|
+
return {
|
|
126
|
+
Value: structuredClone(existingValue),
|
|
127
|
+
Kept: [],
|
|
128
|
+
KeptFileValue: true,
|
|
129
|
+
LeftValueVariables: leftValueVariables,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return { Value: value, Kept: kept, KeptFileValue: false, LeftValueVariables: [] };
|
|
133
|
+
}
|
|
134
|
+
/** Sorted names of the referenced variables whose value is still in the merged JSON. */
|
|
135
|
+
function findLeftValueVariables(existing, merged, env) {
|
|
136
|
+
const mergedText = JSON.stringify(merged);
|
|
137
|
+
return [...collectEnvVariableNames(existing, new Set())]
|
|
138
|
+
.filter((name) => holdsEnvValue(mergedText, env[name]))
|
|
139
|
+
.sort();
|
|
140
|
+
}
|
|
141
|
+
function collectEnvVariableNames(value, names) {
|
|
142
|
+
if (typeof value === 'string') {
|
|
143
|
+
const reference = ParseEnvReference(value);
|
|
144
|
+
if (reference) {
|
|
145
|
+
names.add(reference.VariableName);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (Array.isArray(value)) {
|
|
149
|
+
value.forEach((item) => collectEnvVariableNames(item, names));
|
|
150
|
+
}
|
|
151
|
+
else if (IsJsonContainer(value)) {
|
|
152
|
+
Object.values(value).forEach((item) => collectEnvVariableNames(item, names));
|
|
153
|
+
}
|
|
154
|
+
return names;
|
|
155
|
+
}
|
|
156
|
+
/** Most JSON-escape levels the left-over check looks for (a JSON string inside a JSON string, and so on). */
|
|
157
|
+
const MAX_ESCAPE_LEVELS = 4;
|
|
158
|
+
/** True when the text holds the trimmed value, plain or JSON-escaped one or more times. */
|
|
159
|
+
function holdsEnvValue(text, envValue) {
|
|
160
|
+
const trimmed = envValue?.trim();
|
|
161
|
+
if (!trimmed || trimmed.length < MIN_MASKED_VALUE_LENGTH) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
let form = trimmed;
|
|
165
|
+
for (let level = 0; level <= MAX_ESCAPE_LEVELS; level++) {
|
|
166
|
+
if (text.includes(form)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
const escaped = JSON.stringify(form).slice(1, -1);
|
|
170
|
+
if (escaped === form) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
form = escaped;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
function parseJsonContainer(value) {
|
|
178
|
+
if (IsJsonContainer(value)) {
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
if (typeof value !== 'string') {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(value);
|
|
186
|
+
return IsJsonContainer(parsed) ? parsed : null;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function putBackReferences(existing, target, path, kept, env) {
|
|
193
|
+
if (Array.isArray(existing)) {
|
|
194
|
+
if (!Array.isArray(target)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const count = Math.min(existing.length, target.length);
|
|
198
|
+
for (let i = 0; i < count; i++) {
|
|
199
|
+
const reference = keepLeaf(existing[i], target[i], `${path}[${i}]`, kept, env);
|
|
200
|
+
if (reference !== null) {
|
|
201
|
+
target[i] = reference;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(target)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
for (const [key, item] of Object.entries(existing)) {
|
|
210
|
+
if (!Object.prototype.hasOwnProperty.call(target, key)) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const reference = keepLeaf(item, target[key], appendKey(path, key), kept, env);
|
|
214
|
+
if (reference !== null) {
|
|
215
|
+
target[key] = reference;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/** The reference to put at this path, or null. Walks into nested objects and arrays. */
|
|
220
|
+
function keepLeaf(existingItem, targetItem, path, kept, env) {
|
|
221
|
+
if (typeof existingItem === 'string') {
|
|
222
|
+
const comparable = IsJsonContainer(targetItem) ? JSON.stringify(targetItem) : targetItem;
|
|
223
|
+
const result = KeepEnvReference(existingItem, comparable, env);
|
|
224
|
+
if (!result) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
kept.push({ Path: path, Reference: result.Reference, VariableName: result.VariableName, Check: result.Check });
|
|
228
|
+
return result.Reference;
|
|
229
|
+
}
|
|
230
|
+
if (IsJsonContainer(existingItem) && IsJsonContainer(targetItem)) {
|
|
231
|
+
putBackReferences(existingItem, targetItem, path, kept, env);
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
function appendKey(path, key) {
|
|
236
|
+
if (/^[A-Za-z_$][\w$]*$/.test(key)) {
|
|
237
|
+
return path ? `${path}.${key}` : key;
|
|
238
|
+
}
|
|
239
|
+
return `${path}[${JSON.stringify(key)}]`;
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=env-reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-reference.js","sourceRoot":"","sources":["../../src/lib/env-reference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { BaseEntity } from '@memberjunction/core';
|
|
2
|
+
import type { SyncEngine } from './sync-engine.js';
|
|
3
|
+
/** Replaces registered SET lines and gives names-only warnings for one push. */
|
|
4
|
+
export declare class EnvSqlRedactor {
|
|
5
|
+
private readonly variables;
|
|
6
|
+
private readonly env;
|
|
7
|
+
/** Registrations by save-call hash; `ANY_SAVE_CALL_SUFFIX` holds those registered without a hash. */
|
|
8
|
+
private readonly fieldsByHash;
|
|
9
|
+
private readonly primaryKeys;
|
|
10
|
+
private transformFailed;
|
|
11
|
+
/** `variables` is read when `Warnings` runs, so a set that grows during the run can be passed. */
|
|
12
|
+
constructor(variables: ReadonlySet<string>, env?: NodeJS.ProcessEnv);
|
|
13
|
+
/**
|
|
14
|
+
* Registers a field whose value is in a save statement. With `saveCallHash` (the 12-hex
|
|
15
|
+
* `GenericDatabaseProvider.SaveCallVariableHash` of the record), only the SET line of that save
|
|
16
|
+
* call is replaced. Without it, the SET line of any save call with the same code name and literal
|
|
17
|
+
* is replaced. A null or undefined value is not registered, because no SET line is written for it.
|
|
18
|
+
* A registration stays for the whole push.
|
|
19
|
+
*/
|
|
20
|
+
Register(entityName: string, fieldName: string, codeName: string, value: unknown, variableNames: ReadonlySet<string>, saveCallHash?: string): void;
|
|
21
|
+
/** Registers an env-sourced primary key field. Its value stays in the log, so it gives a warning. */
|
|
22
|
+
RegisterPrimaryKey(entityName: string, fieldName: string, variableNames: ReadonlySet<string>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Registers the env-sourced fields that the save statement of `entity` holds. Each field is
|
|
25
|
+
* registered at the IS-A level whose table holds it, with that level's save-call hash. A level's
|
|
26
|
+
* statement holds every field when `fullRow` (a create or alwaysPush) or when its entity has no
|
|
27
|
+
* generated update procedure (the full save SQL is logged); else only the changed fields.
|
|
28
|
+
* Key fields give a warning. `envFields` keys are matched without regard to case. Call it right
|
|
29
|
+
* before the save, so the hash uses the key values the provider hashes.
|
|
30
|
+
*/
|
|
31
|
+
RegisterEntityFields(entity: BaseEntity, envFields: ReadonlyMap<string, ReadonlySet<string>> | undefined, fullRow: boolean): void;
|
|
32
|
+
/**
|
|
33
|
+
* The `SqlLoggingOptions.TransformStatement` function. It can run many times on the same text and
|
|
34
|
+
* on text that is never written. It only marks fields as matched and never throws; on an
|
|
35
|
+
* unexpected error it returns a comment in place of the statement.
|
|
36
|
+
*/
|
|
37
|
+
readonly Transform: (sql: string) => string;
|
|
38
|
+
/** Names-only warnings for the SQL log at `sqlLogPath`. Reads the written log; never throws. */
|
|
39
|
+
Warnings(sqlLogPath: string): string[];
|
|
40
|
+
private fieldsForHash;
|
|
41
|
+
/** The registrations that can match the statement: those of each suffix in it, and those without a hash. */
|
|
42
|
+
private candidateFields;
|
|
43
|
+
private replaceSetLines;
|
|
44
|
+
private unmatchedFieldWarnings;
|
|
45
|
+
private primaryKeyWarnings;
|
|
46
|
+
/**
|
|
47
|
+
* For each resolved variable other than a key variable: a warning when its value is in the
|
|
48
|
+
* written log, or when it is not set now and so cannot be checked.
|
|
49
|
+
*/
|
|
50
|
+
private variableValueWarnings;
|
|
51
|
+
}
|
|
52
|
+
/** The sync engine members an `EnvSqlLog` uses. */
|
|
53
|
+
type EnvSqlLogEngine = Pick<SyncEngine, 'BeforeLookupCreateSave' | 'ResolvedEnvVariables'>;
|
|
54
|
+
/**
|
|
55
|
+
* The redactor of one open SQL log, with the `SyncEngine.BeforeLookupCreateSave` hook that registers
|
|
56
|
+
* each record a `?create` lookup creates (with the full row, because a create writes every field).
|
|
57
|
+
*/
|
|
58
|
+
export declare class EnvSqlLog {
|
|
59
|
+
readonly Redactor: EnvSqlRedactor;
|
|
60
|
+
private readonly engine;
|
|
61
|
+
private readonly hook;
|
|
62
|
+
/** Creates the redactor over the engine's resolved variables and sets the engine's hook. */
|
|
63
|
+
constructor(engine: EnvSqlLogEngine);
|
|
64
|
+
/** Clears the engine's hook when it is still this log's hook. */
|
|
65
|
+
Close(): void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Adds a field that was left out because its `?optional` variable is not set. The SQL log then
|
|
69
|
+
* leaves the field's SET line out by name, as for an env-sourced field: a full-row save would
|
|
70
|
+
* otherwise write the field's database value.
|
|
71
|
+
*/
|
|
72
|
+
export declare function AddSkippedOptionalEnvField(envFields: Map<string, Set<string>> | undefined, fieldName: string, variableName: string): void;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=env-sql-redactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-sql-redactor.d.ts","sourceRoot":"","sources":["../../src/lib/env-sql-redactor.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAehD,gFAAgF;AAChF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,qGAAqG;IACrG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiD;IAC9E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,eAAe,CAAS;IAEhC,kGAAkG;gBACtF,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB;IAKhF;;;;;;OAMG;IACH,QAAQ,CACN,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI;IAoBP,qGAAqG;IACrG,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI;IAUnG;;;;;;;OAOG;IACH,oBAAoB,CAClB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAC/D,OAAO,EAAE,OAAO,GACf,IAAI;IAuBP;;;;OAIG;IACH,QAAQ,CAAC,SAAS,GAAI,KAAK,MAAM,KAAG,MAAM,CAOxC;IAEF,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAYtC,OAAO,CAAC,aAAa;IASrB,4GAA4G;IAC5G,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,kBAAkB;IAM1B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAiB9B;AAqBD,mDAAmD;AACnD,KAAK,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,wBAAwB,GAAG,sBAAsB,CAAC,CAAC;AAE3F;;;GAGG;AACH,qBAAa,SAAS;IACpB,SAAgB,QAAQ,EAAE,cAAc,CAAC;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoD;IAEzE,4FAA4F;gBAChF,MAAM,EAAE,eAAe;IAOnC,iEAAiE;IACjE,KAAK,IAAI,IAAI;CAKd;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAC/C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,IAAI,CAON"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Leaves the values of env-sourced fields out of the push SQL log.
|
|
3
|
+
*
|
|
4
|
+
* SQL Server saves set each parameter with one line: `SET @<CodeName>_<12 hex>[_n] = <literal>`.
|
|
5
|
+
* For a registered field, that line is replaced with a comment. The variable is then NULL in the
|
|
6
|
+
* recorded statement, so a replayed update keeps the target's value. A primary key cannot be left
|
|
7
|
+
* out; it gives a warning. After the run, the written log is searched for the values of the
|
|
8
|
+
* resolved variables. All messages name variables, never values.
|
|
9
|
+
* @module env-sql-redactor
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import { GenericDatabaseProvider } from '@memberjunction/generic-database-provider';
|
|
13
|
+
import { EnvDisplayMask } from './env-display.js';
|
|
14
|
+
import { ANY_SAVE_CALL_SUFFIX, OwningLevel, SaveCallHashesIn, SetLinePattern, SqlLiteralsOf } from './sql-set-line.js';
|
|
15
|
+
/** Replaces registered SET lines and gives names-only warnings for one push. */
|
|
16
|
+
export class EnvSqlRedactor {
|
|
17
|
+
/** `variables` is read when `Warnings` runs, so a set that grows during the run can be passed. */
|
|
18
|
+
constructor(variables, env = process.env) {
|
|
19
|
+
/** Registrations by save-call hash; `ANY_SAVE_CALL_SUFFIX` holds those registered without a hash. */
|
|
20
|
+
this.fieldsByHash = new Map();
|
|
21
|
+
this.primaryKeys = new Map();
|
|
22
|
+
this.transformFailed = false;
|
|
23
|
+
/**
|
|
24
|
+
* The `SqlLoggingOptions.TransformStatement` function. It can run many times on the same text and
|
|
25
|
+
* on text that is never written. It only marks fields as matched and never throws; on an
|
|
26
|
+
* unexpected error it returns a comment in place of the statement.
|
|
27
|
+
*/
|
|
28
|
+
this.Transform = (sql) => {
|
|
29
|
+
try {
|
|
30
|
+
return this.replaceSetLines(sql);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
this.transformFailed = true;
|
|
34
|
+
return '-- Statement not logged: env values could not be left out';
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
this.variables = variables;
|
|
38
|
+
this.env = env;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Registers a field whose value is in a save statement. With `saveCallHash` (the 12-hex
|
|
42
|
+
* `GenericDatabaseProvider.SaveCallVariableHash` of the record), only the SET line of that save
|
|
43
|
+
* call is replaced. Without it, the SET line of any save call with the same code name and literal
|
|
44
|
+
* is replaced. A null or undefined value is not registered, because no SET line is written for it.
|
|
45
|
+
* A registration stays for the whole push.
|
|
46
|
+
*/
|
|
47
|
+
Register(entityName, fieldName, codeName, value, variableNames, saveCallHash) {
|
|
48
|
+
const literals = SqlLiteralsOf(value);
|
|
49
|
+
if (literals.length === 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const hash = saveCallHash?.toLowerCase() ?? ANY_SAVE_CALL_SUFFIX;
|
|
53
|
+
const fields = this.fieldsForHash(hash);
|
|
54
|
+
const key = [entityName, fieldName, codeName, ...literals].join('\u0000');
|
|
55
|
+
if (fields.has(key)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
fields.set(key, {
|
|
59
|
+
EntityName: entityName,
|
|
60
|
+
FieldName: fieldName,
|
|
61
|
+
Sources: sourcesOf(variableNames),
|
|
62
|
+
Pattern: SetLinePattern(codeName, hash, literals),
|
|
63
|
+
Matched: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** Registers an env-sourced primary key field. Its value stays in the log, so it gives a warning. */
|
|
67
|
+
RegisterPrimaryKey(entityName, fieldName, variableNames) {
|
|
68
|
+
const field = `${entityName}.${fieldName}`;
|
|
69
|
+
const existing = this.primaryKeys.get(field);
|
|
70
|
+
if (existing) {
|
|
71
|
+
variableNames.forEach((name) => existing.Variables.add(name));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.primaryKeys.set(field, { Field: field, Variables: new Set(variableNames) });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Registers the env-sourced fields that the save statement of `entity` holds. Each field is
|
|
79
|
+
* registered at the IS-A level whose table holds it, with that level's save-call hash. A level's
|
|
80
|
+
* statement holds every field when `fullRow` (a create or alwaysPush) or when its entity has no
|
|
81
|
+
* generated update procedure (the full save SQL is logged); else only the changed fields.
|
|
82
|
+
* Key fields give a warning. `envFields` keys are matched without regard to case. Call it right
|
|
83
|
+
* before the save, so the hash uses the key values the provider hashes.
|
|
84
|
+
*/
|
|
85
|
+
RegisterEntityFields(entity, envFields, fullRow) {
|
|
86
|
+
if (!envFields || envFields.size === 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const keyNames = new Set(entity.EntityInfo.PrimaryKeys.map((pk) => pk.Name));
|
|
90
|
+
for (const [key, variables] of envFields) {
|
|
91
|
+
const fieldName = entity.GetFieldByName(key)?.Name ?? key;
|
|
92
|
+
if (keyNames.has(fieldName)) {
|
|
93
|
+
this.RegisterPrimaryKey(entity.EntityInfo.Name, fieldName, variables);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const level = OwningLevel(entity, fieldName);
|
|
97
|
+
const field = level.GetFieldByName(fieldName);
|
|
98
|
+
const levelInfo = level.EntityInfo;
|
|
99
|
+
const holdsField = fullRow || !levelInfo.spUpdateGenerated || fieldName in level.GetChangesSinceLastSave();
|
|
100
|
+
if (field && holdsField) {
|
|
101
|
+
const keyValues = level.PrimaryKey?.KeyValuePairs?.map((pair) => pair.Value) ?? [];
|
|
102
|
+
const saveCallHash = GenericDatabaseProvider.SaveCallVariableHash(levelInfo.SchemaName, levelInfo.BaseTable, keyValues);
|
|
103
|
+
this.Register(levelInfo.Name, fieldName, field.EntityFieldInfo.CodeName, level.Get(fieldName), variables, saveCallHash);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Names-only warnings for the SQL log at `sqlLogPath`. Reads the written log; never throws. */
|
|
108
|
+
Warnings(sqlLogPath) {
|
|
109
|
+
const failure = this.transformFailed
|
|
110
|
+
? [`SQL log ${sqlLogPath}: env values could not be left out of a statement. Check the log before you share it.`]
|
|
111
|
+
: [];
|
|
112
|
+
return [
|
|
113
|
+
...failure,
|
|
114
|
+
...this.unmatchedFieldWarnings(sqlLogPath),
|
|
115
|
+
...this.primaryKeyWarnings(sqlLogPath),
|
|
116
|
+
...this.variableValueWarnings(sqlLogPath),
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
fieldsForHash(hash) {
|
|
120
|
+
let fields = this.fieldsByHash.get(hash);
|
|
121
|
+
if (!fields) {
|
|
122
|
+
fields = new Map();
|
|
123
|
+
this.fieldsByHash.set(hash, fields);
|
|
124
|
+
}
|
|
125
|
+
return fields;
|
|
126
|
+
}
|
|
127
|
+
/** The registrations that can match the statement: those of each suffix in it, and those without a hash. */
|
|
128
|
+
candidateFields(sql) {
|
|
129
|
+
const hashes = SaveCallHashesIn(sql);
|
|
130
|
+
const candidates = [];
|
|
131
|
+
for (const hash of hashes) {
|
|
132
|
+
this.fieldsByHash.get(hash)?.forEach((field) => candidates.push(field));
|
|
133
|
+
}
|
|
134
|
+
return candidates;
|
|
135
|
+
}
|
|
136
|
+
replaceSetLines(sql) {
|
|
137
|
+
if (this.fieldsByHash.size === 0) {
|
|
138
|
+
return sql;
|
|
139
|
+
}
|
|
140
|
+
let result = sql;
|
|
141
|
+
for (const field of this.candidateFields(sql)) {
|
|
142
|
+
const comment = `-- ${field.EntityName}.${field.FieldName}: not recorded, value comes from ${field.Sources}`;
|
|
143
|
+
const next = result.replace(field.Pattern, (_line, indent) => `${indent}${comment}`);
|
|
144
|
+
if (next !== result) {
|
|
145
|
+
field.Matched = true;
|
|
146
|
+
result = next;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
unmatchedFieldWarnings(sqlLogPath) {
|
|
152
|
+
return [...this.fieldsByHash.values()]
|
|
153
|
+
.flatMap((fields) => [...fields.values()])
|
|
154
|
+
.filter((field) => !field.Matched)
|
|
155
|
+
.map((field) => `SQL log ${sqlLogPath}: the line for ${field.EntityName}.${field.FieldName} (from ${field.Sources}) was not found, so its value may be in the log. Check the log before you share it.`);
|
|
156
|
+
}
|
|
157
|
+
primaryKeyWarnings(sqlLogPath) {
|
|
158
|
+
return [...this.primaryKeys.values()].map((key) => `SQL log ${sqlLogPath}: ${key.Field} is a primary key from ${sourcesOf(key.Variables)}. The log holds its value. Check the log before you share it.`);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* For each resolved variable other than a key variable: a warning when its value is in the
|
|
162
|
+
* written log, or when it is not set now and so cannot be checked.
|
|
163
|
+
*/
|
|
164
|
+
variableValueWarnings(sqlLogPath) {
|
|
165
|
+
const logText = readLog(sqlLogPath);
|
|
166
|
+
if (logText === null) {
|
|
167
|
+
return [`SQL log ${sqlLogPath}: the log could not be read to check for env values. Check the log before you share it.`];
|
|
168
|
+
}
|
|
169
|
+
const keyVariables = new Set();
|
|
170
|
+
this.primaryKeys.forEach((key) => key.Variables.forEach((name) => keyVariables.add(name)));
|
|
171
|
+
const warnings = [];
|
|
172
|
+
for (const name of [...this.variables].filter((variable) => !keyVariables.has(variable)).sort()) {
|
|
173
|
+
if (this.env[name] === undefined) {
|
|
174
|
+
warnings.push(`SQL log ${sqlLogPath}: @env:${name} is not set now, so the log could not be checked for its value. Check the log before you share it.`);
|
|
175
|
+
}
|
|
176
|
+
else if (valueIsInText(name, logText, this.env)) {
|
|
177
|
+
warnings.push(`SQL log ${sqlLogPath}: the value of @env:${name} appears in the log. Check the log before you share it.`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return warnings;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** The log text, or null when the file cannot be read. */
|
|
184
|
+
function readLog(sqlLogPath) {
|
|
185
|
+
try {
|
|
186
|
+
return fs.readFileSync(sqlLogPath, 'utf8');
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** True when the variable's value is in the text, found with the same forms and length rule as `EnvDisplayMask.MaskText`. */
|
|
193
|
+
function valueIsInText(name, text, env) {
|
|
194
|
+
return EnvDisplayMask.ForVariables([name], env).MaskText(text) !== text;
|
|
195
|
+
}
|
|
196
|
+
/** `@env:A` or `@env:A, @env:B`, sorted. */
|
|
197
|
+
function sourcesOf(variableNames) {
|
|
198
|
+
return [...variableNames].sort().map((name) => `@env:${name}`).join(', ');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The redactor of one open SQL log, with the `SyncEngine.BeforeLookupCreateSave` hook that registers
|
|
202
|
+
* each record a `?create` lookup creates (with the full row, because a create writes every field).
|
|
203
|
+
*/
|
|
204
|
+
export class EnvSqlLog {
|
|
205
|
+
/** Creates the redactor over the engine's resolved variables and sets the engine's hook. */
|
|
206
|
+
constructor(engine) {
|
|
207
|
+
this.engine = engine;
|
|
208
|
+
this.Redactor = new EnvSqlRedactor(engine.ResolvedEnvVariables);
|
|
209
|
+
this.hook = (created, envFields) => this.Redactor.RegisterEntityFields(created, envFields, true);
|
|
210
|
+
engine.BeforeLookupCreateSave = this.hook;
|
|
211
|
+
}
|
|
212
|
+
/** Clears the engine's hook when it is still this log's hook. */
|
|
213
|
+
Close() {
|
|
214
|
+
if (this.engine.BeforeLookupCreateSave === this.hook) {
|
|
215
|
+
this.engine.BeforeLookupCreateSave = null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Adds a field that was left out because its `?optional` variable is not set. The SQL log then
|
|
221
|
+
* leaves the field's SET line out by name, as for an env-sourced field: a full-row save would
|
|
222
|
+
* otherwise write the field's database value.
|
|
223
|
+
*/
|
|
224
|
+
export function AddSkippedOptionalEnvField(envFields, fieldName, variableName) {
|
|
225
|
+
if (!envFields) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const variables = envFields.get(fieldName) ?? new Set();
|
|
229
|
+
variables.add(variableName);
|
|
230
|
+
envFields.set(fieldName, variables);
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=env-sql-redactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-sql-redactor.js","sourceRoot":"","sources":["../../src/lib/env-sql-redactor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Finds existing file records by a database primary key. An `@env:` key value is
|
|
3
|
+
* replaced by its variable (trimmed) for the match, and UUID key fields are compared without case.
|
|
4
|
+
* @module existing-record-index
|
|
5
|
+
*/
|
|
6
|
+
import type { EntityInfo } from '@memberjunction/core';
|
|
7
|
+
import type { RecordData } from './sync-engine.js';
|
|
8
|
+
import { PrimaryKeyValues } from './record-primary-key.js';
|
|
9
|
+
/** A primaryKey field whose `@env:` variable is not set. Never holds a value. */
|
|
10
|
+
export interface UnsetKeyVariable {
|
|
11
|
+
VariableName: string;
|
|
12
|
+
Field: string;
|
|
13
|
+
/** File that holds the record, when known. */
|
|
14
|
+
FilePath?: string;
|
|
15
|
+
}
|
|
16
|
+
/** One existing file record. */
|
|
17
|
+
export interface ExistingRecordEntry {
|
|
18
|
+
Record: RecordData;
|
|
19
|
+
/** File that holds the record, when known. */
|
|
20
|
+
FilePath?: string;
|
|
21
|
+
/** True when the file holds an array of records. */
|
|
22
|
+
InArray?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Thrown when a primaryKey `@env:` variable is not set, so pull cannot match the record. */
|
|
25
|
+
export declare class UnsetPrimaryKeyVariableError extends Error {
|
|
26
|
+
readonly Variables: ReadonlyArray<UnsetKeyVariable>;
|
|
27
|
+
/** Entity whose key uses the variables. */
|
|
28
|
+
readonly EntityName: string;
|
|
29
|
+
/** Entity the user pulls, when it differs from `EntityName`. */
|
|
30
|
+
readonly PulledEntityName?: string;
|
|
31
|
+
constructor(entityName: string, variables: ReadonlyArray<UnsetKeyVariable>, pulledEntityName?: string);
|
|
32
|
+
/** The same error with `filePath` on each variable that names no file, and the entity the user pulls. */
|
|
33
|
+
InRecordFile(filePath: string | undefined, pulledEntityName: string): UnsetPrimaryKeyVariableError;
|
|
34
|
+
}
|
|
35
|
+
/** Existing file records, found by the database primary key. The first record wins for a repeated key. */
|
|
36
|
+
export declare class ExistingRecordIndex {
|
|
37
|
+
private readonly uuidFields;
|
|
38
|
+
private readonly env;
|
|
39
|
+
private readonly byKey;
|
|
40
|
+
private readonly unsetVariables;
|
|
41
|
+
private duplicates;
|
|
42
|
+
private constructor();
|
|
43
|
+
/** Indexes the entries. Records without a primaryKey, or with an unset key variable, are not indexed. */
|
|
44
|
+
static Build(entries: ReadonlyArray<ExistingRecordEntry>, entityInfo: EntityInfo | null | undefined, env?: NodeJS.ProcessEnv): ExistingRecordIndex;
|
|
45
|
+
/** The lookup string of a record as the file writes it, for `FileWriteBatch` array updates. */
|
|
46
|
+
static FileLookupOf(record: RecordData): string;
|
|
47
|
+
/** Key variables that are not set. The records that use them are not indexed. */
|
|
48
|
+
get UnsetKeyVariables(): ReadonlyArray<UnsetKeyVariable>;
|
|
49
|
+
/** Number of records whose key repeats an earlier record's key. */
|
|
50
|
+
get DuplicateCount(): number;
|
|
51
|
+
/** @throws UnsetPrimaryKeyVariableError when any key variable is not set */
|
|
52
|
+
ThrowIfUnsetKeyVariables(entityName: string): void;
|
|
53
|
+
/** The existing entry whose resolved key equals the database key, or undefined. */
|
|
54
|
+
Find(databaseKey: PrimaryKeyValues): ExistingRecordEntry | undefined;
|
|
55
|
+
/** The match string of a database key. */
|
|
56
|
+
MatchKey(databaseKey: PrimaryKeyValues): string;
|
|
57
|
+
/** The match string of a file record's key, or null when the key is empty or a key variable is not set. */
|
|
58
|
+
KeyOf(record: RecordData): string | null;
|
|
59
|
+
private add;
|
|
60
|
+
/** A file key value as text: the variable (trimmed) for `@env:`, the value otherwise; null when unusable. */
|
|
61
|
+
private resolve;
|
|
62
|
+
/** Trimmed, as a fixed-width key is padded; UUID fields lowercased. */
|
|
63
|
+
private normalize;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The primary key pull writes: the file's `@env:` value for each field whose variable (trimmed)
|
|
67
|
+
* equals the database value, with UUID fields compared without case; the database value otherwise.
|
|
68
|
+
*/
|
|
69
|
+
export declare function KeepPrimaryKeyEnvReferences(fileKey: Record<string, unknown> | undefined, databaseKey: Record<string, unknown>, entityInfo: EntityInfo | null | undefined, env?: NodeJS.ProcessEnv): Record<string, unknown>;
|
|
70
|
+
//# sourceMappingURL=existing-record-index.d.ts.map
|