inibase 1.2.7 → 1.2.9
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/file.d.ts +3 -30
- package/dist/file.js +48 -109
- package/dist/index.d.ts +0 -1
- package/dist/index.js +91 -106
- package/dist/utils.js +12 -12
- package/dist/utils.server.js +3 -3
- package/package.json +13 -11
package/dist/file.d.ts
CHANGED
|
@@ -111,34 +111,7 @@ export declare const remove: (filePath: string, linesToDelete: number | number[]
|
|
|
111
111
|
export declare const search: (filePath: string, operator: ComparisonOperator | ComparisonOperator[], comparedAtValue: string | number | boolean | null | (string | number | boolean | null)[], logicalOperator?: "and" | "or", searchIn?: Set<number>, field?: Field & {
|
|
112
112
|
databasePath?: string;
|
|
113
113
|
}, limit?: number, offset?: number, readWholeFile?: boolean) => Promise<[Record<number, string | number | boolean | null | (string | number | boolean | null)[]> | null, number, Set<number> | null]>;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* @param filePath - Path of the file to read.
|
|
118
|
-
* @param lineNumbers - Optional specific line number(s) to include in the sum. If not provided, sums all lines.
|
|
119
|
-
* @returns Promise<number>. The sum of numerical values from the specified lines.
|
|
120
|
-
*
|
|
121
|
-
* Note: Decodes each line as a number using the 'decode' function. Non-numeric lines contribute 0 to the sum.
|
|
122
|
-
*/
|
|
123
|
-
export declare const sum: (filePath: string, lineNumbers?: number | number[]) => Promise<number>;
|
|
124
|
-
/**
|
|
125
|
-
* Asynchronously finds the maximum numerical value from specified lines in a file.
|
|
126
|
-
*
|
|
127
|
-
* @param filePath - Path of the file to read.
|
|
128
|
-
* @param lineNumbers - Optional specific line number(s) to consider for finding the maximum value. If not provided, considers all lines.
|
|
129
|
-
* @returns Promise<number>. The maximum numerical value found in the specified lines.
|
|
130
|
-
*
|
|
131
|
-
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the maximum.
|
|
132
|
-
*/
|
|
133
|
-
export declare const max: (filePath: string, lineNumbers?: number | number[]) => Promise<number>;
|
|
134
|
-
/**
|
|
135
|
-
* Asynchronously finds the minimum numerical value from specified lines in a file.
|
|
136
|
-
*
|
|
137
|
-
* @param filePath - Path of the file to read.
|
|
138
|
-
* @param lineNumbers - Optional specific line number(s) to consider for finding the minimum value. If not provided, considers all lines.
|
|
139
|
-
* @returns Promise<number>. The minimum numerical value found in the specified lines.
|
|
140
|
-
*
|
|
141
|
-
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the minimum.
|
|
142
|
-
*/
|
|
143
|
-
export declare const min: (filePath: string, lineNumbers?: number | number[]) => Promise<number>;
|
|
114
|
+
export declare const sum: (fp: string, ln?: number | number[]) => Promise<number>;
|
|
115
|
+
export declare const min: (fp: string, ln?: number | number[]) => Promise<number>;
|
|
116
|
+
export declare const max: (fp: string, ln?: number | number[]) => Promise<number>;
|
|
144
117
|
export declare const getFileDate: (path: string) => Promise<Date>;
|
package/dist/file.js
CHANGED
|
@@ -581,127 +581,66 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
581
581
|
}
|
|
582
582
|
};
|
|
583
583
|
/**
|
|
584
|
-
*
|
|
584
|
+
* Reads the file once and returns either the sum, min or max of the
|
|
585
|
+
* (optionally-selected) numeric lines.
|
|
585
586
|
*
|
|
586
|
-
* @param filePath
|
|
587
|
-
* @param
|
|
588
|
-
* @
|
|
587
|
+
* @param filePath Absolute path of the column file (may be .gz-compressed).
|
|
588
|
+
* @param wanted Metric to compute: "sum" (default), "min" or "max".
|
|
589
|
+
* @param lineNumbers Specific line-number(s) to restrict the scan to.
|
|
589
590
|
*
|
|
590
|
-
*
|
|
591
|
+
* @returns Promise<number> The requested metric, or 0 if no numeric value found.
|
|
591
592
|
*/
|
|
592
|
-
|
|
593
|
+
async function reduceNumbers(filePath, wanted = "sum", lineNumbers) {
|
|
594
|
+
/* optional subset */
|
|
595
|
+
const filter = lineNumbers
|
|
596
|
+
? new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers])
|
|
597
|
+
: null;
|
|
598
|
+
/* running aggregators */
|
|
593
599
|
let sum = 0;
|
|
594
|
-
let
|
|
600
|
+
let min = Infinity;
|
|
601
|
+
let max = -Infinity;
|
|
602
|
+
let processed = 0; // count of numeric lines we actually used
|
|
603
|
+
let seen = 0; // count of filtered lines we have visited
|
|
604
|
+
let line = 0;
|
|
605
|
+
const fh = await open(filePath, "r");
|
|
606
|
+
const rl = createReadLineInternface(filePath, fh);
|
|
595
607
|
try {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
if (!lineNumbersArray.size)
|
|
608
|
-
break;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
else
|
|
612
|
-
for await (const line of rl)
|
|
613
|
-
sum += +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
|
|
614
|
-
return sum;
|
|
615
|
-
}
|
|
616
|
-
finally {
|
|
617
|
-
await fileHandle?.close();
|
|
618
|
-
}
|
|
619
|
-
};
|
|
620
|
-
/**
|
|
621
|
-
* Asynchronously finds the maximum numerical value from specified lines in a file.
|
|
622
|
-
*
|
|
623
|
-
* @param filePath - Path of the file to read.
|
|
624
|
-
* @param lineNumbers - Optional specific line number(s) to consider for finding the maximum value. If not provided, considers all lines.
|
|
625
|
-
* @returns Promise<number>. The maximum numerical value found in the specified lines.
|
|
626
|
-
*
|
|
627
|
-
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the maximum.
|
|
628
|
-
*/
|
|
629
|
-
export const max = async (filePath, lineNumbers) => {
|
|
630
|
-
let max = 0;
|
|
631
|
-
let fileHandle = null;
|
|
632
|
-
let rl = null;
|
|
633
|
-
try {
|
|
634
|
-
fileHandle = await open(filePath, "r");
|
|
635
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
636
|
-
if (lineNumbers) {
|
|
637
|
-
let linesCount = 0;
|
|
638
|
-
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
639
|
-
for await (const line of rl) {
|
|
640
|
-
linesCount++;
|
|
641
|
-
if (!lineNumbersArray.has(linesCount))
|
|
642
|
-
continue;
|
|
643
|
-
const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
|
|
644
|
-
if (lineContentNum > max)
|
|
645
|
-
max = lineContentNum;
|
|
646
|
-
lineNumbersArray.delete(linesCount);
|
|
647
|
-
if (!lineNumbersArray.size)
|
|
648
|
-
break;
|
|
608
|
+
for await (const txt of rl) {
|
|
609
|
+
line++;
|
|
610
|
+
/* skip unwanted lines */
|
|
611
|
+
if (filter && !filter.has(line))
|
|
612
|
+
continue;
|
|
613
|
+
const num = Number(decode(txt, { key: "BLABLA", type: "number" })); // ← your existing decode()
|
|
614
|
+
if (isNaN(num))
|
|
615
|
+
continue;
|
|
616
|
+
processed++;
|
|
617
|
+
if (wanted === "sum") {
|
|
618
|
+
sum += num;
|
|
649
619
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
|
|
654
|
-
if (lineContentNum > max)
|
|
655
|
-
max = lineContentNum;
|
|
620
|
+
else if (wanted === "min") {
|
|
621
|
+
if (num < min)
|
|
622
|
+
min = num;
|
|
656
623
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
await fileHandle?.close();
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
/**
|
|
664
|
-
* Asynchronously finds the minimum numerical value from specified lines in a file.
|
|
665
|
-
*
|
|
666
|
-
* @param filePath - Path of the file to read.
|
|
667
|
-
* @param lineNumbers - Optional specific line number(s) to consider for finding the minimum value. If not provided, considers all lines.
|
|
668
|
-
* @returns Promise<number>. The minimum numerical value found in the specified lines.
|
|
669
|
-
*
|
|
670
|
-
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the minimum.
|
|
671
|
-
*/
|
|
672
|
-
export const min = async (filePath, lineNumbers) => {
|
|
673
|
-
let min = 0;
|
|
674
|
-
let fileHandle = null;
|
|
675
|
-
try {
|
|
676
|
-
fileHandle = await open(filePath, "r");
|
|
677
|
-
const rl = createReadLineInternface(filePath, fileHandle);
|
|
678
|
-
if (lineNumbers) {
|
|
679
|
-
let linesCount = 0;
|
|
680
|
-
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
681
|
-
for await (const line of rl) {
|
|
682
|
-
linesCount++;
|
|
683
|
-
if (!lineNumbersArray.has(linesCount))
|
|
684
|
-
continue;
|
|
685
|
-
const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
|
|
686
|
-
if (lineContentNum < min)
|
|
687
|
-
min = lineContentNum;
|
|
688
|
-
lineNumbersArray.delete(linesCount);
|
|
689
|
-
if (!lineNumbersArray.size)
|
|
690
|
-
break;
|
|
624
|
+
else if (wanted === "max") {
|
|
625
|
+
if (num > max)
|
|
626
|
+
max = num;
|
|
691
627
|
}
|
|
628
|
+
/* early break when we have consumed all requested lines */
|
|
629
|
+
if (filter && ++seen === filter.size)
|
|
630
|
+
break;
|
|
692
631
|
}
|
|
693
|
-
else
|
|
694
|
-
for await (const line of rl) {
|
|
695
|
-
const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
|
|
696
|
-
if (lineContentNum < min)
|
|
697
|
-
min = lineContentNum;
|
|
698
|
-
}
|
|
699
|
-
return min;
|
|
700
632
|
}
|
|
701
633
|
finally {
|
|
702
|
-
await
|
|
634
|
+
await fh.close();
|
|
703
635
|
}
|
|
704
|
-
|
|
636
|
+
if (processed === 0)
|
|
637
|
+
return 0; // nothing numeric found
|
|
638
|
+
return wanted === "sum" ? sum : wanted === "min" ? min : max;
|
|
639
|
+
}
|
|
640
|
+
/* Optional convenience wrappers (signatures unchanged) */
|
|
641
|
+
export const sum = (fp, ln) => reduceNumbers(fp, "sum", ln);
|
|
642
|
+
export const min = (fp, ln) => reduceNumbers(fp, "min", ln);
|
|
643
|
+
export const max = (fp, ln) => reduceNumbers(fp, "max", ln);
|
|
705
644
|
export const getFileDate = (path) => stat(path)
|
|
706
645
|
.then((s) => s.mtime || s.birthtime)
|
|
707
646
|
.catch(() => new Date());
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -440,11 +440,12 @@ export default class Inibase {
|
|
|
440
440
|
formatField(value, field, _formatOnlyAvailiableKeys) {
|
|
441
441
|
if (value === null || value === undefined || value === "")
|
|
442
442
|
return value;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
let _fieldType = field.type;
|
|
444
|
+
if (Array.isArray(_fieldType))
|
|
445
|
+
_fieldType = Utils.detectFieldType(value, _fieldType) ?? _fieldType[0];
|
|
446
|
+
if (Array.isArray(value) && !["array", "json"].includes(_fieldType))
|
|
446
447
|
value = value[0];
|
|
447
|
-
switch (
|
|
448
|
+
switch (_fieldType) {
|
|
448
449
|
case "array":
|
|
449
450
|
if (!field.children)
|
|
450
451
|
return null;
|
|
@@ -759,8 +760,9 @@ export default class Inibase {
|
|
|
759
760
|
await this.processTableField(tableName, field, linesNumber, RETURN, options, prefix);
|
|
760
761
|
}
|
|
761
762
|
else {
|
|
763
|
+
let _fieldChildren = field.children;
|
|
762
764
|
// Handling array of objects and filtering nested arrays
|
|
763
|
-
const nestedArrayFields =
|
|
765
|
+
const nestedArrayFields = _fieldChildren.filter((children) => children.type === "array" &&
|
|
764
766
|
Utils.isArrayOfObjects(children.children));
|
|
765
767
|
if (nestedArrayFields.length > 0) {
|
|
766
768
|
// one of children has array field type and has children array of object = Schema
|
|
@@ -769,10 +771,10 @@ export default class Inibase {
|
|
|
769
771
|
for (const [index, item] of Object.entries(childItems))
|
|
770
772
|
this._processSchemaDataHelper(RETURN, item, index, field);
|
|
771
773
|
// Remove nested arrays after processing
|
|
772
|
-
|
|
774
|
+
_fieldChildren = _fieldChildren.filter((children) => !nestedArrayFields.map(({ key }) => key).includes(children.key));
|
|
773
775
|
}
|
|
774
776
|
// Process remaining items for the field's children
|
|
775
|
-
const items = await this.processSchemaData(tableName,
|
|
777
|
+
const items = await this.processSchemaData(tableName, _fieldChildren, linesNumber, options, `${(prefix ?? "") + field.key}.`);
|
|
776
778
|
// Process the items after retrieval
|
|
777
779
|
if (items) {
|
|
778
780
|
for (const [index, item] of Object.entries(items)) {
|
|
@@ -925,141 +927,124 @@ export default class Inibase {
|
|
|
925
927
|
}
|
|
926
928
|
}
|
|
927
929
|
}
|
|
928
|
-
_setNestedKey(obj, path, value) {
|
|
929
|
-
const keys = path.split(".");
|
|
930
|
-
let current = obj;
|
|
931
|
-
keys.forEach((key, index) => {
|
|
932
|
-
if (index === keys.length - 1) {
|
|
933
|
-
current[key] = value; // Set the value at the last key
|
|
934
|
-
}
|
|
935
|
-
else {
|
|
936
|
-
current[key] = current[key] || {}; // Ensure the object structure exists
|
|
937
|
-
current = current[key];
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
930
|
async applyCriteria(tableName, options, criteria, allTrue, searchIn) {
|
|
942
931
|
const tablePath = join(this.databasePath, tableName);
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
932
|
+
/** result container – we mutate rows in-place instead of deep-merging */
|
|
933
|
+
const RETURN = {};
|
|
934
|
+
/* ---------- fast exit ---------- */
|
|
935
|
+
if (!criteria || Object.keys(criteria).length === 0)
|
|
936
|
+
return null;
|
|
937
|
+
/* ---------- split top-level logical groups ---------- */
|
|
946
938
|
const criteriaAND = criteria.and;
|
|
939
|
+
const criteriaOR = criteria.or;
|
|
947
940
|
if (criteriaAND)
|
|
948
941
|
delete criteria.and;
|
|
949
|
-
const criteriaOR = criteria.or;
|
|
950
942
|
if (criteriaOR)
|
|
951
943
|
delete criteria.or;
|
|
952
|
-
|
|
944
|
+
/** cache table schema once – Utils.getField() is cheap but we call it a lot */
|
|
945
|
+
const schema = globalConfig[this.databasePath].tables.get(tableName).schema;
|
|
946
|
+
/* ---------- MAIN LOOP (top-level criteria only) ---------- */
|
|
947
|
+
if (Object.keys(criteria).length) {
|
|
953
948
|
if (allTrue === undefined)
|
|
954
949
|
allTrue = true;
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
950
|
+
for (const [key, rawValue] of Object.entries(criteria)) {
|
|
951
|
+
/* bail early if no candidates left for an “AND” chain */
|
|
952
|
+
if (allTrue && searchIn && searchIn.size === 0)
|
|
953
|
+
return null;
|
|
954
|
+
const field = Utils.getField(key, schema);
|
|
959
955
|
if (!field)
|
|
960
956
|
continue;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
957
|
+
let value = rawValue;
|
|
958
|
+
/* ----- resolve relational sub-queries ----- */
|
|
959
|
+
if (field.table && Utils.isObject(value)) {
|
|
960
|
+
const rel = await this.get(field.table, value, {
|
|
961
|
+
columns: "id",
|
|
962
|
+
});
|
|
963
|
+
value = rel?.length ? `[]${rel.map(({ id }) => id)}` : undefined; // ⟵ no match → abort whole AND-chain
|
|
964
|
+
if (value === undefined && allTrue)
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
/* ----- determine operator / compare value ----- */
|
|
968
|
+
let searchOperator;
|
|
969
|
+
let searchComparedAtValue;
|
|
970
|
+
let searchLogicalOperator;
|
|
965
971
|
if (Utils.isObject(value)) {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
Array.isArray(value?.and)) {
|
|
982
|
-
const searchCriteria = (value?.and)
|
|
983
|
-
.map((single_and) => typeof single_and === "string"
|
|
984
|
-
? Utils.FormatObjectCriteriaValue(single_and)
|
|
985
|
-
: ["=", single_and])
|
|
986
|
-
.filter((a) => a);
|
|
987
|
-
if (searchCriteria.length > 0) {
|
|
988
|
-
searchOperator = searchCriteria.map((single_and) => single_and[0]);
|
|
989
|
-
searchComparedAtValue = searchCriteria.map((single_and) => single_and[1]);
|
|
990
|
-
searchLogicalOperator = "and";
|
|
972
|
+
/* nested object with .and / .or inside */
|
|
973
|
+
const nestedAnd = value.and;
|
|
974
|
+
const nestedOr = value.or;
|
|
975
|
+
if (nestedAnd || nestedOr) {
|
|
976
|
+
const logicalChild = nestedAnd ?? nestedOr;
|
|
977
|
+
const logic = nestedAnd ? "and" : "or";
|
|
978
|
+
const crit = Object.entries(logicalChild)
|
|
979
|
+
.map((item) => typeof item[1] === "string"
|
|
980
|
+
? Utils.FormatObjectCriteriaValue(item[1])
|
|
981
|
+
: ["=", item[1]])
|
|
982
|
+
.filter(Boolean);
|
|
983
|
+
if (crit.length) {
|
|
984
|
+
searchOperator = crit.map((c) => c[0]);
|
|
985
|
+
searchComparedAtValue = crit.map((c) => c[1]);
|
|
986
|
+
searchLogicalOperator = logic;
|
|
991
987
|
}
|
|
992
|
-
delete value.and;
|
|
993
988
|
}
|
|
994
989
|
}
|
|
995
990
|
else if (Array.isArray(value)) {
|
|
996
|
-
const
|
|
997
|
-
.map((
|
|
998
|
-
? Utils.FormatObjectCriteriaValue(
|
|
999
|
-
: ["=",
|
|
1000
|
-
.filter(
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
searchLogicalOperator = "and";
|
|
1005
|
-
}
|
|
991
|
+
const crit = value
|
|
992
|
+
.map((v) => typeof v === "string"
|
|
993
|
+
? Utils.FormatObjectCriteriaValue(v)
|
|
994
|
+
: ["=", v])
|
|
995
|
+
.filter(Boolean);
|
|
996
|
+
searchOperator = crit.map((c) => c[0]);
|
|
997
|
+
searchComparedAtValue = crit.map((c) => c[1]);
|
|
998
|
+
searchLogicalOperator = "or";
|
|
1006
999
|
}
|
|
1007
1000
|
else if (typeof value === "string") {
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
searchComparedAtValue = ComparisonOperatorValue[1];
|
|
1012
|
-
}
|
|
1001
|
+
const [op, val] = Utils.FormatObjectCriteriaValue(value);
|
|
1002
|
+
searchOperator = op;
|
|
1003
|
+
searchComparedAtValue = val;
|
|
1013
1004
|
}
|
|
1014
1005
|
else {
|
|
1015
1006
|
searchOperator = "=";
|
|
1016
1007
|
searchComparedAtValue = value;
|
|
1017
1008
|
}
|
|
1018
|
-
|
|
1009
|
+
/* ---------- disk search ---------- */
|
|
1010
|
+
const [hitRows, totalLines, lineSet] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, searchIn, {
|
|
1019
1011
|
...field,
|
|
1020
1012
|
databasePath: this.databasePath,
|
|
1021
1013
|
table: field.table ?? tableName,
|
|
1022
1014
|
}, options.perPage, (options.page - 1) * options.perPage +
|
|
1023
1015
|
(options.page > 1 ? 1 : 0), true);
|
|
1024
|
-
if (
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
return [id, nestedObj];
|
|
1029
|
-
}));
|
|
1030
|
-
RETURN = allTrue
|
|
1031
|
-
? formatedSearchResult
|
|
1032
|
-
: Utils.deepMerge(RETURN, formatedSearchResult);
|
|
1033
|
-
this.totalItems.set(`${tableName}-${key}`, totalLines);
|
|
1034
|
-
if (linesNumbers?.size && allTrue)
|
|
1035
|
-
searchIn = linesNumbers;
|
|
1016
|
+
if (!hitRows) {
|
|
1017
|
+
if (allTrue)
|
|
1018
|
+
return null; // AND-chain broken
|
|
1019
|
+
continue; // OR-chain: just skip
|
|
1036
1020
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1021
|
+
/* ---------- map rows into RETURN without deep-merge ---------- */
|
|
1022
|
+
for (const [lnStr, val] of Object.entries(hitRows)) {
|
|
1023
|
+
const ln = +lnStr;
|
|
1024
|
+
const row = (RETURN[ln] ??= {});
|
|
1025
|
+
row[key] = val;
|
|
1026
|
+
}
|
|
1027
|
+
this.totalItems.set(`${tableName}-${key}`, totalLines);
|
|
1028
|
+
/* shrink search domain for next AND condition */
|
|
1029
|
+
if (lineSet?.size && allTrue)
|
|
1030
|
+
searchIn = lineSet;
|
|
1039
1031
|
}
|
|
1040
1032
|
}
|
|
1033
|
+
/* ---------- process nested .and / .or recursively (unchanged) ---------- */
|
|
1041
1034
|
if (criteriaAND && Utils.isObject(criteriaAND)) {
|
|
1042
|
-
const
|
|
1043
|
-
if (
|
|
1044
|
-
RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).filter(([_k, v], _i) => Object.keys(v).filter((key) => Object.keys(criteriaAND).includes(key)).length)));
|
|
1045
|
-
}
|
|
1046
|
-
else
|
|
1035
|
+
const res = await this.applyCriteria(tableName, options, criteriaAND, true, searchIn);
|
|
1036
|
+
if (!res)
|
|
1047
1037
|
return null;
|
|
1038
|
+
for (const [lnStr, data] of Object.entries(res))
|
|
1039
|
+
(RETURN[+lnStr] ??= {}), Object.assign(RETURN[+lnStr], data);
|
|
1048
1040
|
}
|
|
1049
1041
|
if (criteriaOR && Utils.isObject(criteriaOR)) {
|
|
1050
|
-
const
|
|
1051
|
-
if (
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
RETURN = {};
|
|
1055
|
-
RETURN = Object.fromEntries(Object.entries(RETURN).filter(([_index, item]) => Object.keys(item).filter((key) => Object.keys(criteriaOR).includes(key) ||
|
|
1056
|
-
Object.keys(criteriaOR).some((criteriaKey) => criteriaKey.startsWith(`${key}.`))).length));
|
|
1057
|
-
if (!Object.keys(RETURN).length)
|
|
1058
|
-
RETURN = {};
|
|
1059
|
-
}
|
|
1060
|
-
else
|
|
1061
|
-
RETURN = {};
|
|
1042
|
+
const res = await this.applyCriteria(tableName, options, criteriaOR, false, undefined);
|
|
1043
|
+
if (res)
|
|
1044
|
+
for (const [lnStr, data] of Object.entries(res))
|
|
1045
|
+
(RETURN[+lnStr] ??= {}), Object.assign(RETURN[+lnStr], data);
|
|
1062
1046
|
}
|
|
1047
|
+
/* ---------- final answer ---------- */
|
|
1063
1048
|
return Object.keys(RETURN).length ? RETURN : null;
|
|
1064
1049
|
}
|
|
1065
1050
|
_filterSchemaByColumns(schema, columns) {
|
package/dist/utils.js
CHANGED
|
@@ -427,8 +427,11 @@ export const FormatObjectCriteriaValue = (value) => {
|
|
|
427
427
|
case "[":
|
|
428
428
|
return value[1] === "]"
|
|
429
429
|
? [
|
|
430
|
-
|
|
431
|
-
value.slice(2)
|
|
430
|
+
"[]",
|
|
431
|
+
value.slice(2)
|
|
432
|
+
.toString()
|
|
433
|
+
.split(",")
|
|
434
|
+
.map((v) => (isNumber(v) ? Number(v) : v)),
|
|
432
435
|
]
|
|
433
436
|
: ["[]", value.slice(1)];
|
|
434
437
|
case "!":
|
|
@@ -439,23 +442,20 @@ export const FormatObjectCriteriaValue = (value) => {
|
|
|
439
442
|
]
|
|
440
443
|
: value[1] === "["
|
|
441
444
|
? [
|
|
442
|
-
|
|
443
|
-
value.slice(3)
|
|
445
|
+
"![]",
|
|
446
|
+
value.slice(3)
|
|
447
|
+
.toString()
|
|
448
|
+
.split(",")
|
|
449
|
+
.map((v) => (isNumber(v) ? Number(v) : v)),
|
|
444
450
|
]
|
|
445
451
|
: [
|
|
446
452
|
`${value.slice(0, 1)}=`,
|
|
447
453
|
value.slice(1),
|
|
448
454
|
];
|
|
449
455
|
case "=":
|
|
450
|
-
return [
|
|
451
|
-
value.slice(0, 1),
|
|
452
|
-
value.slice(1),
|
|
453
|
-
];
|
|
456
|
+
return ["=", value.slice(1)];
|
|
454
457
|
case "*":
|
|
455
|
-
return [
|
|
456
|
-
value.slice(0, 1),
|
|
457
|
-
value.slice(1),
|
|
458
|
-
];
|
|
458
|
+
return ["*", value.slice(1)];
|
|
459
459
|
default:
|
|
460
460
|
return ["=", value];
|
|
461
461
|
}
|
package/dist/utils.server.js
CHANGED
|
@@ -95,10 +95,10 @@ export const addIdToSchema = (schema, startWithID) => {
|
|
|
95
95
|
function _addIdToField(field) {
|
|
96
96
|
if (!field.id) {
|
|
97
97
|
startWithID.value++;
|
|
98
|
-
field.id =
|
|
98
|
+
field.id = startWithID.value;
|
|
99
99
|
}
|
|
100
|
-
else
|
|
101
|
-
field.id =
|
|
100
|
+
else if (isValidID(field.id))
|
|
101
|
+
field.id = decodeID(field.id);
|
|
102
102
|
if ((field.type === "array" || field.type === "object") &&
|
|
103
103
|
isArrayOfObjects(field.children))
|
|
104
104
|
field.children = _addIdToSchema(field.children);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inibase",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Karim Amahtil",
|
|
@@ -69,22 +69,24 @@
|
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@biomejs/biome": "1.9.4",
|
|
72
|
-
"@types/bun": "^1.
|
|
73
|
-
"@types/node": "^22.
|
|
74
|
-
"lefthook": "^1.
|
|
75
|
-
"tinybench": "^
|
|
76
|
-
"
|
|
72
|
+
"@types/bun": "^1.2.10",
|
|
73
|
+
"@types/node": "^22.15.2",
|
|
74
|
+
"lefthook": "^1.11.11",
|
|
75
|
+
"tinybench": "^4.0.1",
|
|
76
|
+
"tsx": "^4.19.3",
|
|
77
|
+
"typescript": "^5.8.3"
|
|
77
78
|
},
|
|
78
79
|
"dependencies": {
|
|
79
|
-
"dotenv": "^16.
|
|
80
|
+
"dotenv": "^16.5.0",
|
|
80
81
|
"inison": "^2.0.1",
|
|
81
82
|
"re2": "^1.21.4"
|
|
82
83
|
},
|
|
83
84
|
"scripts": {
|
|
84
|
-
"prepublish": "
|
|
85
|
-
"
|
|
85
|
+
"prepublish": "tsc",
|
|
86
|
+
"prebuild": "biome check --write src",
|
|
87
|
+
"build": "tsc",
|
|
86
88
|
"benchmark": "./benchmark/run.js",
|
|
87
|
-
"test": "
|
|
88
|
-
"test:utils": "
|
|
89
|
+
"test": "tsx ./tests/inibase.test.ts",
|
|
90
|
+
"test:utils": "tsx ./tests/utils.test.ts"
|
|
89
91
|
}
|
|
90
92
|
}
|