@keshavsoft/kschema-cli 1.1.1

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.
Files changed (111) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +95 -0
  4. package/bin/cli.js +20 -0
  5. package/commands/init.js +20 -0
  6. package/commands/test.js +36 -0
  7. package/dev.md +74 -0
  8. package/index.js +1 -0
  9. package/package.json +16 -0
  10. package/src/core/configStore.js +10 -0
  11. package/src/utils/pathBuilder.js +3 -0
  12. package/src/v1/data/deleteData.js +16 -0
  13. package/src/v1/data/getData.js +13 -0
  14. package/src/v1/data/index.js +4 -0
  15. package/src/v1/data/insertData.js +16 -0
  16. package/src/v1/data/updateData.js +20 -0
  17. package/src/v1/index.js +3 -0
  18. package/src/v2/config/getSchema.js +12 -0
  19. package/src/v2/data/deleteData.js +16 -0
  20. package/src/v2/data/getData.js +13 -0
  21. package/src/v2/data/index.js +4 -0
  22. package/src/v2/data/insertData copy.js +46 -0
  23. package/src/v2/data/insertData.js +52 -0
  24. package/src/v2/data/updateData.js +20 -0
  25. package/src/v2/index.js +3 -0
  26. package/src/v3/config/getSchema.js +12 -0
  27. package/src/v3/data/deleteData.js +16 -0
  28. package/src/v3/data/getData.js +13 -0
  29. package/src/v3/data/index.js +4 -0
  30. package/src/v3/data/insertData.js +27 -0
  31. package/src/v3/data/updateData.js +20 -0
  32. package/src/v3/helpers/fileHelper.js +11 -0
  33. package/src/v3/helpers/pkHelper.js +18 -0
  34. package/src/v3/helpers/validateHelper.js +20 -0
  35. package/src/v3/index.js +3 -0
  36. package/src/v4/config/getSchema.js +12 -0
  37. package/src/v4/data/deleteData.js +16 -0
  38. package/src/v4/data/getData.js +13 -0
  39. package/src/v4/data/index.js +4 -0
  40. package/src/v4/data/insertData.js +47 -0
  41. package/src/v4/data/updateData.js +20 -0
  42. package/src/v4/helpers/fileHelper.js +11 -0
  43. package/src/v4/helpers/pkHelper.js +18 -0
  44. package/src/v4/helpers/recordHelper.js +9 -0
  45. package/src/v4/helpers/validateHelper.js +15 -0
  46. package/src/v4/index.js +3 -0
  47. package/src/v5/config/getSchema.js +12 -0
  48. package/src/v5/data/deleteData.js +16 -0
  49. package/src/v5/data/getData.js +13 -0
  50. package/src/v5/data/index.js +8 -0
  51. package/src/v5/data/insertData.js +56 -0
  52. package/src/v5/data/insertDataStrict.js +63 -0
  53. package/src/v5/data/updateData.js +20 -0
  54. package/src/v5/helpers/fileHelper.js +11 -0
  55. package/src/v5/helpers/pkHelper.js +18 -0
  56. package/src/v5/helpers/recordHelper.js +9 -0
  57. package/src/v5/helpers/validateHelper.js +15 -0
  58. package/src/v5/index.js +3 -0
  59. package/src/v6/config/getSchema.js +12 -0
  60. package/src/v6/data/deleteData.js +16 -0
  61. package/src/v6/data/getData.js +13 -0
  62. package/src/v6/data/index.js +8 -0
  63. package/src/v6/data/insertData.js +56 -0
  64. package/src/v6/data/insertDataStrict.js +76 -0
  65. package/src/v6/data/updateData.js +20 -0
  66. package/src/v6/helpers/fileHelper.js +11 -0
  67. package/src/v6/helpers/pkHelper.js +18 -0
  68. package/src/v6/helpers/recordHelper.js +9 -0
  69. package/src/v6/helpers/validateHelper.js +15 -0
  70. package/src/v6/index.js +21 -0
  71. package/src/v7/config/getSchema.js +12 -0
  72. package/src/v7/data/deleteData.js +16 -0
  73. package/src/v7/data/filterByColumns.js +19 -0
  74. package/src/v7/data/filterByPk.js +16 -0
  75. package/src/v7/data/findByColumns.js +21 -0
  76. package/src/v7/data/findByPk.js +16 -0
  77. package/src/v7/data/getData.js +13 -0
  78. package/src/v7/data/index.js +11 -0
  79. package/src/v7/data/insertData.js +55 -0
  80. package/src/v7/data/insertDataStrict.js +73 -0
  81. package/src/v7/data/updateData.js +20 -0
  82. package/src/v7/helpers/fileHelper.js +16 -0
  83. package/src/v7/helpers/pkHelper.js +21 -0
  84. package/src/v7/helpers/recordHelper.js +15 -0
  85. package/src/v7/helpers/validateHelper.js +27 -0
  86. package/src/v7/index.js +27 -0
  87. package/src/v8/config/getSchema.js +12 -0
  88. package/src/v8/data/deleteByColumnsData.js +20 -0
  89. package/src/v8/data/deleteData.js +22 -0
  90. package/src/v8/data/filterByColumns.js +19 -0
  91. package/src/v8/data/filterByPk.js +16 -0
  92. package/src/v8/data/findByColumns.js +21 -0
  93. package/src/v8/data/findByPk.js +16 -0
  94. package/src/v8/data/getData.js +13 -0
  95. package/src/v8/data/index.js +12 -0
  96. package/src/v8/data/insertData.js +55 -0
  97. package/src/v8/data/insertDataStrict.js +73 -0
  98. package/src/v8/data/updateData.js +20 -0
  99. package/src/v8/helpers/fileHelper.js +16 -0
  100. package/src/v8/helpers/pkHelper.js +21 -0
  101. package/src/v8/helpers/recordHelper.js +15 -0
  102. package/src/v8/helpers/validateHelper.js +27 -0
  103. package/src/v8/index.js +43 -0
  104. package/template/Config/Schemas/BillsTable.json +165 -0
  105. package/template/Config/Schemas/ItemsTable.json +200 -0
  106. package/template/Config/Schemas/LedgerNames.json +45 -0
  107. package/template/Config/Schemas/StockItems.json +45 -0
  108. package/template/Config/api.json +8 -0
  109. package/template/Config/schema.json +8 -0
  110. package/template/Config/ui.json +8 -0
  111. package/template/config.json +4 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * insertDataStrict - Strict Orchestration Flow
