@jackchuka/gql-ingest 3.1.8 → 4.0.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/README.md +72 -71
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/index.js +98 -100
- package/dist/cli/templates/index.d.ts +1 -1
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/index.js +65 -118
- package/dist/index.js.map +3 -3
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/events.d.ts +0 -2
- package/dist/lib/events.d.ts.map +1 -1
- package/dist/lib/gql-ingest.d.ts +7 -12
- package/dist/lib/gql-ingest.d.ts.map +1 -1
- package/dist/lib/mapper.d.ts +2 -3
- package/dist/lib/mapper.d.ts.map +1 -1
- package/package.json +5 -4
|
@@ -25,5 +25,5 @@ export declare function generateConfigYaml(basePath: string, force: boolean, log
|
|
|
25
25
|
export declare function generateEntityFiles(basePath: string, entityName: string, options: EntityTemplateOptions, logger: Logger, force?: boolean): Promise<void>;
|
|
26
26
|
export declare function toPascalCase(str: string): string;
|
|
27
27
|
export declare function validateEntityName(name: string): boolean;
|
|
28
|
-
export declare function ensureDirectories(basePath: string,
|
|
28
|
+
export declare function ensureDirectories(basePath: string, _logger: Logger): void;
|
|
29
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,UAAU,CAE/D;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAKtB,CAAC;AAEX,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,UAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAYf;AA+DD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,MAAM,EACd,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,UAAU,CAE/D;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAKtB,CAAC;AAEX,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,UAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAYf;AA+DD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,MAAM,EACd,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CAmCf;AA+DD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIzE"}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,6 @@ import { GraphQLClient } from "graphql-request";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/config.ts
|
|
14
14
|
import fs from "fs";
|
|
15
|
-
import path from "path";
|
|
16
15
|
import * as yaml from "js-yaml";
|
|
17
16
|
|
|
18
17
|
// src/lib/logger.ts
|
|
@@ -13876,23 +13875,24 @@ var DEFAULT_CONFIG = {
|
|
|
13876
13875
|
entityConfig: {},
|
|
13877
13876
|
entityDependencies: {}
|
|
13878
13877
|
};
|
|
13879
|
-
function loadConfig(
|
|
13880
|
-
|
|
13878
|
+
function loadConfig(configFile, logger = noopLogger) {
|
|
13879
|
+
if (!configFile) {
|
|
13880
|
+
logger.info("No config file provided, using defaults");
|
|
13881
|
+
return DEFAULT_CONFIG;
|
|
13882
|
+
}
|
|
13881
13883
|
try {
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
}
|
|
13886
|
-
const fileContents = fs.readFileSync(configPath, "utf8");
|
|
13887
|
-
const yamlConfig = yaml.load(fileContents);
|
|
13888
|
-
if (yamlConfig === null || typeof yamlConfig !== "object" || Array.isArray(yamlConfig)) {
|
|
13889
|
-
logger.warn("Warning: config.yaml is not a valid object. Using defaults.");
|
|
13890
|
-
return DEFAULT_CONFIG;
|
|
13891
|
-
}
|
|
13884
|
+
const content = fs.readFileSync(configFile, "utf-8");
|
|
13885
|
+
const yamlConfig = yaml.load(content);
|
|
13886
|
+
logger.info(`Loaded config from ${configFile}`);
|
|
13892
13887
|
return mergeWithDefaults(yamlConfig);
|
|
13893
13888
|
} catch (error48) {
|
|
13894
|
-
const
|
|
13895
|
-
|
|
13889
|
+
const isNotFound = error48 instanceof Error && "code" in error48 && // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
|
|
13890
|
+
error48.code === "ENOENT";
|
|
13891
|
+
if (isNotFound) {
|
|
13892
|
+
logger.info(`Config file not found at ${configFile}, using defaults`);
|
|
13893
|
+
} else {
|
|
13894
|
+
logger.warn(`Failed to parse ${configFile}, using defaults`);
|
|
13895
|
+
}
|
|
13896
13896
|
return DEFAULT_CONFIG;
|
|
13897
13897
|
}
|
|
13898
13898
|
}
|
|
@@ -14038,7 +14038,7 @@ var GraphQLClientWrapper = class {
|
|
|
14038
14038
|
|
|
14039
14039
|
// src/lib/mapper.ts
|
|
14040
14040
|
import fs6 from "fs";
|
|
14041
|
-
import
|
|
14041
|
+
import path from "path";
|
|
14042
14042
|
import { parse as parse3, Kind } from "graphql";
|
|
14043
14043
|
|
|
14044
14044
|
// src/readers/data-reader.ts
|
|
@@ -14322,38 +14322,6 @@ var DataMapper = class {
|
|
|
14322
14322
|
this.logger = logger;
|
|
14323
14323
|
this.formatOverride = formatOverride;
|
|
14324
14324
|
}
|
|
14325
|
-
discoverMappings(configDir, entityFilter) {
|
|
14326
|
-
const mappingsPath = path2.resolve(this.basePath, configDir, "mappings");
|
|
14327
|
-
try {
|
|
14328
|
-
const files = fs6.readdirSync(mappingsPath);
|
|
14329
|
-
let jsonFiles = files.filter((file2) => file2.endsWith(".json"));
|
|
14330
|
-
if (entityFilter && entityFilter.length > 0) {
|
|
14331
|
-
const requestedEntities = new Set(entityFilter);
|
|
14332
|
-
const foundEntities = /* @__PURE__ */ new Set();
|
|
14333
|
-
jsonFiles = jsonFiles.filter((file2) => {
|
|
14334
|
-
const entityName = path2.basename(file2, ".json");
|
|
14335
|
-
if (requestedEntities.has(entityName)) {
|
|
14336
|
-
foundEntities.add(entityName);
|
|
14337
|
-
return true;
|
|
14338
|
-
}
|
|
14339
|
-
return false;
|
|
14340
|
-
});
|
|
14341
|
-
const notFound = entityFilter.filter((e) => !foundEntities.has(e));
|
|
14342
|
-
if (notFound.length > 0) {
|
|
14343
|
-
this.logger.warn(
|
|
14344
|
-
`Warning: The following entities were not found in mappings: ${notFound.join(", ")}`
|
|
14345
|
-
);
|
|
14346
|
-
}
|
|
14347
|
-
}
|
|
14348
|
-
jsonFiles.sort();
|
|
14349
|
-
this.logger.info(`Discovered ${jsonFiles.length} mapping files: ${jsonFiles.join(", ")}`);
|
|
14350
|
-
return jsonFiles.map((file2) => path2.join(configDir, "mappings", file2));
|
|
14351
|
-
} catch (error48) {
|
|
14352
|
-
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
14353
|
-
this.logger.error(`Error reading mappings directory ${mappingsPath}: ${message}`);
|
|
14354
|
-
return [];
|
|
14355
|
-
}
|
|
14356
|
-
}
|
|
14357
14325
|
/**
|
|
14358
14326
|
* Process an entity (backward-compatible method)
|
|
14359
14327
|
*/
|
|
@@ -14364,22 +14332,18 @@ var DataMapper = class {
|
|
|
14364
14332
|
* Process an entity with event callbacks and abort support
|
|
14365
14333
|
*/
|
|
14366
14334
|
async processEntityWithEvents(configPath, parallelConfig, retryConfig, signal, callbacks) {
|
|
14367
|
-
const entityName = path2.basename(configPath, ".json");
|
|
14368
14335
|
const entityStartTime = Date.now();
|
|
14369
|
-
this.
|
|
14370
|
-
this.metrics.startEntityProcessing(entityName);
|
|
14371
|
-
const configFullPath = path2.resolve(this.basePath, configPath);
|
|
14336
|
+
const configFullPath = path.resolve(this.basePath, configPath);
|
|
14372
14337
|
const config2 = JSON.parse(fs6.readFileSync(configFullPath, "utf8"));
|
|
14373
|
-
const
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
const dataPath = path2.resolve(configDir, dataFile);
|
|
14338
|
+
const entityName = config2.name;
|
|
14339
|
+
this.logger.info(`Processing entity: ${entityName}`);
|
|
14340
|
+
this.metrics.startEntityProcessing(entityName);
|
|
14341
|
+
const entityDir = path.dirname(configFullPath);
|
|
14342
|
+
const dataPath = path.resolve(entityDir, config2.dataFile);
|
|
14379
14343
|
const format = this.formatOverride || config2.dataFormat;
|
|
14380
14344
|
const reader = DataReaderFactory.getReader(dataPath, format);
|
|
14381
14345
|
const data = await reader.readFile(dataPath);
|
|
14382
|
-
const graphqlPath =
|
|
14346
|
+
const graphqlPath = path.resolve(entityDir, config2.graphqlFile);
|
|
14383
14347
|
const mutation = fs6.readFileSync(graphqlPath, "utf8");
|
|
14384
14348
|
callbacks?.onEntityStart?.({
|
|
14385
14349
|
entityName,
|
|
@@ -14558,8 +14522,8 @@ var DataMapper = class {
|
|
|
14558
14522
|
if (mappingValue === "$") {
|
|
14559
14523
|
variables[graphqlVar] = row;
|
|
14560
14524
|
} else if (typeof mappingValue === "string" && mappingValue.startsWith("$.")) {
|
|
14561
|
-
const
|
|
14562
|
-
const value = this.getValueByPath(row,
|
|
14525
|
+
const dataPath = mappingValue.substring(2);
|
|
14526
|
+
const value = this.getValueByPath(row, dataPath);
|
|
14563
14527
|
if (value !== void 0) {
|
|
14564
14528
|
const type = variableTypes[graphqlVar];
|
|
14565
14529
|
variables[graphqlVar] = this.convertValue(value, type, graphqlVar);
|
|
@@ -14574,8 +14538,8 @@ var DataMapper = class {
|
|
|
14574
14538
|
}
|
|
14575
14539
|
return variables;
|
|
14576
14540
|
}
|
|
14577
|
-
getValueByPath(obj,
|
|
14578
|
-
const parts =
|
|
14541
|
+
getValueByPath(obj, dataPath) {
|
|
14542
|
+
const parts = dataPath.split(".");
|
|
14579
14543
|
let current = obj;
|
|
14580
14544
|
for (const part of parts) {
|
|
14581
14545
|
if (current && typeof current === "object" && part in current) {
|
|
@@ -14594,8 +14558,8 @@ var DataMapper = class {
|
|
|
14594
14558
|
const result = {};
|
|
14595
14559
|
for (const [key, value] of Object.entries(mappingObj)) {
|
|
14596
14560
|
if (typeof value === "string" && value.startsWith("$.")) {
|
|
14597
|
-
const
|
|
14598
|
-
let fieldValue = this.getValueByPath(row,
|
|
14561
|
+
const dataPath = value.substring(2);
|
|
14562
|
+
let fieldValue = this.getValueByPath(row, dataPath);
|
|
14599
14563
|
if (key === "values" && typeof fieldValue === "string" && fieldValue.includes(",")) {
|
|
14600
14564
|
fieldValue = fieldValue.split(",").map((v) => v.trim());
|
|
14601
14565
|
}
|
|
@@ -14764,7 +14728,8 @@ var DependencyResolver = class {
|
|
|
14764
14728
|
};
|
|
14765
14729
|
|
|
14766
14730
|
// src/lib/gql-ingest.ts
|
|
14767
|
-
import
|
|
14731
|
+
import fs7 from "fs";
|
|
14732
|
+
import path2 from "path";
|
|
14768
14733
|
|
|
14769
14734
|
// src/lib/events.ts
|
|
14770
14735
|
var DEFAULT_EVENT_OPTIONS = {
|
|
@@ -14900,12 +14865,12 @@ var GQLIngest = class extends EventEmitter {
|
|
|
14900
14865
|
return controller.signal;
|
|
14901
14866
|
}
|
|
14902
14867
|
/**
|
|
14903
|
-
* Ingest
|
|
14904
|
-
* @param
|
|
14868
|
+
* Ingest entity files
|
|
14869
|
+
* @param entityFiles Array of paths to entity JSON mapping files
|
|
14905
14870
|
* @param options Optional ingestion options
|
|
14906
14871
|
* @returns Promise with ingestion result
|
|
14907
14872
|
*/
|
|
14908
|
-
async ingest(
|
|
14873
|
+
async ingest(entityFiles, options) {
|
|
14909
14874
|
const errors = [];
|
|
14910
14875
|
this.abortController = new AbortController();
|
|
14911
14876
|
const signal = options?.signal ? this.combineSignals(options.signal, this.abortController.signal) : this.abortController.signal;
|
|
@@ -14932,19 +14897,9 @@ var GQLIngest = class extends EventEmitter {
|
|
|
14932
14897
|
this.logger,
|
|
14933
14898
|
options?.format ?? this.formatOverride
|
|
14934
14899
|
);
|
|
14935
|
-
const config2 = loadConfig(
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
if (typeof options.entities === "string") {
|
|
14939
|
-
entityFilter = options.entities.split(",").map((e) => e.trim());
|
|
14940
|
-
} else {
|
|
14941
|
-
entityFilter = options.entities;
|
|
14942
|
-
}
|
|
14943
|
-
}
|
|
14944
|
-
const mappingPaths = this.mapper.discoverMappings(configPath, entityFilter);
|
|
14945
|
-
if (mappingPaths.length === 0) {
|
|
14946
|
-
const filterMsg = entityFilter ? ` matching entities: ${entityFilter.join(", ")}` : "";
|
|
14947
|
-
const warning = `No mapping files found in ${configPath}/mappings${filterMsg}`;
|
|
14900
|
+
const config2 = loadConfig(options?.config, this.logger);
|
|
14901
|
+
if (entityFiles.length === 0) {
|
|
14902
|
+
const warning = "No entity files provided";
|
|
14948
14903
|
this.logger.warn(warning);
|
|
14949
14904
|
return {
|
|
14950
14905
|
metrics: this.metrics.getMetrics(),
|
|
@@ -14952,7 +14907,21 @@ var GQLIngest = class extends EventEmitter {
|
|
|
14952
14907
|
errors: [warning]
|
|
14953
14908
|
};
|
|
14954
14909
|
}
|
|
14955
|
-
const
|
|
14910
|
+
const entityFilter = options?.entities ? new Set(options.entities) : null;
|
|
14911
|
+
const entityNames = [];
|
|
14912
|
+
const pathMap = /* @__PURE__ */ new Map();
|
|
14913
|
+
for (const file2 of entityFiles) {
|
|
14914
|
+
const fullPath = path2.resolve(process.cwd(), file2);
|
|
14915
|
+
const entityConfig = JSON.parse(fs7.readFileSync(fullPath, "utf8"));
|
|
14916
|
+
if (!entityConfig.name) {
|
|
14917
|
+
throw new Error(`Missing "name" field in entity file: ${file2}`);
|
|
14918
|
+
}
|
|
14919
|
+
if (entityFilter && !entityFilter.has(entityConfig.name)) {
|
|
14920
|
+
continue;
|
|
14921
|
+
}
|
|
14922
|
+
entityNames.push(entityConfig.name);
|
|
14923
|
+
pathMap.set(entityConfig.name, file2);
|
|
14924
|
+
}
|
|
14956
14925
|
this.totalEntities = entityNames.length;
|
|
14957
14926
|
const relevantDependencies = {};
|
|
14958
14927
|
if (config2.entityDependencies) {
|
|
@@ -14962,35 +14931,23 @@ var GQLIngest = class extends EventEmitter {
|
|
|
14962
14931
|
}
|
|
14963
14932
|
}
|
|
14964
14933
|
}
|
|
14965
|
-
const resolver = new DependencyResolver(
|
|
14966
|
-
entityNames,
|
|
14967
|
-
relevantDependencies,
|
|
14968
|
-
!!entityFilter
|
|
14969
|
-
// Allow partial resolution when using --entities
|
|
14970
|
-
);
|
|
14934
|
+
const resolver = new DependencyResolver(entityNames, relevantDependencies, false);
|
|
14971
14935
|
const validationErrors = resolver.validateDependencies();
|
|
14972
14936
|
if (validationErrors.length > 0) {
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
14976
|
-
|
|
14977
|
-
}
|
|
14978
|
-
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
return {
|
|
14984
|
-
metrics: this.metrics.getMetrics(),
|
|
14985
|
-
success: false,
|
|
14986
|
-
errors
|
|
14987
|
-
};
|
|
14988
|
-
}
|
|
14937
|
+
this.logger.error("Dependency validation errors:");
|
|
14938
|
+
validationErrors.forEach((error48) => {
|
|
14939
|
+
this.logger.error(` - ${error48}`);
|
|
14940
|
+
errors.push(error48);
|
|
14941
|
+
});
|
|
14942
|
+
return {
|
|
14943
|
+
metrics: this.metrics.getMetrics(),
|
|
14944
|
+
success: false,
|
|
14945
|
+
errors
|
|
14946
|
+
};
|
|
14989
14947
|
}
|
|
14990
14948
|
const waves = resolver.resolveExecutionOrder();
|
|
14991
14949
|
this.totalWaves = waves.length;
|
|
14992
14950
|
const startedPayload = {
|
|
14993
|
-
configPath,
|
|
14994
14951
|
totalEntities: entityNames.length,
|
|
14995
14952
|
entityNames,
|
|
14996
14953
|
totalWaves: waves.length,
|
|
@@ -14999,7 +14956,7 @@ var GQLIngest = class extends EventEmitter {
|
|
|
14999
14956
|
this.safeEmit("started", startedPayload);
|
|
15000
14957
|
this.startProgressInterval();
|
|
15001
14958
|
await this.processEntitiesInWaves(
|
|
15002
|
-
|
|
14959
|
+
pathMap,
|
|
15003
14960
|
resolver,
|
|
15004
14961
|
this.mapper,
|
|
15005
14962
|
config2,
|
|
@@ -15049,15 +15006,6 @@ var GQLIngest = class extends EventEmitter {
|
|
|
15049
15006
|
this.stopProgressInterval();
|
|
15050
15007
|
}
|
|
15051
15008
|
}
|
|
15052
|
-
/**
|
|
15053
|
-
* Ingest specific entities from a configuration directory
|
|
15054
|
-
* @param configPath Path to configuration directory
|
|
15055
|
-
* @param entities Array of entity names to process
|
|
15056
|
-
* @returns Promise with ingestion result
|
|
15057
|
-
*/
|
|
15058
|
-
async ingestEntities(configPath, entities) {
|
|
15059
|
-
return this.ingest(configPath, { entities });
|
|
15060
|
-
}
|
|
15061
15009
|
/**
|
|
15062
15010
|
* Get current processing metrics
|
|
15063
15011
|
* @returns Current metrics
|
|
@@ -15119,9 +15067,8 @@ var GQLIngest = class extends EventEmitter {
|
|
|
15119
15067
|
/**
|
|
15120
15068
|
* Process entities in dependency-aware waves with abort support
|
|
15121
15069
|
*/
|
|
15122
|
-
async processEntitiesInWaves(
|
|
15070
|
+
async processEntitiesInWaves(pathMap, resolver, mapper, config2, logger, signal) {
|
|
15123
15071
|
const waves = resolver.resolveExecutionOrder();
|
|
15124
|
-
const pathMap = new Map(mappingPaths.map((path3) => [basename(path3, ".json"), path3]));
|
|
15125
15072
|
logger.info(`Processing ${waves.length} dependency waves...`);
|
|
15126
15073
|
for (const wave of waves) {
|
|
15127
15074
|
if (signal?.aborted) {
|