@nmakarov/cli-toolkit 0.11.3 → 0.14.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/dist/db.cjs +97 -2
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +93 -1
- package/dist/db.js.map +1 -1
- package/dist/filedatabase.cjs +195 -15
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +192 -14
- package/dist/filedatabase.js.map +1 -1
- package/dist/index.cjs +288 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +283 -13
- package/dist/index.js.map +1 -1
- package/dist/mock-server.cjs +168 -13
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +168 -13
- package/dist/mock-server.js.map +1 -1
- package/dist/utils.cjs +251 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +199 -0
- package/dist/utils.js.map +1 -0
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -1110,6 +1110,9 @@ __export(src_exports, {
|
|
|
1110
1110
|
buildBreadcrumb: () => buildBreadcrumb,
|
|
1111
1111
|
buildDetailBreadcrumb: () => buildDetailBreadcrumb,
|
|
1112
1112
|
buildFooter: () => buildFooter,
|
|
1113
|
+
dbConnect: () => dbConnect,
|
|
1114
|
+
dbFindAndConnect: () => dbFindAndConnect,
|
|
1115
|
+
dbInit: () => dbInit,
|
|
1113
1116
|
defaultFileSynopsisFunction: () => defaultFileSynopsisFunction,
|
|
1114
1117
|
defaultVersionSynopsisFunction: () => defaultVersionSynopsisFunction,
|
|
1115
1118
|
fileDatabaseInit: () => fileDatabaseInit,
|
|
@@ -1117,6 +1120,8 @@ __export(src_exports, {
|
|
|
1117
1120
|
h: () => import_react5.createElement,
|
|
1118
1121
|
joiEdateType: () => joiEdateType,
|
|
1119
1122
|
joiStringArrayType: () => joiStringArrayType,
|
|
1123
|
+
listSources: () => listSources,
|
|
1124
|
+
listTables: () => listTables,
|
|
1120
1125
|
load: () => load,
|
|
1121
1126
|
organizeFooterMessages: () => organizeFooterMessages,
|
|
1122
1127
|
setupContext: () => setupContext,
|
|
@@ -2584,20 +2589,48 @@ var FileDatabase = class {
|
|
|
2584
2589
|
}
|
|
2585
2590
|
/**
|
|
2586
2591
|
* Figure out what data to write and which file to use (for pagination)
|
|
2592
|
+
* @param data - Data to write
|
|
2593
|
+
* @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)
|
|
2594
|
+
* @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)
|
|
2587
2595
|
*/
|
|
2588
|
-
figureOutDataAndFileToWrite(data) {
|
|
2596
|
+
figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {
|
|
2589
2597
|
let dataToWrite;
|
|
2590
2598
|
let dataLeftOver;
|
|
2591
2599
|
const incomingDataType = detectDataType(data);
|
|
2592
2600
|
if (this.metadata.dataType !== incomingDataType) {
|
|
2593
2601
|
this.metadata.dataType = incomingDataType;
|
|
2594
2602
|
}
|
|
2595
|
-
if (this.metadata.files.length
|
|
2603
|
+
if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {
|
|
2604
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2605
|
+
if (!Array.isArray(data)) {
|
|
2606
|
+
dataToWrite = data;
|
|
2607
|
+
dataLeftOver = null;
|
|
2608
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2609
|
+
} else {
|
|
2610
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2611
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2612
|
+
this.lastFileData = dataToWrite;
|
|
2613
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
let newlyCreatedFileIndex = null;
|
|
2617
|
+
if (forceNewFile) {
|
|
2618
|
+
const filesBeforeCreate = this.metadata.files.length;
|
|
2619
|
+
this.makeNewFile();
|
|
2620
|
+
newlyCreatedFileIndex = filesBeforeCreate;
|
|
2621
|
+
this.logger.debug?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
|
|
2622
|
+
} else if (this.metadata.files.length === 0) {
|
|
2596
2623
|
this.makeNewFile();
|
|
2597
2624
|
}
|
|
2598
2625
|
const lastFile = this.metadata.files[this.metadata.files.length - 1];
|
|
2599
2626
|
const lastFileRecordsCount = lastFile.recordsCount;
|
|
2600
|
-
if (
|
|
2627
|
+
if (forceNewFile && newlyCreatedFileIndex !== null) {
|
|
2628
|
+
const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];
|
|
2629
|
+
if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {
|
|
2630
|
+
this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
if (!Array.isArray(data) && !forceNewFile) {
|
|
2601
2634
|
const lastFileExtension = import_path4.default.extname(lastFile.fileName);
|
|
2602
2635
|
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2603
2636
|
if (lastFileExtension !== expectedExtension) {
|
|
@@ -2607,24 +2640,35 @@ var FileDatabase = class {
|
|
|
2607
2640
|
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2608
2641
|
}
|
|
2609
2642
|
}
|
|
2643
|
+
} else if (!Array.isArray(data) && forceNewFile) {
|
|
2644
|
+
const lastFileExtension = import_path4.default.extname(lastFile.fileName);
|
|
2645
|
+
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2646
|
+
if (lastFileExtension !== expectedExtension) {
|
|
2647
|
+
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2648
|
+
}
|
|
2610
2649
|
}
|
|
2611
2650
|
if (Array.isArray(data)) {
|
|
2612
|
-
if (
|
|
2651
|
+
if (forceNewFile) {
|
|
2652
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2653
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2654
|
+
this.lastFileData = dataToWrite;
|
|
2655
|
+
} else if (lastFileRecordsCount < this.pageSize) {
|
|
2613
2656
|
dataToWrite = [...this.lastFileData || [], ...data.slice(0, this.pageSize - lastFileRecordsCount)];
|
|
2614
2657
|
dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);
|
|
2658
|
+
this.lastFileData = dataToWrite;
|
|
2615
2659
|
} else {
|
|
2616
2660
|
this.makeNewFile();
|
|
2617
2661
|
dataToWrite = data.slice(0, this.pageSize);
|
|
2618
2662
|
dataLeftOver = data.slice(this.pageSize);
|
|
2663
|
+
this.lastFileData = dataToWrite;
|
|
2619
2664
|
}
|
|
2620
|
-
this.lastFileData = dataToWrite;
|
|
2621
2665
|
} else {
|
|
2622
2666
|
dataToWrite = data;
|
|
2623
2667
|
dataLeftOver = null;
|
|
2624
2668
|
}
|
|
2625
2669
|
const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;
|
|
2626
2670
|
this.logger.debug?.(
|
|
2627
|
-
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2671
|
+
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2628
2672
|
);
|
|
2629
2673
|
return { dataToWrite, dataLeftOver, fileName };
|
|
2630
2674
|
}
|
|
@@ -2652,7 +2696,7 @@ var FileDatabase = class {
|
|
|
2652
2696
|
/**
|
|
2653
2697
|
* Update metadata after writing data
|
|
2654
2698
|
*/
|
|
2655
|
-
updateMetadata(dataToWrite, fileName) {
|
|
2699
|
+
updateMetadata(dataToWrite, fileName, customMetadata) {
|
|
2656
2700
|
let currentFile;
|
|
2657
2701
|
if (fileName) {
|
|
2658
2702
|
const foundFile = this.metadata.files.find((file) => file.fileName === fileName);
|
|
@@ -2667,6 +2711,9 @@ var FileDatabase = class {
|
|
|
2667
2711
|
}
|
|
2668
2712
|
const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;
|
|
2669
2713
|
currentFile.recordsCount = recordsCount;
|
|
2714
|
+
if (customMetadata) {
|
|
2715
|
+
Object.assign(currentFile, customMetadata);
|
|
2716
|
+
}
|
|
2670
2717
|
const fileIndex = this.metadata.files.indexOf(currentFile);
|
|
2671
2718
|
if (fileIndex !== -1) {
|
|
2672
2719
|
this.calculateFileSynopsis(dataToWrite, fileIndex);
|
|
@@ -2719,6 +2766,11 @@ var FileDatabase = class {
|
|
|
2719
2766
|
} else {
|
|
2720
2767
|
if (!this.metadata.files.length) {
|
|
2721
2768
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2769
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2770
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2771
|
+
} else {
|
|
2772
|
+
this.currentFileNumber = 0;
|
|
2773
|
+
}
|
|
2722
2774
|
}
|
|
2723
2775
|
}
|
|
2724
2776
|
} else {
|
|
@@ -2729,16 +2781,22 @@ var FileDatabase = class {
|
|
|
2729
2781
|
try {
|
|
2730
2782
|
const rawData = await import_fs4.default.promises.readFile(metadataPath, "utf8");
|
|
2731
2783
|
this.metadata = JSON.parse(rawData);
|
|
2784
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2785
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2786
|
+
} else {
|
|
2787
|
+
this.currentFileNumber = 0;
|
|
2788
|
+
}
|
|
2732
2789
|
} catch (e) {
|
|
2733
2790
|
this.metadata = this.getDefaultMetadata();
|
|
2791
|
+
this.currentFileNumber = 0;
|
|
2734
2792
|
}
|
|
2735
2793
|
} else {
|
|
2736
2794
|
this.metadata = this.getDefaultMetadata();
|
|
2737
|
-
this.
|
|
2795
|
+
this.currentFileNumber = 0;
|
|
2738
2796
|
}
|
|
2739
2797
|
} else {
|
|
2740
2798
|
this.metadata = this.getDefaultMetadata();
|
|
2741
|
-
this.
|
|
2799
|
+
this.currentFileNumber = 0;
|
|
2742
2800
|
}
|
|
2743
2801
|
}
|
|
2744
2802
|
} else if (read) {
|
|
@@ -2757,6 +2815,11 @@ var FileDatabase = class {
|
|
|
2757
2815
|
}
|
|
2758
2816
|
if (!this.metadata.files.length) {
|
|
2759
2817
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2818
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2819
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2820
|
+
} else {
|
|
2821
|
+
this.currentFileNumber = 0;
|
|
2822
|
+
}
|
|
2760
2823
|
}
|
|
2761
2824
|
} else {
|
|
2762
2825
|
this.currentVersion = null;
|
|
@@ -2770,6 +2833,11 @@ var FileDatabase = class {
|
|
|
2770
2833
|
try {
|
|
2771
2834
|
const rawData = await import_fs4.default.promises.readFile(metadataPath, "utf8");
|
|
2772
2835
|
this.metadata = JSON.parse(rawData);
|
|
2836
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2837
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2838
|
+
} else {
|
|
2839
|
+
this.currentFileNumber = 0;
|
|
2840
|
+
}
|
|
2773
2841
|
} catch (e) {
|
|
2774
2842
|
throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
|
|
2775
2843
|
}
|
|
@@ -2778,6 +2846,11 @@ var FileDatabase = class {
|
|
|
2778
2846
|
}
|
|
2779
2847
|
} else {
|
|
2780
2848
|
this.metadata = await this.figureMetadataFromVersionFiles("");
|
|
2849
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2850
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2851
|
+
} else {
|
|
2852
|
+
this.currentFileNumber = 0;
|
|
2853
|
+
}
|
|
2781
2854
|
}
|
|
2782
2855
|
}
|
|
2783
2856
|
}
|
|
@@ -2799,14 +2872,44 @@ var FileDatabase = class {
|
|
|
2799
2872
|
this.metadata.dataType = incomingDataType;
|
|
2800
2873
|
this.makeNewFile();
|
|
2801
2874
|
}
|
|
2802
|
-
let
|
|
2875
|
+
let targetFileIndex = null;
|
|
2876
|
+
const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;
|
|
2877
|
+
if (hasCustomMetadata) {
|
|
2878
|
+
for (let i = 0; i < this.metadata.files.length; i++) {
|
|
2879
|
+
const fileEntry = this.metadata.files[i];
|
|
2880
|
+
const matches = Object.keys(options.customMetadata).every((key) => {
|
|
2881
|
+
return key in fileEntry && fileEntry[key] === options.customMetadata[key];
|
|
2882
|
+
});
|
|
2883
|
+
if (matches) {
|
|
2884
|
+
targetFileIndex = i;
|
|
2885
|
+
this.logger.debug?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2886
|
+
break;
|
|
2887
|
+
} else {
|
|
2888
|
+
this.logger.debug?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
if (targetFileIndex === null) {
|
|
2892
|
+
this.logger.debug?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
|
|
2893
|
+
}
|
|
2894
|
+
} else {
|
|
2895
|
+
this.logger.debug?.(`[FileDatabase] No custom metadata provided, will create new file`);
|
|
2896
|
+
}
|
|
2897
|
+
if (targetFileIndex !== null) {
|
|
2898
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2899
|
+
this.currentFileNumber = targetFile.number;
|
|
2900
|
+
this.lastFileData = null;
|
|
2901
|
+
this.currentRecord = 0;
|
|
2902
|
+
this.hasReadFirstPage = false;
|
|
2903
|
+
}
|
|
2904
|
+
const forceNewFile = hasCustomMetadata && targetFileIndex === null;
|
|
2905
|
+
let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);
|
|
2803
2906
|
const destPath = this.getDestinationPath(this.currentVersion || void 0);
|
|
2804
2907
|
await this.safeWrite(import_path4.default.join(destPath, fileName), dataToWrite);
|
|
2805
|
-
this.updateMetadata(dataToWrite, fileName);
|
|
2806
|
-
while (dataLeftOver && dataLeftOver.length > 0) {
|
|
2908
|
+
this.updateMetadata(dataToWrite, fileName, options.customMetadata);
|
|
2909
|
+
while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {
|
|
2807
2910
|
const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);
|
|
2808
2911
|
await this.safeWrite(import_path4.default.join(destPath, writeContext.fileName), writeContext.dataToWrite);
|
|
2809
|
-
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);
|
|
2912
|
+
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);
|
|
2810
2913
|
dataLeftOver = writeContext.dataLeftOver;
|
|
2811
2914
|
}
|
|
2812
2915
|
this.calculateVersionSynopsis();
|
|
@@ -2923,7 +3026,85 @@ var FileDatabase = class {
|
|
|
2923
3026
|
getMetadata() {
|
|
2924
3027
|
return { ...this.metadata };
|
|
2925
3028
|
}
|
|
3029
|
+
/**
|
|
3030
|
+
* Find data by custom metadata fields
|
|
3031
|
+
* Searches through all versions and files to find entries matching the search criteria
|
|
3032
|
+
*
|
|
3033
|
+
* @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: "123", id: "456" })
|
|
3034
|
+
* @returns Array of found entries with their file paths and metadata
|
|
3035
|
+
*/
|
|
3036
|
+
async findData(searchCriteria) {
|
|
3037
|
+
const results = [];
|
|
3038
|
+
if (!this.versioned) {
|
|
3039
|
+
await this.prepare({ read: true });
|
|
3040
|
+
const metadata = this.getMetadata();
|
|
3041
|
+
for (const fileEntry of metadata.files) {
|
|
3042
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
3043
|
+
return fileEntry[key] === searchCriteria[key];
|
|
3044
|
+
});
|
|
3045
|
+
if (matches) {
|
|
3046
|
+
const destPath = this.getDestinationPath();
|
|
3047
|
+
const filePath = import_path4.default.join(destPath, fileEntry.fileName);
|
|
3048
|
+
const fileData = await import_fs4.default.promises.readFile(filePath, "utf8");
|
|
3049
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
3050
|
+
results.push({
|
|
3051
|
+
filePath,
|
|
3052
|
+
fileName: fileEntry.fileName,
|
|
3053
|
+
version: null,
|
|
3054
|
+
metadata: fileEntry,
|
|
3055
|
+
data
|
|
3056
|
+
});
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
} else {
|
|
3060
|
+
const versions = await this.getVersions();
|
|
3061
|
+
for (const version of versions) {
|
|
3062
|
+
await this.prepare({ read: true, version });
|
|
3063
|
+
const metadata = this.getMetadata();
|
|
3064
|
+
for (const fileEntry of metadata.files) {
|
|
3065
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
3066
|
+
return fileEntry[key] === searchCriteria[key];
|
|
3067
|
+
});
|
|
3068
|
+
if (matches) {
|
|
3069
|
+
const destPath = this.getDestinationPath(version);
|
|
3070
|
+
const filePath = import_path4.default.join(destPath, fileEntry.fileName);
|
|
3071
|
+
const fileData = await import_fs4.default.promises.readFile(filePath, "utf8");
|
|
3072
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
3073
|
+
results.push({
|
|
3074
|
+
filePath,
|
|
3075
|
+
fileName: fileEntry.fileName,
|
|
3076
|
+
version,
|
|
3077
|
+
metadata: fileEntry,
|
|
3078
|
+
data
|
|
3079
|
+
});
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
return results;
|
|
3085
|
+
}
|
|
2926
3086
|
};
|
|
3087
|
+
function listTables(basePath, namespace) {
|
|
3088
|
+
const namespacePath = import_path4.default.join(basePath, namespace);
|
|
3089
|
+
if (!import_fs4.default.existsSync(namespacePath)) {
|
|
3090
|
+
return [];
|
|
3091
|
+
}
|
|
3092
|
+
try {
|
|
3093
|
+
return import_fs4.default.readdirSync(namespacePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3094
|
+
} catch (error) {
|
|
3095
|
+
return [];
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
function listSources(basePath) {
|
|
3099
|
+
if (!import_fs4.default.existsSync(basePath)) {
|
|
3100
|
+
return [];
|
|
3101
|
+
}
|
|
3102
|
+
try {
|
|
3103
|
+
return import_fs4.default.readdirSync(basePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3104
|
+
} catch (error) {
|
|
3105
|
+
return [];
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
2927
3108
|
function fileDatabaseInit(context, options = {}) {
|
|
2928
3109
|
return new FileDatabase(context, options);
|
|
2929
3110
|
}
|
|
@@ -2936,6 +3117,10 @@ var Db = class {
|
|
|
2936
3117
|
logger;
|
|
2937
3118
|
queriesLog = [];
|
|
2938
3119
|
isConnected = false;
|
|
3120
|
+
/**
|
|
3121
|
+
* Constructor - accepts config object
|
|
3122
|
+
* Use dbInit() function to initialize with Context
|
|
3123
|
+
*/
|
|
2939
3124
|
constructor(config2) {
|
|
2940
3125
|
if (!config2.connectionString) {
|
|
2941
3126
|
throw new ParamError("Db: connectionString is required");
|
|
@@ -3222,6 +3407,91 @@ var Db = class {
|
|
|
3222
3407
|
return this.isConnected && this.knexInstance !== null;
|
|
3223
3408
|
}
|
|
3224
3409
|
};
|
|
3410
|
+
function capitalizeFirstLetter(str) {
|
|
3411
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
3412
|
+
}
|
|
3413
|
+
async function dbConnect(context, connectionString, name, dbProfile) {
|
|
3414
|
+
const defs = {
|
|
3415
|
+
testDbConnection: "boolean default true",
|
|
3416
|
+
name: "string",
|
|
3417
|
+
poolMin: "number default 2",
|
|
3418
|
+
poolMax: "number default 10",
|
|
3419
|
+
acquireConnectionTimeout: "number default 10000",
|
|
3420
|
+
sslRejectUnauthorized: "boolean default false"
|
|
3421
|
+
};
|
|
3422
|
+
const paramsConfig = context.params.getAll(defs);
|
|
3423
|
+
const config2 = {
|
|
3424
|
+
connectionString,
|
|
3425
|
+
name: paramsConfig.name || name || "default",
|
|
3426
|
+
testConnection: paramsConfig.testDbConnection,
|
|
3427
|
+
profile: dbProfile ?? false,
|
|
3428
|
+
pool: {
|
|
3429
|
+
min: paramsConfig.poolMin,
|
|
3430
|
+
max: paramsConfig.poolMax
|
|
3431
|
+
},
|
|
3432
|
+
acquireConnectionTimeout: paramsConfig.acquireConnectionTimeout,
|
|
3433
|
+
ssl: {
|
|
3434
|
+
rejectUnauthorized: paramsConfig.sslRejectUnauthorized
|
|
3435
|
+
},
|
|
3436
|
+
logger: context.logger
|
|
3437
|
+
};
|
|
3438
|
+
try {
|
|
3439
|
+
const db = new Db(config2);
|
|
3440
|
+
context.registerCleanup(async () => {
|
|
3441
|
+
await db.disconnect();
|
|
3442
|
+
context.logger.debug(`[Db] instance "${name || connectionString}" destroyed`);
|
|
3443
|
+
});
|
|
3444
|
+
await db.connect();
|
|
3445
|
+
context.logger.debug(`[Db] instance "${name || connectionString}" initialized`);
|
|
3446
|
+
return db;
|
|
3447
|
+
} catch (error) {
|
|
3448
|
+
if (error instanceof ParamError) {
|
|
3449
|
+
throw error;
|
|
3450
|
+
}
|
|
3451
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3452
|
+
throw new ParamError(`[Db] connect error: ${errorMsg}`);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
async function dbFindAndConnect(context, dbNameOrConnectionString) {
|
|
3456
|
+
let dbName;
|
|
3457
|
+
let dbConnectionString;
|
|
3458
|
+
let dbProfile;
|
|
3459
|
+
if (dbNameOrConnectionString) {
|
|
3460
|
+
if (dbNameOrConnectionString.match(/^(postgresql|mysql):\/\/[^\s]+:[^\s]+@[^\s]+:\d+\/[^\s]+$/)) {
|
|
3461
|
+
dbName = void 0;
|
|
3462
|
+
dbConnectionString = dbNameOrConnectionString;
|
|
3463
|
+
} else {
|
|
3464
|
+
dbName = dbNameOrConnectionString;
|
|
3465
|
+
}
|
|
3466
|
+
} else {
|
|
3467
|
+
const defs = {
|
|
3468
|
+
dbName: "string",
|
|
3469
|
+
dbConnectionString: "string",
|
|
3470
|
+
dbProfile: "boolean default false"
|
|
3471
|
+
};
|
|
3472
|
+
const paramsConfig = context.params.getAll(defs);
|
|
3473
|
+
dbName = paramsConfig.dbName;
|
|
3474
|
+
dbConnectionString = paramsConfig.dbConnectionString;
|
|
3475
|
+
dbProfile = paramsConfig.dbProfile;
|
|
3476
|
+
}
|
|
3477
|
+
if (!dbName && !dbConnectionString) {
|
|
3478
|
+
throw new ParamError("Db: either dbName or dbConnectionString must be specified");
|
|
3479
|
+
}
|
|
3480
|
+
if (dbName) {
|
|
3481
|
+
const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;
|
|
3482
|
+
dbConnectionString = await context.params.get(paramName, "string");
|
|
3483
|
+
if (!dbConnectionString) {
|
|
3484
|
+
throw new ParamError(
|
|
3485
|
+
`Db: cannot find dbConnectionString for dbName="${dbName}" (looked for param "${paramName}")`
|
|
3486
|
+
);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
const db = await dbConnect(context, dbConnectionString, dbName, dbProfile);
|
|
3490
|
+
return db;
|
|
3491
|
+
}
|
|
3492
|
+
async function dbInit(context, dbNameOrConnectionString) {
|
|
3493
|
+
return await dbFindAndConnect(context, dbNameOrConnectionString);
|
|
3494
|
+
}
|
|
3225
3495
|
|
|
3226
3496
|
// src/logger/index.ts
|
|
3227
3497
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
@@ -3617,6 +3887,9 @@ function setupContext(opts = {}) {
|
|
|
3617
3887
|
buildBreadcrumb,
|
|
3618
3888
|
buildDetailBreadcrumb,
|
|
3619
3889
|
buildFooter,
|
|
3890
|
+
dbConnect,
|
|
3891
|
+
dbFindAndConnect,
|
|
3892
|
+
dbInit,
|
|
3620
3893
|
defaultFileSynopsisFunction,
|
|
3621
3894
|
defaultVersionSynopsisFunction,
|
|
3622
3895
|
fileDatabaseInit,
|
|
@@ -3624,6 +3897,8 @@ function setupContext(opts = {}) {
|
|
|
3624
3897
|
h,
|
|
3625
3898
|
joiEdateType,
|
|
3626
3899
|
joiStringArrayType,
|
|
3900
|
+
listSources,
|
|
3901
|
+
listTables,
|
|
3627
3902
|
load,
|
|
3628
3903
|
organizeFooterMessages,
|
|
3629
3904
|
setupContext,
|