3
+ *
4
+ * 1. Load config & schema
5
+ * 2. Resolve primary key + file path
6
+ * 3. Reject manual primary key input
7
+ * 4. Reject extra fields (only schema fields allowed)
8
+ * 5. Read existing data
9
+ * 6. Normalize record (keep only schema fields)
10
+ * 7. Validate (required + unique on schema columns)
11
+ * 8. Attach primary key (auto increment)
12
+ * 9. Push + persist to file
13
+ * 10. Return inserted record
14
+ *
15
+ * Notes:
16
+ * - Only schema-defined fields are allowed
17
+ * - Any extra field will throw an error
18
+ * - Primary key is system-generated only
19
+ */
20
+ import { getConfig } from "../../core/configStore.js";
21
+ import { buildDataPath } from "../../utils/pathBuilder.js";
22
+ import { getSchema } from "../config/getSchema.js";
23
+
24
+ import { getPrimaryKey, attachPrimaryKey } from "../helpers/pkHelper.js";
25
+ import { readData, writeData } from "../helpers/fileHelper.js";
26
+ import { validateRecord } from "../helpers/validateHelper.js";
27
+ import { normalizeRecord } from "../helpers/recordHelper.js";
28
+
29
+ export const insertDataStrict = ({ table, record }) => {
30
+ try {
31
+ const config = getConfig();
32
+ const schema = getSchema(table);
33
+
34
+ const pk = getPrimaryKey(schema.columns);
35
+ const path = buildDataPath(config, table);
36
+
37
+ const schemaFields = schema.columns.map(c => c.field);
38
+
39
+ if (pk in record) {
40
+ throw new Error(`Primary key '${pk}' should not be provided`);
41
+ }
42
+
43
+ const extraFields = Object.keys(record).filter(
44
+ key => !schemaFields.includes(key)
45
+ );
46
+
47
+ if (extraFields.length) {
48
+ throw new Error(`Invalid fields: ${extraFields.join(", ")}`);
49
+ }
50
+
51
+ const data = readData(path);
52
+
53
+ const cleanRecord = normalizeRecord(record, schema.columns);
54
+
55
+ validateRecord(cleanRecord, schema.columns, data);
56
+
57
+ const newRecord = attachPrimaryKey(cleanRecord, pk, data);
58
+
59
+ data.push(newRecord);
60
+
61
+ writeData(path, data);
62
+
63
+ // return newRecord;
64
+
65
+ // existing logic...
66
+ return { success: true, data: newRecord };
67
+ } catch (err) {
68
+ return {
69
+ success: false,
70
+ error: {
71
+ message: err.message,
72
+ code: "VALIDATION_ERROR"
73
+ }
74
+ };
75
+ };
76
+ };
@@ -0,0 +1,20 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+ import { buildDataPath } from "../../utils/pathBuilder.js";
4
+
5
+ export const updateData = ({ table, key, value, updates }) => {
6
+ const cfg = getConfig();
7
+ const path = buildDataPath(cfg, table);
8
+
9
+ const data = JSON.parse(fs.readFileSync(path));
10
+
11
+ const index = data.findIndex(item => item[key] === value);
12
+
13
+ if (index === -1) throw new Error("Record not found");
14
+
15
+ data[index] = { ...data[index], ...updates };
16
+
17
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
18
+
19
+ return data[index];
20
+ };
@@ -0,0 +1,11 @@
1
+ // v3/helpers/fileHelper.js
2
+ import fs from "fs";
3
+
4
+ export const readData = (path) => {
5
+ if (!fs.existsSync(path)) return [];
6
+ return JSON.parse(fs.readFileSync(path, "utf-8"));
7
+ };
8
+
9
+ export const writeData = (path, data) => {
10
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
11
+ };
@@ -0,0 +1,18 @@
1
+ // v3/helpers/pkHelper.js
2
+
3
+ export const getPrimaryKey = (columns) => {
4
+ const pkColumn = columns.find(c => c.primary);
5
+ if (!pkColumn) throw new Error("Primary key not defined");
6
+ return pkColumn.field;
7
+ };
8
+
9
+ export const attachPrimaryKey = (record, pk, data) => {
10
+ const maxId = data.length
11
+ ? Math.max(...data.map(row => row[pk] || 0))
12
+ : 0;
13
+
14
+ return {
15
+ ...record,
16
+ [pk]: maxId + 1
17
+ };
18
+ };
@@ -0,0 +1,9 @@
1
+ export const normalizeRecord = (record, columns) => {
2
+ const clean = {};
3
+ columns.forEach(col => {
4
+ if (record[col.field] !== undefined) {
5
+ clean[col.field] = record[col.field];
6
+ }
7
+ });
8
+ return clean;
9
+ };
@@ -0,0 +1,15 @@
1
+ export const validateRecord = (record, columns, data) => {
2
+ columns.forEach(col => {
3
+ const value = record[col.field];
4
+
5
+ if (col.required && (value === undefined || value === "")) {
6
+ throw new Error(`${col.field} is required`);
7
+ }
8
+
9
+ if (value === undefined) return;
10
+
11
+ if (col.unique && data.some(r => r[col.field] === value)) {
12
+ throw new Error(`${col.field} must be unique`);
13
+ }
14
+ });
15
+ };
@@ -0,0 +1,21 @@
1
+ import { loadConfig, getConfig } from "../core/configStore.js";
2
+ import {
3
+ insertData,
4
+ getData,
5
+ updateData,
6
+ deleteData,
7
+ insertDataStrict
8
+ } from "./data/index.js";
9
+
10
+ export const kschema = {
11
+ loadConfig,
12
+ getConfig,
13
+
14
+ table: (table) => ({
15
+ insert: (record) => insertData({ table, record }),
16
+ get: () => getData({ table }),
17
+ update: (record) => updateData({ table, record }),
18
+ delete: (id) => deleteData({ table, id }),
19
+ insertStrict: (record) => insertDataStrict({ table, record }),
20
+ })
21
+ };
@@ -0,0 +1,12 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+
4
+ export const getSchema = (table) => {
5
+ const config = getConfig();
6
+
7
+ const schemaPath = `${config.SchemaPath}/${table}.json`;
8
+
9
+ const schema = fs.readFileSync(schemaPath, "utf-8");
10
+
11
+ return JSON.parse(schema);
12
+ };
@@ -0,0 +1,16 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+ import { buildDataPath } from "../../utils/pathBuilder.js";
4
+
5
+ export const deleteData = ({ table, key, value }) => {
6
+ const cfg = getConfig();
7
+ const path = buildDataPath(cfg, table);
8
+
9
+ const data = JSON.parse(fs.readFileSync(path));
10
+
11
+ const newData = data.filter(item => item[key] !== value);
12
+
13
+ fs.writeFileSync(path, JSON.stringify(newData, null, 2));
14
+
15
+ return true;
16
+ };
@@ -0,0 +1,19 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getSchema } from "../config/getSchema.js";
4
+
5
+ import { readData } from "../helpers/fileHelper.js";
6
+ import { applyFilter } from "../helpers/recordHelper.js";
7
+ import { validateFilterKeys } from "../helpers/validateHelper.js";
8
+
9
+ export const filterByColumnsData = ({ table, filter }) => {
10
+ const cfg = getConfig();
11
+ const schema = getSchema(table);
12
+
13
+ validateFilterKeys(filter, schema.columns);
14
+
15
+ const path = buildDataPath(cfg, table);
16
+ const data = readData(path);
17
+
18
+ return applyFilter(data, filter);
19
+ };
@@ -0,0 +1,16 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getPrimaryKey } from "../helpers/pkHelper.js";
4
+ import { getSchema } from "../config/getSchema.js";
5
+ import { readData } from "../helpers/fileHelper.js";
6
+
7
+ export const filterByPkData = ({ table, id }) => {
8
+ const cfg = getConfig();
9
+ const schema = getSchema(table);
10
+ const pk = getPrimaryKey(schema.columns);
11
+
12
+ const path = buildDataPath(cfg, table);
13
+ const data = readData(path);
14
+
15
+ return data.filter(row => Number(row[pk]) === Number(id));
16
+ };
@@ -0,0 +1,21 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getSchema } from "../config/getSchema.js";
4
+
5
+ import { readData } from "../helpers/fileHelper.js";
6
+ import { applyFilter } from "../helpers/recordHelper.js";
7
+ import { validateFilterKeys } from "../helpers/validateHelper.js";
8
+
9
+ export const findByColumnsData = ({ table, filter }) => {
10
+ const cfg = getConfig();
11
+ const schema = getSchema(table);
12
+
13
+ validateFilterKeys(filter, schema.columns);
14
+
15
+ const path = buildDataPath(cfg, table);
16
+ const data = readData(path);
17
+
18
+ return data.find(row =>
19
+ Object.keys(filter).every(key => row[key] === filter[key])
20
+ ) || null;
21
+ };
@@ -0,0 +1,16 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getPrimaryKey } from "../helpers/pkHelper.js";
4
+ import { getSchema } from "../config/getSchema.js";
5
+ import { readData } from "../helpers/fileHelper.js";
6
+
7
+ export const findByPkData = ({ table, id }) => {
8
+ const cfg = getConfig();
9
+ const schema = getSchema(table);
10
+ const pk = getPrimaryKey(schema.columns);
11
+
12
+ const path = buildDataPath(cfg, table);
13
+ const data = readData(path);
14
+
15
+ return data.find(row => Number(row[pk]) === Number(id)) || null;
16
+ };
@@ -0,0 +1,13 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+ import { buildDataPath } from "../../utils/pathBuilder.js";
4
+
5
+ export const getData = ({ table }) => {
6
+ const cfg = getConfig();
7
+
8
+ const path = buildDataPath(cfg, table);
9
+
10
+ const data = fs.readFileSync(path, "utf-8");
11
+
12
+ return JSON.parse(data);
13
+ };
@@ -0,0 +1,11 @@
1
+ export { getData } from "./getData.js";
2
+ export { insertData } from "./insertData.js";
3
+ export { insertDataStrict } from "./insertDataStrict.js";
4
+
5
+ export { updateData } from "./updateData.js";
6
+ export { deleteData } from "./deleteData.js";
7
+
8
+ export { findByPkData } from "./findByPk.js";
9
+ export { filterByPkData } from "./filterByPk.js";
10
+
11
+ export { filterByColumnsData } from "./filterByColumns.js";
@@ -0,0 +1,55 @@
1
+ /**
2
+ * insertData - Orchestration Flow
3
+ *
4
+ * 1. Load config & schema
5
+ * 2. Resolve primary key + file path
6
+ * 3. Read existing data
7
+ * 4. Prepare record (allow extra fields, validate only schema fields)
8
+ * 5. Validate (required + unique only on schema columns)
9
+ * 6. Attach primary key (auto increment)
10
+ * 7. Push + persist to file
11
+ * 8. Return inserted record
12
+ *
13
+ * Notes:
14
+ * - Extra fields are NOT validated but are stored
15
+ * - Schema drives validation, not storage
16
+ */
17
+ import { getConfig } from "../../core/configStore.js";
18
+ import { buildDataPath } from "../../utils/pathBuilder.js";
19
+ import { getSchema } from "../config/getSchema.js";
20
+
21
+ import { getPrimaryKey, attachPrimaryKey } from "../helpers/pkHelper.js";
22
+ import { readData, writeData } from "../helpers/fileHelper.js";
23
+ import { validateRecord } from "../helpers/validateHelper.js";
24
+ import { normalizeRecord } from "../helpers/recordHelper.js";
25
+
26
+ /**
27
+ * Inserts a record into the data store
28
+ *
29
+ * @param {Object} params
30
+ * @param {string} params.table - Table name
31
+ * @param {Object} params.record - Record data to insert
32
+ *
33
+ * @returns {Object} Inserted record with primary key
34
+ */
35
+ export const insertData = ({ table, record }) => {
36
+ const config = getConfig();
37
+ const schema = getSchema(table);
38
+
39
+ const pk = getPrimaryKey(schema.columns);
40
+ const path = buildDataPath(config, table);
41
+
42
+ const data = readData(path);
43
+
44
+ const cleanRecord = { ...record };
45
+
46
+ validateRecord(cleanRecord, schema.columns, data);
47
+
48
+ const newRecord = attachPrimaryKey(cleanRecord, pk, data);
49
+
50
+ data.push(newRecord);
51
+
52
+ writeData(path, data);
53
+
54
+ return newRecord[pk];
55
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * insertDataStrict - Strict Orchestration Flow
3
+ *
4
+ * 1. Load config & schema
5
+ * 2. Resolve primary key + file path
6
+ * 3. Reject manual primary key input
7
+ * 4. Reject extra fields (only schema fields allowed)
8
+ * 5. Read existing data
9
+ * 6. Normalize record (keep only schema fields)
10
+ * 7. Validate (required + unique on schema columns)
11
+ * 8. Attach primary key (auto increment)
12
+ * 9. Push + persist to file
13
+ * 10. Return inserted record
14
+ *
15
+ * Notes:
16
+ * - Only schema-defined fields are allowed
17
+ * - Any extra field will throw an error
18
+ * - Primary key is system-generated only
19
+ */
20
+ import { getConfig } from "../../core/configStore.js";
21
+ import { buildDataPath } from "../../utils/pathBuilder.js";
22
+ import { getSchema } from "../config/getSchema.js";
23
+
24
+ import { getPrimaryKey, attachPrimaryKey } from "../helpers/pkHelper.js";
25
+ import { readData, writeData } from "../helpers/fileHelper.js";
26
+ import { validateRecord } from "../helpers/validateHelper.js";
27
+ import { normalizeRecord } from "../helpers/recordHelper.js";
28
+
29
+ export const insertDataStrict = ({ table, record }) => {
30
+ try {
31
+ const config = getConfig();
32
+ const schema = getSchema(table);
33
+
34
+ const pk = getPrimaryKey(schema.columns);
35
+ const path = buildDataPath(config, table);
36
+
37
+ const schemaFields = schema.columns.map(c => c.field);
38
+
39
+ if (pk in record) {
40
+ throw new Error(`Primary key '${pk}' should not be provided`);
41
+ };
42
+
43
+ const extraFields = Object.keys(record).filter(
44
+ key => !schemaFields.includes(key)
45
+ );
46
+
47
+ if (extraFields.length) {
48
+ throw new Error(`Invalid fields: ${extraFields.join(", ")}`);
49
+ };
50
+
51
+ const data = readData(path);
52
+
53
+ const cleanRecord = normalizeRecord(record, schema.columns);
54
+
55
+ validateRecord(cleanRecord, schema.columns, data);
56
+
57
+ const newRecord = attachPrimaryKey(cleanRecord, pk, data);
58
+
59
+ data.push(newRecord);
60
+
61
+ writeData(path, data);
62
+
63
+ return pk;
64
+ } catch (err) {
65
+ return {
66
+ success: false,
67
+ error: {
68
+ message: err.message,
69
+ code: "VALIDATION_ERROR"
70
+ }
71
+ };
72
+ };
73
+ };
@@ -0,0 +1,20 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+ import { buildDataPath } from "../../utils/pathBuilder.js";
4
+
5
+ export const updateData = ({ table, key, value, updates }) => {
6
+ const cfg = getConfig();
7
+ const path = buildDataPath(cfg, table);
8
+
9
+ const data = JSON.parse(fs.readFileSync(path));
10
+
11
+ const index = data.findIndex(item => item[key] === value);
12
+
13
+ if (index === -1) throw new Error("Record not found");
14
+
15
+ data[index] = { ...data[index], ...updates };
16
+
17
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
18
+
19
+ return data[index];
20
+ };
@@ -0,0 +1,16 @@
1
+ import fs from "fs";
2
+
3
+ export const readData = (path) => {
4
+ if (!fs.existsSync(path)) return [];
5
+ return JSON.parse(fs.readFileSync(path, "utf-8"));
6
+ };
7
+
8
+ export const writeData = (path, data) => {
9
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
10
+ };
11
+
12
+ export const applyFilter = (data, filter) => {
13
+ return data.filter(row =>
14
+ Object.keys(filter).every(key => row[key] === filter[key])
15
+ );
16
+ };
@@ -0,0 +1,21 @@
1
+ // v3/helpers/pkHelper.js
2
+
3
+ export const getPrimaryKey = (columns) => {
4
+ const pkColumn = columns.find(c => c.primary);
5
+ if (!pkColumn) throw new Error("Primary key not defined");
6
+ return pkColumn.field;
7
+ };
8
+
9
+ export const attachPrimaryKey = (record, pk, data) => {
10
+ let maxId = 0;
11
+
12
+ for (const row of data) {
13
+ const val = Number(row[pk]) || 0;
14
+ if (val > maxId) maxId = val;
15
+ }
16
+
17
+ return {
18
+ ...record,
19
+ [pk]: maxId + 1
20
+ };
21
+ };
@@ -0,0 +1,15 @@
1
+ export const normalizeRecord = (record, columns) => {
2
+ const clean = {};
3
+ columns.forEach(col => {
4
+ if (record[col.field] !== undefined) {
5
+ clean[col.field] = record[col.field];
6
+ }
7
+ });
8
+ return clean;
9
+ };
10
+
11
+ export const applyFilter = (data, filter) => {
12
+ return data.filter(row =>
13
+ Object.keys(filter).every(key => row[key] === filter[key])
14
+ );
15
+ };
@@ -0,0 +1,27 @@
1
+ export const validateRecord = (record, columns, data) => {
2
+ columns.forEach(col => {
3
+ const value = record[col.field];
4
+
5
+ if (col.required && (value === undefined || value === null || value === "")) {
6
+ throw new Error(`${col.field} is required`);
7
+ }
8
+
9
+ if (value === undefined) return;
10
+
11
+ if (col.unique && data.some(r => r[col.field] === value)) {
12
+ throw new Error(`${col.field} must be unique`);
13
+ }
14
+ });
15
+ };
16
+
17
+ export const validateFilterKeys = (filter, columns) => {
18
+ const validColumns = columns.map(col => col.field);
19
+
20
+ const invalidKeys = Object.keys(filter).filter(
21
+ key => !validColumns.includes(key)
22
+ );
23
+
24
+ if (invalidKeys.length > 0) {
25
+ throw new Error(`Invalid columns: ${invalidKeys.join(", ")}`);
26
+ };
27
+ };
@@ -0,0 +1,27 @@
1
+ import { loadConfig, getConfig } from "../core/configStore.js";
2
+ import {
3
+ insertData,
4
+ getData,
5
+ updateData,
6
+ deleteData,
7
+ insertDataStrict,
8
+ findByPkData,
9
+ filterByPkData,
10
+ filterByColumnsData
11
+ } from "./data/index.js";
12
+
13
+ export const kschema = {
14
+ loadConfig,
15
+ getConfig,
16
+
17
+ table: (table) => ({
18
+ insert: (record) => insertData({ table, record }),
19
+ get: () => getData({ table }),
20
+ update: (record) => updateData({ table, record }),
21
+ delete: (id) => deleteData({ table, id }),
22
+ insertStrict: (record) => insertDataStrict({ table, record }),
23
+ findByPk: (id) => findByPkData({ table, id }),
24
+ filterByPk: (id) => filterByPkData({ table, id }),
25
+ filterByColumns: (filter) => filterByColumnsData({ table, filter }),
26
+ })
27
+ };
@@ -0,0 +1,12 @@
1
+ import fs from "fs";
2
+ import { getConfig } from "../../core/configStore.js";
3
+
4
+ export const getSchema = (table) => {
5
+ const config = getConfig();
6
+
7
+ const schemaPath = `${config.SchemaPath}/${table}.json`;
8
+
9
+ const schema = fs.readFileSync(schemaPath, "utf-8");
10
+
11
+ return JSON.parse(schema);
12
+ };
@@ -0,0 +1,20 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { readData, writeData } from "../helpers/fileHelper.js";
4
+ import { applyFilter } from "../helpers/recordHelper.js";
5
+
6
+ const deleteByColumnsData = ({ table, filter }) => {
7
+ const config = getConfig();
8
+ const path = buildDataPath(config, table);
9
+ const data = readData(path);
10
+
11
+ const toDelete = applyFilter(data, filter);
12
+ if (toDelete.length === 0) throw new Error(`No records match filter`);
13
+
14
+ const newData = data.filter(item => !toDelete.includes(item));
15
+ writeData(path, newData);
16
+
17
+ return toDelete.length;
18
+ };
19
+
20
+ export { deleteByColumnsData };
@@ -0,0 +1,22 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getSchema } from "../config/getSchema.js";
4
+ import { getPrimaryKey } from "../helpers/pkHelper.js";
5
+ import { readData, writeData } from "../helpers/fileHelper.js";
6
+
7
+ const deleteData = ({ table, id }) => {
8
+ const config = getConfig();
9
+ const path = buildDataPath(config, table);
10
+
11
+ const pk = getPrimaryKey(getSchema(table).columns);
12
+
13
+ const data = readData(path);
14
+
15
+ if (!data.some(item => item[pk] === id)) throw new Error(`${pk}: ${id} not found`);
16
+
17
+ writeData(path, data.filter(item => item[pk] !== id));
18
+
19
+ return true;
20
+ };
21
+
22
+ export { deleteData };
@@ -0,0 +1,19 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getSchema } from "../config/getSchema.js";
4
+
5
+ import { readData } from "../helpers/fileHelper.js";
6
+ import { applyFilter } from "../helpers/recordHelper.js";
7
+ import { validateFilterKeys } from "../helpers/validateHelper.js";
8
+
9
+ export const filterByColumnsData = ({ table, filter }) => {
10
+ const cfg = getConfig();
11
+ const schema = getSchema(table);
12
+
13
+ validateFilterKeys(filter, schema.columns);
14
+
15
+ const path = buildDataPath(cfg, table);
16
+ const data = readData(path);
17
+
18
+ return applyFilter(data, filter);
19
+ };
@@ -0,0 +1,16 @@
1
+ import { getConfig } from "../../core/configStore.js";
2
+ import { buildDataPath } from "../../utils/pathBuilder.js";
3
+ import { getPrimaryKey } from "../helpers/pkHelper.js";
4
+ import { getSchema } from "../config/getSchema.js";
5
+ import { readData } from "../helpers/fileHelper.js";
6
+
7
+ export const filterByPkData = ({ table, id }) => {
8
+ const cfg = getConfig();
9
+ const schema = getSchema(table);
10
+ const pk = getPrimaryKey(schema.columns);
11
+
12
+ const path = buildDataPath(cfg, table);
13
+ const data = readData(path);
14
+
15
+ return data.filter(row => Number(row[pk]) === Number(id));
16
+ };