@caracal-lynx/sluice 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1822 -0
- package/LICENCE-FAQ.md +74 -0
- package/LICENSE +92 -0
- package/README.md +582 -0
- package/dist/adapters/source/csv.d.ts +10 -0
- package/dist/adapters/source/csv.d.ts.map +1 -0
- package/dist/adapters/source/csv.js +110 -0
- package/dist/adapters/source/csv.js.map +1 -0
- package/dist/adapters/source/index.d.ts +9 -0
- package/dist/adapters/source/index.d.ts.map +1 -0
- package/dist/adapters/source/index.js +26 -0
- package/dist/adapters/source/index.js.map +1 -0
- package/dist/adapters/source/mssql.d.ts +11 -0
- package/dist/adapters/source/mssql.d.ts.map +1 -0
- package/dist/adapters/source/mssql.js +230 -0
- package/dist/adapters/source/mssql.js.map +1 -0
- package/dist/adapters/source/pg.d.ts +11 -0
- package/dist/adapters/source/pg.d.ts.map +1 -0
- package/dist/adapters/source/pg.js +88 -0
- package/dist/adapters/source/pg.js.map +1 -0
- package/dist/adapters/source/registry.d.ts +10 -0
- package/dist/adapters/source/registry.d.ts.map +1 -0
- package/dist/adapters/source/registry.js +36 -0
- package/dist/adapters/source/registry.js.map +1 -0
- package/dist/adapters/source/rest.d.ts +16 -0
- package/dist/adapters/source/rest.d.ts.map +1 -0
- package/dist/adapters/source/rest.js +182 -0
- package/dist/adapters/source/rest.js.map +1 -0
- package/dist/adapters/source/rest.types.d.ts +15 -0
- package/dist/adapters/source/rest.types.d.ts.map +1 -0
- package/dist/adapters/source/rest.types.js +6 -0
- package/dist/adapters/source/rest.types.js.map +1 -0
- package/dist/adapters/source/types.d.ts +23 -0
- package/dist/adapters/source/types.d.ts.map +1 -0
- package/dist/adapters/source/types.js +4 -0
- package/dist/adapters/source/types.js.map +1 -0
- package/dist/adapters/source/xlsx.d.ts +10 -0
- package/dist/adapters/source/xlsx.d.ts.map +1 -0
- package/dist/adapters/source/xlsx.js +71 -0
- package/dist/adapters/source/xlsx.js.map +1 -0
- package/dist/adapters/target/bc.d.ts +21 -0
- package/dist/adapters/target/bc.d.ts.map +1 -0
- package/dist/adapters/target/bc.js +188 -0
- package/dist/adapters/target/bc.js.map +1 -0
- package/dist/adapters/target/bluecherry.d.ts +10 -0
- package/dist/adapters/target/bluecherry.d.ts.map +1 -0
- package/dist/adapters/target/bluecherry.js +127 -0
- package/dist/adapters/target/bluecherry.js.map +1 -0
- package/dist/adapters/target/csv.d.ts +10 -0
- package/dist/adapters/target/csv.d.ts.map +1 -0
- package/dist/adapters/target/csv.js +40 -0
- package/dist/adapters/target/csv.js.map +1 -0
- package/dist/adapters/target/ifs.d.ts +10 -0
- package/dist/adapters/target/ifs.d.ts.map +1 -0
- package/dist/adapters/target/ifs.js +55 -0
- package/dist/adapters/target/ifs.js.map +1 -0
- package/dist/adapters/target/index.d.ts +8 -0
- package/dist/adapters/target/index.d.ts.map +1 -0
- package/dist/adapters/target/index.js +22 -0
- package/dist/adapters/target/index.js.map +1 -0
- package/dist/adapters/target/pg.d.ts +11 -0
- package/dist/adapters/target/pg.d.ts.map +1 -0
- package/dist/adapters/target/pg.js +103 -0
- package/dist/adapters/target/pg.js.map +1 -0
- package/dist/adapters/target/registry.d.ts +9 -0
- package/dist/adapters/target/registry.d.ts.map +1 -0
- package/dist/adapters/target/registry.js +29 -0
- package/dist/adapters/target/registry.js.map +1 -0
- package/dist/adapters/target/types.d.ts +15 -0
- package/dist/adapters/target/types.d.ts.map +1 -0
- package/dist/adapters/target/types.js +4 -0
- package/dist/adapters/target/types.js.map +1 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +135 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +4162 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +263 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +3 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +4 -0
- package/dist/config/types.js.map +1 -0
- package/dist/dq/engine.d.ts +10 -0
- package/dist/dq/engine.d.ts.map +1 -0
- package/dist/dq/engine.js +114 -0
- package/dist/dq/engine.js.map +1 -0
- package/dist/dq/index.d.ts +6 -0
- package/dist/dq/index.d.ts.map +1 -0
- package/dist/dq/index.js +6 -0
- package/dist/dq/index.js.map +1 -0
- package/dist/dq/reporter.d.ts +5 -0
- package/dist/dq/reporter.d.ts.map +1 -0
- package/dist/dq/reporter.js +41 -0
- package/dist/dq/reporter.js.map +1 -0
- package/dist/dq/rules/allowedValues.d.ts +7 -0
- package/dist/dq/rules/allowedValues.d.ts.map +1 -0
- package/dist/dq/rules/allowedValues.js +26 -0
- package/dist/dq/rules/allowedValues.js.map +1 -0
- package/dist/dq/rules/email.d.ts +7 -0
- package/dist/dq/rules/email.d.ts.map +1 -0
- package/dist/dq/rules/email.js +24 -0
- package/dist/dq/rules/email.js.map +1 -0
- package/dist/dq/rules/index.d.ts +15 -0
- package/dist/dq/rules/index.d.ts.map +1 -0
- package/dist/dq/rules/index.js +30 -0
- package/dist/dq/rules/index.js.map +1 -0
- package/dist/dq/rules/maxLength.d.ts +7 -0
- package/dist/dq/rules/maxLength.d.ts.map +1 -0
- package/dist/dq/rules/maxLength.js +25 -0
- package/dist/dq/rules/maxLength.js.map +1 -0
- package/dist/dq/rules/minMax.d.ts +11 -0
- package/dist/dq/rules/minMax.d.ts.map +1 -0
- package/dist/dq/rules/minMax.js +52 -0
- package/dist/dq/rules/minMax.js.map +1 -0
- package/dist/dq/rules/notNull.d.ts +7 -0
- package/dist/dq/rules/notNull.d.ts.map +1 -0
- package/dist/dq/rules/notNull.js +21 -0
- package/dist/dq/rules/notNull.js.map +1 -0
- package/dist/dq/rules/pattern.d.ts +7 -0
- package/dist/dq/rules/pattern.d.ts.map +1 -0
- package/dist/dq/rules/pattern.js +31 -0
- package/dist/dq/rules/pattern.js.map +1 -0
- package/dist/dq/rules/types.d.ts +6 -0
- package/dist/dq/rules/types.d.ts.map +1 -0
- package/dist/dq/rules/types.js +4 -0
- package/dist/dq/rules/types.js.map +1 -0
- package/dist/dq/rules/ukPostcode.d.ts +7 -0
- package/dist/dq/rules/ukPostcode.d.ts.map +1 -0
- package/dist/dq/rules/ukPostcode.js +24 -0
- package/dist/dq/rules/ukPostcode.js.map +1 -0
- package/dist/dq/rules/unique.d.ts +14 -0
- package/dist/dq/rules/unique.d.ts.map +1 -0
- package/dist/dq/rules/unique.js +9 -0
- package/dist/dq/rules/unique.js.map +1 -0
- package/dist/dq/types.d.ts +29 -0
- package/dist/dq/types.d.ts.map +1 -0
- package/dist/dq/types.js +4 -0
- package/dist/dq/types.js.map +1 -0
- package/dist/enrich/types.d.ts +87 -0
- package/dist/enrich/types.d.ts.map +1 -0
- package/dist/enrich/types.js +4 -0
- package/dist/enrich/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/merge/conflict-log.d.ts +9 -0
- package/dist/merge/conflict-log.d.ts.map +1 -0
- package/dist/merge/conflict-log.js +28 -0
- package/dist/merge/conflict-log.js.map +1 -0
- package/dist/merge/engine.d.ts +7 -0
- package/dist/merge/engine.d.ts.map +1 -0
- package/dist/merge/engine.js +19 -0
- package/dist/merge/engine.js.map +1 -0
- package/dist/merge/index.d.ts +11 -0
- package/dist/merge/index.d.ts.map +1 -0
- package/dist/merge/index.js +34 -0
- package/dist/merge/index.js.map +1 -0
- package/dist/merge/sql-builder.d.ts +19 -0
- package/dist/merge/sql-builder.d.ts.map +1 -0
- package/dist/merge/sql-builder.js +148 -0
- package/dist/merge/sql-builder.js.map +1 -0
- package/dist/merge/strategies/coalesce.d.ts +17 -0
- package/dist/merge/strategies/coalesce.d.ts.map +1 -0
- package/dist/merge/strategies/coalesce.js +77 -0
- package/dist/merge/strategies/coalesce.js.map +1 -0
- package/dist/merge/strategies/index.d.ts +5 -0
- package/dist/merge/strategies/index.d.ts.map +1 -0
- package/dist/merge/strategies/index.js +7 -0
- package/dist/merge/strategies/index.js.map +1 -0
- package/dist/merge/strategies/intersect.d.ts +17 -0
- package/dist/merge/strategies/intersect.d.ts.map +1 -0
- package/dist/merge/strategies/intersect.js +75 -0
- package/dist/merge/strategies/intersect.js.map +1 -0
- package/dist/merge/strategies/priority-override.d.ts +16 -0
- package/dist/merge/strategies/priority-override.d.ts.map +1 -0
- package/dist/merge/strategies/priority-override.js +78 -0
- package/dist/merge/strategies/priority-override.js.map +1 -0
- package/dist/merge/strategies/registry.d.ts +8 -0
- package/dist/merge/strategies/registry.d.ts.map +1 -0
- package/dist/merge/strategies/registry.js +19 -0
- package/dist/merge/strategies/registry.js.map +1 -0
- package/dist/merge/strategies/union.d.ts +15 -0
- package/dist/merge/strategies/union.d.ts.map +1 -0
- package/dist/merge/strategies/union.js +75 -0
- package/dist/merge/strategies/union.js.map +1 -0
- package/dist/merge/types.d.ts +24 -0
- package/dist/merge/types.d.ts.map +1 -0
- package/dist/merge/types.js +4 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/multi-source-runner.d.ts +22 -0
- package/dist/multi-source-runner.d.ts.map +1 -0
- package/dist/multi-source-runner.js +398 -0
- package/dist/multi-source-runner.js.map +1 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +22 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +151 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/registry.d.ts +25 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +42 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +61 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +4 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/runner.d.ts +97 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +520 -0
- package/dist/runner.js.map +1 -0
- package/dist/staging/index.d.ts +3 -0
- package/dist/staging/index.d.ts.map +1 -0
- package/dist/staging/index.js +5 -0
- package/dist/staging/index.js.map +1 -0
- package/dist/staging/schema.d.ts +19 -0
- package/dist/staging/schema.d.ts.map +1 -0
- package/dist/staging/schema.js +15 -0
- package/dist/staging/schema.js.map +1 -0
- package/dist/staging/store.d.ts +71 -0
- package/dist/staging/store.d.ts.map +1 -0
- package/dist/staging/store.js +270 -0
- package/dist/staging/store.js.map +1 -0
- package/dist/transform/cleanse.d.ts +2 -0
- package/dist/transform/cleanse.d.ts.map +1 -0
- package/dist/transform/cleanse.js +59 -0
- package/dist/transform/cleanse.js.map +1 -0
- package/dist/transform/engine.d.ts +10 -0
- package/dist/transform/engine.d.ts.map +1 -0
- package/dist/transform/engine.js +225 -0
- package/dist/transform/engine.js.map +1 -0
- package/dist/transform/expression.d.ts +5 -0
- package/dist/transform/expression.d.ts.map +1 -0
- package/dist/transform/expression.js +52 -0
- package/dist/transform/expression.js.map +1 -0
- package/dist/transform/index.d.ts +6 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +7 -0
- package/dist/transform/index.js.map +1 -0
- package/dist/transform/lookup.d.ts +10 -0
- package/dist/transform/lookup.d.ts.map +1 -0
- package/dist/transform/lookup.js +66 -0
- package/dist/transform/lookup.js.map +1 -0
- package/dist/transform/types.d.ts +10 -0
- package/dist/transform/types.d.ts.map +1 -0
- package/dist/transform/types.js +4 -0
- package/dist/transform/types.js.map +1 -0
- package/dist/utils/env.d.ts +3 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +26 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/errors.d.ts +26 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +39 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +16 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/progress.d.ts +66 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +283 -0
- package/dist/utils/progress.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/merge/engine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,WAAW;IAChB,GAAG,CACP,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,eAAe,EAAE,EAC7B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC;CAaxB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
import { MergeStrategyRegistry } from './index.js';
|
|
5
|
+
export class MergeEngine {
|
|
6
|
+
async run(store, rawSources, config) {
|
|
7
|
+
const strategyId = config.strategy ?? 'coalesce';
|
|
8
|
+
const strategy = MergeStrategyRegistry.get(strategyId);
|
|
9
|
+
logger.info({ strategy: strategyId }, 'merge: starting');
|
|
10
|
+
try {
|
|
11
|
+
return await strategy.merge(store, rawSources, config);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
logger.error({ err, strategy: strategyId }, 'merge: failed');
|
|
15
|
+
throw err;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/merge/engine.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAIvC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGnD,MAAM,OAAO,WAAW;IACtB,KAAK,CAAC,GAAG,CACP,KAAmB,EACnB,UAA6B,EAC7B,MAAmB;QAEnB,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,IAAI,UAAU,CAAC;QACjD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAEzD,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,eAAe,CAAC,CAAC;YAC7D,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MergeStrategyPlugin } from './types.js';
|
|
2
|
+
export { MergeEngine } from './engine.js';
|
|
3
|
+
export type { BuildMergeContext } from './sql-builder.js';
|
|
4
|
+
export declare const MergeStrategyRegistry: {
|
|
5
|
+
register(plugin: MergeStrategyPlugin): void;
|
|
6
|
+
get(id: string): MergeStrategyPlugin;
|
|
7
|
+
has(id: string): boolean;
|
|
8
|
+
list(): string[];
|
|
9
|
+
};
|
|
10
|
+
export type { MergeStrategyPlugin, MergeSourceMeta, MergeResult } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/merge/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAOtD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAU1D,eAAO,MAAM,qBAAqB;qBACf,mBAAmB,GAAG,IAAI;YAInC,MAAM,GAAG,mBAAmB;YAW5B,MAAM,GAAG,OAAO;YAIhB,MAAM,EAAE;CAGjB,CAAC;AAEF,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { ConfigError } from '../utils/errors.js';
|
|
4
|
+
import { coalesceStrategy } from './strategies/coalesce.js';
|
|
5
|
+
import { unionStrategy } from './strategies/union.js';
|
|
6
|
+
import { intersectStrategy } from './strategies/intersect.js';
|
|
7
|
+
import { priorityOverrideStrategy } from './strategies/priority-override.js';
|
|
8
|
+
export { MergeEngine } from './engine.js';
|
|
9
|
+
const registry = new Map();
|
|
10
|
+
// Pre-register all built-in strategies
|
|
11
|
+
registry.set(coalesceStrategy.id, coalesceStrategy);
|
|
12
|
+
registry.set(unionStrategy.id, unionStrategy);
|
|
13
|
+
registry.set(intersectStrategy.id, intersectStrategy);
|
|
14
|
+
registry.set(priorityOverrideStrategy.id, priorityOverrideStrategy);
|
|
15
|
+
export const MergeStrategyRegistry = {
|
|
16
|
+
register(plugin) {
|
|
17
|
+
registry.set(plugin.id, plugin);
|
|
18
|
+
},
|
|
19
|
+
get(id) {
|
|
20
|
+
const plugin = registry.get(id);
|
|
21
|
+
if (!plugin) {
|
|
22
|
+
const supported = Array.from(registry.keys()).join(', ');
|
|
23
|
+
throw new ConfigError(`No merge strategy registered for id '${id}'. Supported: ${supported}`);
|
|
24
|
+
}
|
|
25
|
+
return plugin;
|
|
26
|
+
},
|
|
27
|
+
has(id) {
|
|
28
|
+
return registry.has(id);
|
|
29
|
+
},
|
|
30
|
+
list() {
|
|
31
|
+
return Array.from(registry.keys());
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/merge/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAE7E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;AAExD,uCAAuC;AACvC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;AACpD,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;AAC9C,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACtD,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC;AAEpE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,QAAQ,CAAC,MAA2B;QAClC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzD,MAAM,IAAI,WAAW,CACnB,wCAAwC,EAAE,iBAAiB,SAAS,EAAE,CACvE,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MergeConfig } from '../config/types.js';
|
|
2
|
+
import type { MergeSourceMeta } from './types.js';
|
|
3
|
+
export interface BuildMergeContext {
|
|
4
|
+
sources: MergeSourceMeta[];
|
|
5
|
+
keyColumns: string[];
|
|
6
|
+
sourceColumns: Record<string, string[]>;
|
|
7
|
+
}
|
|
8
|
+
export declare function normalizeKeyColumns(key: MergeConfig['key']): string[];
|
|
9
|
+
export declare function prefixedColumn(sourceId: string, column: string): string;
|
|
10
|
+
export declare function sourceHasColumn(sourceColumns: Record<string, string[]>, sourceId: string, column: string): boolean;
|
|
11
|
+
export declare function buildPresenceExpr(sourceId: string, keyColumns: string[]): string;
|
|
12
|
+
export declare function buildPresentCountExpr(sources: MergeSourceMeta[], keyColumns: string[]): string;
|
|
13
|
+
export declare function buildCoalescedKeyExpr(sources: MergeSourceMeta[], key: string): string;
|
|
14
|
+
export declare function buildConflictPredicate(columnRefs: string[]): string;
|
|
15
|
+
export declare function buildJoinedTableSql(joinedTable: string, context: BuildMergeContext): string;
|
|
16
|
+
export declare function buildFieldValueExpr(column: string, context: BuildMergeContext, strategy: MergeConfig['strategy'], forcedSource?: string): string;
|
|
17
|
+
export declare function buildMergedTableSql(mergedTable: string, joinedTable: string, context: BuildMergeContext, config: MergeConfig, outputColumns: string[]): string;
|
|
18
|
+
export declare function buildConflictFieldSelectSql(joinedTable: string, context: BuildMergeContext, field: string, config: MergeConfig): string | null;
|
|
19
|
+
//# sourceMappingURL=sql-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-builder.d.ts","sourceRoot":"","sources":["../../src/merge/sql-builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACzC;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAErE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAET;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAKhF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAE9F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGrF;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAWnE;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,MAAM,CAiCR;AA8BD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EACjC,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAgBR;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,WAAW,EACnB,aAAa,EAAE,MAAM,EAAE,GACtB,MAAM,CAwBR;AAED,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,GAClB,MAAM,GAAG,IAAI,CAyBf"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { quoteIdent } from '../staging/index.js';
|
|
4
|
+
export function normalizeKeyColumns(key) {
|
|
5
|
+
return Array.isArray(key) ? key : [key];
|
|
6
|
+
}
|
|
7
|
+
export function prefixedColumn(sourceId, column) {
|
|
8
|
+
return `${sourceId}__${column}`;
|
|
9
|
+
}
|
|
10
|
+
export function sourceHasColumn(sourceColumns, sourceId, column) {
|
|
11
|
+
return (sourceColumns[sourceId] ?? []).includes(column);
|
|
12
|
+
}
|
|
13
|
+
export function buildPresenceExpr(sourceId, keyColumns) {
|
|
14
|
+
const checks = keyColumns
|
|
15
|
+
.map((k) => `${quoteIdent(prefixedColumn(sourceId, k))} IS NOT NULL`)
|
|
16
|
+
.join(' AND ');
|
|
17
|
+
return `CASE WHEN ${checks} THEN 1 ELSE 0 END`;
|
|
18
|
+
}
|
|
19
|
+
export function buildPresentCountExpr(sources, keyColumns) {
|
|
20
|
+
return sources.map((s) => `(${buildPresenceExpr(s.id, keyColumns)})`).join(' + ');
|
|
21
|
+
}
|
|
22
|
+
export function buildCoalescedKeyExpr(sources, key) {
|
|
23
|
+
const refs = sources.map((s) => `${quoteIdent(prefixedColumn(s.id, key))}`);
|
|
24
|
+
return `COALESCE(${refs.join(', ')})`;
|
|
25
|
+
}
|
|
26
|
+
export function buildConflictPredicate(columnRefs) {
|
|
27
|
+
const normalized = columnRefs.map((r) => `NULLIF(TRIM(CAST(${r} AS VARCHAR)), '')`);
|
|
28
|
+
const pairs = [];
|
|
29
|
+
for (let i = 0; i < normalized.length; i += 1) {
|
|
30
|
+
for (let j = i + 1; j < normalized.length; j += 1) {
|
|
31
|
+
const left = normalized[i];
|
|
32
|
+
const right = normalized[j];
|
|
33
|
+
pairs.push(`(${left} IS NOT NULL AND ${right} IS NOT NULL AND ${left} <> ${right})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return pairs.length > 0 ? `(${pairs.join(' OR ')})` : 'FALSE';
|
|
37
|
+
}
|
|
38
|
+
export function buildJoinedTableSql(joinedTable, context) {
|
|
39
|
+
const { sources, keyColumns, sourceColumns } = context;
|
|
40
|
+
const aliases = sources.map((_s, idx) => `s${idx}`);
|
|
41
|
+
const selectList = [];
|
|
42
|
+
for (let i = 0; i < sources.length; i += 1) {
|
|
43
|
+
const source = sources[i];
|
|
44
|
+
const alias = aliases[i];
|
|
45
|
+
for (const col of sourceColumns[source.id] ?? []) {
|
|
46
|
+
selectList.push(`${alias}.${quoteIdent(col)} AS ${quoteIdent(prefixedColumn(source.id, col))}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const from = `${quoteIdent(sources[0].tableName)} ${aliases[0]}`;
|
|
50
|
+
const joins = [];
|
|
51
|
+
for (let i = 1; i < sources.length; i += 1) {
|
|
52
|
+
const source = sources[i];
|
|
53
|
+
const alias = aliases[i];
|
|
54
|
+
const prevAliases = aliases.slice(0, i);
|
|
55
|
+
const on = keyColumns
|
|
56
|
+
.map((k) => {
|
|
57
|
+
const left = `COALESCE(${prevAliases.map((a) => `${a}.${quoteIdent(k)}`).join(', ')})`;
|
|
58
|
+
const right = `${alias}.${quoteIdent(k)}`;
|
|
59
|
+
return `${left} = ${right}`;
|
|
60
|
+
})
|
|
61
|
+
.join(' AND ');
|
|
62
|
+
joins.push(`FULL OUTER JOIN ${quoteIdent(source.tableName)} ${alias} ON ${on}`);
|
|
63
|
+
}
|
|
64
|
+
return `CREATE OR REPLACE TABLE ${quoteIdent(joinedTable)} AS SELECT ${selectList.join(', ')} FROM ${from} ${joins.join(' ')}`;
|
|
65
|
+
}
|
|
66
|
+
function buildFieldWinnerSourceExpr(column, context, strategy, forcedSource) {
|
|
67
|
+
const refs = context.sources
|
|
68
|
+
.filter((s) => sourceHasColumn(context.sourceColumns, s.id, column))
|
|
69
|
+
.map((s) => ({
|
|
70
|
+
sourceId: s.id,
|
|
71
|
+
valueRef: quoteIdent(prefixedColumn(s.id, column)),
|
|
72
|
+
presentRef: buildPresenceExpr(s.id, context.keyColumns),
|
|
73
|
+
}));
|
|
74
|
+
if (forcedSource) {
|
|
75
|
+
return `'${forcedSource.replace(/'/g, "''")}'`;
|
|
76
|
+
}
|
|
77
|
+
if (refs.length === 0)
|
|
78
|
+
return 'NULL';
|
|
79
|
+
const whenClauses = refs.map((r) => {
|
|
80
|
+
if (strategy === 'priority-override') {
|
|
81
|
+
return `WHEN ${r.presentRef} = 1 THEN '${r.sourceId.replace(/'/g, "''")}'`;
|
|
82
|
+
}
|
|
83
|
+
return `WHEN NULLIF(TRIM(CAST(${r.valueRef} AS VARCHAR)), '') IS NOT NULL THEN '${r.sourceId.replace(/'/g, "''")}'`;
|
|
84
|
+
});
|
|
85
|
+
return `CASE ${whenClauses.join(' ')} ELSE NULL END`;
|
|
86
|
+
}
|
|
87
|
+
export function buildFieldValueExpr(column, context, strategy, forcedSource) {
|
|
88
|
+
if (forcedSource) {
|
|
89
|
+
if (!sourceHasColumn(context.sourceColumns, forcedSource, column)) {
|
|
90
|
+
return 'NULL';
|
|
91
|
+
}
|
|
92
|
+
return quoteIdent(prefixedColumn(forcedSource, column));
|
|
93
|
+
}
|
|
94
|
+
const refs = context.sources
|
|
95
|
+
.filter((s) => sourceHasColumn(context.sourceColumns, s.id, column))
|
|
96
|
+
.map((s) => quoteIdent(prefixedColumn(s.id, column)));
|
|
97
|
+
if (refs.length === 0)
|
|
98
|
+
return 'NULL';
|
|
99
|
+
if (strategy === 'priority-override')
|
|
100
|
+
return refs[0];
|
|
101
|
+
const normalizedRefs = refs.map((r) => `NULLIF(TRIM(CAST(${r} AS VARCHAR)), '')`);
|
|
102
|
+
return `COALESCE(${normalizedRefs.join(', ')})`;
|
|
103
|
+
}
|
|
104
|
+
export function buildMergedTableSql(mergedTable, joinedTable, context, config, outputColumns) {
|
|
105
|
+
const fieldStrategyMap = new Map((config.fieldStrategies ?? []).map((f) => [f.field, f]));
|
|
106
|
+
const presentCountExpr = buildPresentCountExpr(context.sources, context.keyColumns);
|
|
107
|
+
const selectList = outputColumns
|
|
108
|
+
.map((col) => {
|
|
109
|
+
const override = fieldStrategyMap.get(col);
|
|
110
|
+
const forcedSource = override?.source;
|
|
111
|
+
const strategy = override?.strategy ?? config.strategy;
|
|
112
|
+
const valueExpr = buildFieldValueExpr(col, context, strategy, forcedSource);
|
|
113
|
+
return `${valueExpr} AS ${quoteIdent(col)}`;
|
|
114
|
+
})
|
|
115
|
+
.join(', ');
|
|
116
|
+
let whereClause = '';
|
|
117
|
+
if (config.strategy === 'intersect') {
|
|
118
|
+
whereClause = ` WHERE (${presentCountExpr}) = ${context.sources.length}`;
|
|
119
|
+
}
|
|
120
|
+
else if (config.onUnmatched === 'exclude') {
|
|
121
|
+
whereClause = ` WHERE (${presentCountExpr}) > 1`;
|
|
122
|
+
}
|
|
123
|
+
return `CREATE OR REPLACE TABLE ${quoteIdent(mergedTable)} AS SELECT ${selectList} FROM ${quoteIdent(joinedTable)}${whereClause}`;
|
|
124
|
+
}
|
|
125
|
+
export function buildConflictFieldSelectSql(joinedTable, context, field, config) {
|
|
126
|
+
const override = (config.fieldStrategies ?? []).find((s) => s.field === field);
|
|
127
|
+
const forcedSource = override?.source;
|
|
128
|
+
const strategy = override?.strategy ?? config.strategy;
|
|
129
|
+
const refs = context.sources
|
|
130
|
+
.filter((s) => sourceHasColumn(context.sourceColumns, s.id, field))
|
|
131
|
+
.map((s) => ({
|
|
132
|
+
sourceId: s.id,
|
|
133
|
+
ref: quoteIdent(prefixedColumn(s.id, field)),
|
|
134
|
+
}));
|
|
135
|
+
if (refs.length < 2)
|
|
136
|
+
return null;
|
|
137
|
+
const keySelect = context.keyColumns
|
|
138
|
+
.map((k) => `${buildCoalescedKeyExpr(context.sources, k)} AS ${quoteIdent(k)}`)
|
|
139
|
+
.join(', ');
|
|
140
|
+
const valueExpr = buildFieldValueExpr(field, context, strategy, forcedSource);
|
|
141
|
+
const winnerExpr = buildFieldWinnerSourceExpr(field, context, strategy, forcedSource);
|
|
142
|
+
const conflictPredicate = buildConflictPredicate(refs.map((r) => r.ref));
|
|
143
|
+
const sourceValuesExpr = refs
|
|
144
|
+
.map((r) => `'${r.sourceId.replace(/'/g, "''")}=' || COALESCE(CAST(${r.ref} AS VARCHAR), '<null>')`)
|
|
145
|
+
.join(` || '; ' || `);
|
|
146
|
+
return `SELECT ${keySelect}, '${field.replace(/'/g, "''")}' AS field, ${winnerExpr} AS winning_source, CAST(${valueExpr} AS VARCHAR) AS winning_value, ${sourceValuesExpr} AS source_values FROM ${quoteIdent(joinedTable)} WHERE ${conflictPredicate}`;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=sql-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-builder.js","sourceRoot":"","sources":["../../src/merge/sql-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge strategy: COALESCE
|
|
3
|
+
*
|
|
4
|
+
* For each field, selects the first non-null value across sources,
|
|
5
|
+
* respecting the priority order (lower priority = checked first).
|
|
6
|
+
* Whitespace-only values are treated as blank and skipped.
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
* Source A (priority 1): STYLE_DESC = null
|
|
10
|
+
* Source B (priority 2): STYLE_DESC = "FromExcel"
|
|
11
|
+
* → Result: STYLE_DESC = "FromExcel"
|
|
12
|
+
*
|
|
13
|
+
* Unmatched rows (present in only one source) are included by default.
|
|
14
|
+
*/
|
|
15
|
+
import type { MergeStrategyPlugin } from '../types.js';
|
|
16
|
+
export declare const coalesceStrategy: MergeStrategyPlugin;
|
|
17
|
+
//# sourceMappingURL=coalesce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coalesce.d.ts","sourceRoot":"","sources":["../../../src/merge/strategies/coalesce.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAiBvD,eAAO,MAAM,gBAAgB,EAAE,mBAsG9B,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { quoteIdent } from '../../staging/index.js';
|
|
4
|
+
import { logger } from '../../utils/logger.js';
|
|
5
|
+
import { buildJoinedTableSql, buildMergedTableSql, buildPresentCountExpr, normalizeKeyColumns, } from '../sql-builder.js';
|
|
6
|
+
import { buildConflictLog } from '../conflict-log.js';
|
|
7
|
+
import { ConfigError, PipelineError } from '../../utils/errors.js';
|
|
8
|
+
export const coalesceStrategy = {
|
|
9
|
+
id: 'coalesce',
|
|
10
|
+
description: 'First non-null value wins. Coalesces each field across sources in priority order; includes unmatched rows by default.',
|
|
11
|
+
async merge(store, rawSources, config) {
|
|
12
|
+
if (rawSources.length < 2) {
|
|
13
|
+
throw new ConfigError('merge requires at least 2 sources');
|
|
14
|
+
}
|
|
15
|
+
const sources = [...rawSources].sort((a, b) => a.priority - b.priority);
|
|
16
|
+
const keyColumns = normalizeKeyColumns(config.key);
|
|
17
|
+
const sourceColumns = {};
|
|
18
|
+
for (const source of sources) {
|
|
19
|
+
sourceColumns[source.id] = await store.columnNames(source.tableName);
|
|
20
|
+
for (const key of keyColumns) {
|
|
21
|
+
if (!sourceColumns[source.id].includes(key)) {
|
|
22
|
+
throw new ConfigError(`merge key column '${key}' is missing from source '${source.id}' table '${source.tableName}'`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const context = { sources, keyColumns, sourceColumns };
|
|
27
|
+
// Build the joined table (FULL OUTER JOIN on keys)
|
|
28
|
+
const joinedTable = 'stg_merge_joined';
|
|
29
|
+
await store.query(buildJoinedTableSql(joinedTable, context));
|
|
30
|
+
// Check for unmatched rows and handle per config
|
|
31
|
+
const presentCountExpr = buildPresentCountExpr(sources, keyColumns);
|
|
32
|
+
const unmatchedRows = await store.query(`SELECT count(*) AS n FROM ${quoteIdent(joinedTable)} WHERE (${presentCountExpr}) = 1`);
|
|
33
|
+
const unmatched = Number(unmatchedRows[0]?.n ?? 0);
|
|
34
|
+
if (config.onUnmatched === 'error' && unmatched > 0) {
|
|
35
|
+
throw new PipelineError(`merge halted: ${unmatched} unmatched row(s) encountered with onUnmatched=error`);
|
|
36
|
+
}
|
|
37
|
+
if (config.onUnmatched === 'warn' && unmatched > 0) {
|
|
38
|
+
logger.warn({ unmatched }, 'merge: unmatched rows present');
|
|
39
|
+
}
|
|
40
|
+
// Build output columns in order: keys first, then all non-key columns
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
const outputColumns = [];
|
|
43
|
+
for (const key of keyColumns) {
|
|
44
|
+
if (!seen.has(key)) {
|
|
45
|
+
seen.add(key);
|
|
46
|
+
outputColumns.push(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const source of sources) {
|
|
50
|
+
for (const col of sourceColumns[source.id] ?? []) {
|
|
51
|
+
if (!seen.has(col)) {
|
|
52
|
+
seen.add(col);
|
|
53
|
+
outputColumns.push(col);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Merge: coalesce picks first non-null value respecting priority
|
|
58
|
+
const mergedTable = 'stg_merged';
|
|
59
|
+
await store.query(buildMergedTableSql(mergedTable, joinedTable, context, config, outputColumns));
|
|
60
|
+
const rowsMerged = await store.rowCount(mergedTable);
|
|
61
|
+
const conflictLog = await buildConflictLog(store, joinedTable, context, config, outputColumns, 'stg_merge_conflicts');
|
|
62
|
+
logger.info({
|
|
63
|
+
strategy: 'coalesce',
|
|
64
|
+
sources: sources.length,
|
|
65
|
+
rowsMerged,
|
|
66
|
+
conflicts: conflictLog.count,
|
|
67
|
+
unmatched,
|
|
68
|
+
}, 'merge: complete');
|
|
69
|
+
return {
|
|
70
|
+
rowsMerged,
|
|
71
|
+
conflicts: conflictLog.count,
|
|
72
|
+
unmatched,
|
|
73
|
+
tableName: mergedTable,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=coalesce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coalesce.js","sourceRoot":"","sources":["../../../src/merge/strategies/coalesce.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/merge/strategies/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
export { coalesceStrategy } from './coalesce.js';
|
|
4
|
+
export { priorityOverrideStrategy } from './priority-override.js';
|
|
5
|
+
export { unionStrategy } from './union.js';
|
|
6
|
+
export { intersectStrategy } from './intersect.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/merge/strategies/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge strategy: INTERSECT
|
|
3
|
+
*
|
|
4
|
+
* Only includes rows that are present in ALL sources.
|
|
5
|
+
* Any row missing from even one source is excluded.
|
|
6
|
+
* For each field, uses coalesce semantics (first non-null value respecting priority).
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
* Source A: {ID: "A", ID: "B"}
|
|
10
|
+
* Source B: {ID: "B", ID: "C"}
|
|
11
|
+
* → Result: only {ID: "B"} (present in both)
|
|
12
|
+
*
|
|
13
|
+
* Unmatched rows are always excluded regardless of config.onUnmatched.
|
|
14
|
+
*/
|
|
15
|
+
import type { MergeStrategyPlugin } from '../types.js';
|
|
16
|
+
export declare const intersectStrategy: MergeStrategyPlugin;
|
|
17
|
+
//# sourceMappingURL=intersect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersect.d.ts","sourceRoot":"","sources":["../../../src/merge/strategies/intersect.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAiBvD,eAAO,MAAM,iBAAiB,EAAE,mBAkG/B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { quoteIdent } from '../../staging/index.js';
|
|
4
|
+
import { logger } from '../../utils/logger.js';
|
|
5
|
+
import { buildJoinedTableSql, buildMergedTableSql, buildPresentCountExpr, normalizeKeyColumns, } from '../sql-builder.js';
|
|
6
|
+
import { buildConflictLog } from '../conflict-log.js';
|
|
7
|
+
import { ConfigError } from '../../utils/errors.js';
|
|
8
|
+
export const intersectStrategy = {
|
|
9
|
+
id: 'intersect',
|
|
10
|
+
description: 'Only common rows. Includes only rows present in ALL sources; useful for intersection and reconciliation scenarios.',
|
|
11
|
+
async merge(store, rawSources, config) {
|
|
12
|
+
if (rawSources.length < 2) {
|
|
13
|
+
throw new ConfigError('merge requires at least 2 sources');
|
|
14
|
+
}
|
|
15
|
+
const sources = [...rawSources].sort((a, b) => a.priority - b.priority);
|
|
16
|
+
const keyColumns = normalizeKeyColumns(config.key);
|
|
17
|
+
const sourceColumns = {};
|
|
18
|
+
for (const source of sources) {
|
|
19
|
+
sourceColumns[source.id] = await store.columnNames(source.tableName);
|
|
20
|
+
for (const key of keyColumns) {
|
|
21
|
+
if (!sourceColumns[source.id].includes(key)) {
|
|
22
|
+
throw new ConfigError(`merge key column '${key}' is missing from source '${source.id}' table '${source.tableName}'`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const context = { sources, keyColumns, sourceColumns };
|
|
27
|
+
// Build the joined table (FULL OUTER JOIN on keys)
|
|
28
|
+
const joinedTable = 'stg_merge_joined';
|
|
29
|
+
await store.query(buildJoinedTableSql(joinedTable, context));
|
|
30
|
+
// Count unmatched rows (informational only; intersect always excludes them)
|
|
31
|
+
const presentCountExpr = buildPresentCountExpr(sources, keyColumns);
|
|
32
|
+
const unmatchedRows = await store.query(`SELECT count(*) AS n FROM ${quoteIdent(joinedTable)} WHERE (${presentCountExpr}) < ${sources.length}`);
|
|
33
|
+
const unmatched = Number(unmatchedRows[0]?.n ?? 0);
|
|
34
|
+
if (unmatched > 0) {
|
|
35
|
+
logger.info({ unmatched }, 'merge: intersect strategy excludes unmatched rows');
|
|
36
|
+
}
|
|
37
|
+
// Build output columns in order: keys first, then all non-key columns
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const outputColumns = [];
|
|
40
|
+
for (const key of keyColumns) {
|
|
41
|
+
if (!seen.has(key)) {
|
|
42
|
+
seen.add(key);
|
|
43
|
+
outputColumns.push(key);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const source of sources) {
|
|
47
|
+
for (const col of sourceColumns[source.id] ?? []) {
|
|
48
|
+
if (!seen.has(col)) {
|
|
49
|
+
seen.add(col);
|
|
50
|
+
outputColumns.push(col);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Merge: intersect only includes rows present in all sources, coalesce field values
|
|
55
|
+
const mergedTable = 'stg_merged';
|
|
56
|
+
const cfgOverride = { ...config, strategy: 'intersect' };
|
|
57
|
+
await store.query(buildMergedTableSql(mergedTable, joinedTable, context, cfgOverride, outputColumns));
|
|
58
|
+
const rowsMerged = await store.rowCount(mergedTable);
|
|
59
|
+
const conflictLog = await buildConflictLog(store, joinedTable, context, cfgOverride, outputColumns, 'stg_merge_conflicts');
|
|
60
|
+
logger.info({
|
|
61
|
+
strategy: 'intersect',
|
|
62
|
+
sources: sources.length,
|
|
63
|
+
rowsMerged,
|
|
64
|
+
conflicts: conflictLog.count,
|
|
65
|
+
unmatched,
|
|
66
|
+
}, 'merge: complete');
|
|
67
|
+
return {
|
|
68
|
+
rowsMerged,
|
|
69
|
+
conflicts: conflictLog.count,
|
|
70
|
+
unmatched,
|
|
71
|
+
tableName: mergedTable,
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=intersect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersect.js","sourceRoot":"","sources":["../../../src/merge/strategies/intersect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge strategy: PRIORITY-OVERRIDE
|
|
3
|
+
*
|
|
4
|
+
* For each field, uses the value from the highest-priority source that has
|
|
5
|
+
* ANY data for the key (even if null or whitespace), ignoring lower-priority sources.
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
* Source A (priority 1): STYLE_DESC = null
|
|
9
|
+
* Source B (priority 2): STYLE_DESC = "FromExcel"
|
|
10
|
+
* → Result: STYLE_DESC = null (because Source A is present for this key)
|
|
11
|
+
*
|
|
12
|
+
* Differs from COALESCE in that it respects source presence, not just value nullability.
|
|
13
|
+
*/
|
|
14
|
+
import type { MergeStrategyPlugin } from '../types.js';
|
|
15
|
+
export declare const priorityOverrideStrategy: MergeStrategyPlugin;
|
|
16
|
+
//# sourceMappingURL=priority-override.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priority-override.d.ts","sourceRoot":"","sources":["../../../src/merge/strategies/priority-override.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAiBvD,eAAO,MAAM,wBAAwB,EAAE,mBAuGtC,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import { quoteIdent } from '../../staging/index.js';
|
|
4
|
+
import { logger } from '../../utils/logger.js';
|
|
5
|
+
import { buildJoinedTableSql, buildMergedTableSql, buildPresentCountExpr, normalizeKeyColumns, } from '../sql-builder.js';
|
|
6
|
+
import { buildConflictLog } from '../conflict-log.js';
|
|
7
|
+
import { ConfigError, PipelineError } from '../../utils/errors.js';
|
|
8
|
+
export const priorityOverrideStrategy = {
|
|
9
|
+
id: 'priority-override',
|
|
10
|
+
description: 'Highest priority source wins (even nulls). Uses values from the highest-priority source present for a key, ignoring lower priorities.',
|
|
11
|
+
async merge(store, rawSources, config) {
|
|
12
|
+
if (rawSources.length < 2) {
|
|
13
|
+
throw new ConfigError('merge requires at least 2 sources');
|
|
14
|
+
}
|
|
15
|
+
const sources = [...rawSources].sort((a, b) => a.priority - b.priority);
|
|
16
|
+
const keyColumns = normalizeKeyColumns(config.key);
|
|
17
|
+
const sourceColumns = {};
|
|
18
|
+
for (const source of sources) {
|
|
19
|
+
sourceColumns[source.id] = await store.columnNames(source.tableName);
|
|
20
|
+
for (const key of keyColumns) {
|
|
21
|
+
if (!sourceColumns[source.id].includes(key)) {
|
|
22
|
+
throw new ConfigError(`merge key column '${key}' is missing from source '${source.id}' table '${source.tableName}'`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const context = { sources, keyColumns, sourceColumns };
|
|
27
|
+
// Build the joined table (FULL OUTER JOIN on keys)
|
|
28
|
+
const joinedTable = 'stg_merge_joined';
|
|
29
|
+
await store.query(buildJoinedTableSql(joinedTable, context));
|
|
30
|
+
// Check for unmatched rows and handle per config
|
|
31
|
+
const presentCountExpr = buildPresentCountExpr(sources, keyColumns);
|
|
32
|
+
const unmatchedRows = await store.query(`SELECT count(*) AS n FROM ${quoteIdent(joinedTable)} WHERE (${presentCountExpr}) = 1`);
|
|
33
|
+
const unmatched = Number(unmatchedRows[0]?.n ?? 0);
|
|
34
|
+
if (config.onUnmatched === 'error' && unmatched > 0) {
|
|
35
|
+
throw new PipelineError(`merge halted: ${unmatched} unmatched row(s) encountered with onUnmatched=error`);
|
|
36
|
+
}
|
|
37
|
+
if (config.onUnmatched === 'warn' && unmatched > 0) {
|
|
38
|
+
logger.warn({ unmatched }, 'merge: unmatched rows present');
|
|
39
|
+
}
|
|
40
|
+
// Build output columns in order: keys first, then all non-key columns
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
const outputColumns = [];
|
|
43
|
+
for (const key of keyColumns) {
|
|
44
|
+
if (!seen.has(key)) {
|
|
45
|
+
seen.add(key);
|
|
46
|
+
outputColumns.push(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const source of sources) {
|
|
50
|
+
for (const col of sourceColumns[source.id] ?? []) {
|
|
51
|
+
if (!seen.has(col)) {
|
|
52
|
+
seen.add(col);
|
|
53
|
+
outputColumns.push(col);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Merge: priority-override uses highest-priority source value (even if null)
|
|
58
|
+
const mergedTable = 'stg_merged';
|
|
59
|
+
const cfgOverride = { ...config, strategy: 'priority-override' };
|
|
60
|
+
await store.query(buildMergedTableSql(mergedTable, joinedTable, context, cfgOverride, outputColumns));
|
|
61
|
+
const rowsMerged = await store.rowCount(mergedTable);
|
|
62
|
+
const conflictLog = await buildConflictLog(store, joinedTable, context, cfgOverride, outputColumns, 'stg_merge_conflicts');
|
|
63
|
+
logger.info({
|
|
64
|
+
strategy: 'priority-override',
|
|
65
|
+
sources: sources.length,
|
|
66
|
+
rowsMerged,
|
|
67
|
+
conflicts: conflictLog.count,
|
|
68
|
+
unmatched,
|
|
69
|
+
}, 'merge: complete');
|
|
70
|
+
return {
|
|
71
|
+
rowsMerged,
|
|
72
|
+
conflicts: conflictLog.count,
|
|
73
|
+
unmatched,
|
|
74
|
+
tableName: mergedTable,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=priority-override.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priority-override.js","sourceRoot":"","sources":["../../../src/merge/strategies/priority-override.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge strategy registry.
|
|
3
|
+
* Loads all built-in merge strategies.
|
|
4
|
+
*/
|
|
5
|
+
import type { MergeStrategyPlugin } from '../types.js';
|
|
6
|
+
export declare function getStrategy(id: string): MergeStrategyPlugin | undefined;
|
|
7
|
+
export declare function listStrategies(): string[];
|
|
8
|
+
//# sourceMappingURL=registry.d.ts.map
|