datafolder 1.0.3 → 1.0.5

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 CHANGED
@@ -14,30 +14,26 @@ datafolder is a lightweight JSON database, featuring an AI-friendly API for simp
14
14
  import DataFolder from "datafolder";
15
15
  const dataFolder = new DataFolder(); //Specify where to store the data. Default is ./data/sampleDataFolder
16
16
  await dataFolder.start(); //start() and stop() are the only two async places. All other code doesn't need await.
17
- dataFolder.insert("users/2026/user_0001", {
17
+ dataFolder.insert("traindata/2026/1/20/chat_0001", {
18
18
  userid: "user_0001",
19
19
  email: "a@b.com",
20
- score: 5,
20
+ feedbackScore: 5,
21
21
  address: { city: "a", zipcode: 123 },
22
22
  });
23
- dataFolder.insert("users/2026/user_0002", {
24
- userid: "user_0002",
25
- email: "c@b.com",
26
- score: 3,
27
- address: { city: "b", zipcode: 321 },
28
- });
29
- const { email, password, address, score } = dataFolder.view("users/2026/user_0002");
23
+ dataFolder.insert("traindata/2026/1/20/chat_0001/prompt", "What is async/await?");
24
+ dataFolder.insert("traindata/2026/1/20/chat_0001/answer", "async/await is ...");
25
+ const { email, password, address, feedbackScore } = dataFolder.view("traindata/2026/1/20/chat_0001");
30
26
  address.zipcode = 678;
31
- dataFolder.insert("users/2026/user_0002", { score: score + 1, address });
27
+ dataFolder.insert("traindata/2026/1/20/chat_0001", { feedbackScore: feedbackScore + 1, address });
32
28
  await dataFolder.stop();
33
29
  ```
34
30
 
35
31
  Or operate with dir/file objects:
36
32
 
37
33
  ```javascript
38
- const file = dataFolder.file("users/2026/user_0002");
39
- const { score, address } = file.view({ score: 1, address: 1 });
40
- dataFolder.insert(file, { score: score + 1, address: { city: "c", zipcode: 663 } });
34
+ const file = dataFolder.file("traindata/2026/1/20/chat_0001");
35
+ const { feedbackScore, address } = file.view({ feedbackScore: 1, address: 1 });
36
+ dataFolder.insert(file, { feedbackScore: feedbackScore + 1, address: { city: "c", zipcode: 663 } });
41
37
  ```
42
38
 
43
39
  ## Features
@@ -75,7 +71,7 @@ const { email, address } = dataFolder.view("path/to/file", { email: 1, addres: 1
75
71
 
76
72
  ```javascript
77
73
  dataFolder.insert("path/to/file", { email: newEmail, address: { zipcode: newZipcode } });
78
- dataFolder.insert(file, { score: score + 1 });
74
+ dataFolder.insert(file, { feedbackScore: feedbackScore + 1 });
79
75
  ```
80
76
 
81
77
  #### Delete
@@ -91,14 +87,15 @@ dataFolder.remove(file, { email: 1, address: { zipcode: 1 } });
91
87
  ### 2. Batch APIs
92
88
 
93
89
  ```javascript
94
- const [dir, file, { email, score }] = dataFolder.fetch
90
+ const [dir, file, { email, feedbackScore }] = dataFolder.fetch
95
91
  .dir("path/to/dir")
96
92
  .file("path/to/file")
97
93
  .view("path/to/file")
98
94
  .run();
99
95
  dataFolder.batch
100
- .insert("path/to/file", { email: "email1@a.b.com" })
101
- .insert("path/to/file", { email: "email2", score: 100 })
96
+ .insert("path/to/chat_details", { user: "user_0001", feedbackScore: 100 })
97
+ .insert("path/to/prompt", "what is LLM?")
98
+ .insert("path/to/answer", "LLM is AI...")
102
99
  .remove("path/to/file", { address: { city: 1 } })
103
100
  .run();
104
101
  ```
@@ -106,6 +103,15 @@ dataFolder.batch
106
103
  ### 3. Powerful Query Support. Auto Create Needed Indexes
107
104
 
108
105
  ```javascript
106
+ // get all the training data in year 2026 with feedbackScore between 60 and 85.
107
+ dataFolder.queryFiles("traindata/2026/**", { feedbackScore: (x) => x >= 60 && x <= 85 });
108
+
109
+ // get training data of user_001 from July to Oct in year 2025, 2026 with feedbackScore higher than 90.
110
+ dataFolder.queryFiles(["traindata", { $in: [2025, 2026] }, { $gt: 6, $lte: 10 }], {
111
+ feedbackScore: { $gt: 90 },
112
+ userId: "user_0001",
113
+ });
114
+
109
115
  dataFolder.queryFiles("flights/**", { _from: "airports/LAX" });
110
116
  dataFolder.queryFiles(["flights", "*", "jan", (x) => x >= 5 && x <= 7], {
111
117
  $or: [{ _from: "airports/BIS" }, { _to: "airports/BIS" }],
@@ -125,23 +131,23 @@ dataFolder.queryFilesMulti([
125
131
  ### 4. Flexible Trigger Support to Monitor Any Changes
126
132
 
127
133
  ```javascript
128
- function onEmailChanged({ studentId, email }) {
129
- const { oldValue, newValue } = email;
130
- // Logic to handle email change.
134
+ function onPromptScoreChanged({ promptId, feedbackScore }) {
135
+ const { oldValue, newValue } = feedbackScore;
136
+ // Logic to handle prompt feedback score change.
131
137
  }
132
- dataFolder.insertTrigger("emailChanged", "students/{studentId}", "email");
133
- dataFolder.on("emailChanged", onEmailChanged);
134
- dataFolder.insert("students/student1", { email: "email1" });
135
- dataFolder.insert("students/student2", { email: "email2" });
136
- dataFolder.insert("students/student1", { email: "email1_changed" });
138
+ dataFolder.insertTrigger("promptScoreChanged", "traindata/{promptId}", "feedbackScore");
139
+ dataFolder.on("promptScoreChanged", onPromptScoreChanged);
140
+ dataFolder.insert("traindata/prompt_1", { feedbackScore: 80 });
141
+ dataFolder.insert("traindata/prompt_2", { feedbackScore: 63 });
142
+ dataFolder.insert("traindata/prompt_1", { feedbackScore: 32 });
137
143
  ```
138
144
 
139
145
  Will trigger the following calls:
140
146
 
141
147
  ```javascript
142
- onEmailChanged({ studentId: "student1", email: { oldValue: undefined, newValue: "email1" } });
143
- onEmailChanged({ studentId: "student2", email: { oldValue: undefined, newValue: "email2" } });
144
- onEmailChanged({ studentId: "student1", email: { oldValue: "email1", newValue: "email1_changed" } });
148
+ onPromptScoreChanged({ promptId: "student1", feedbackScore: { oldValue: undefined, newValue: 80 } });
149
+ onPromptScoreChanged({ promptId: "student2", feedbackScore: { oldValue: undefined, newValue: 63 } });
150
+ onPromptScoreChanged({ promptId: "student1", feedbackScore: { oldValue: 80, newValue: 32 } });
145
151
  ```
146
152
 
147
153
  ## Example
package/index.js CHANGED
@@ -1,2 +1 @@
1
- import { QyDB } from "./src/QyDB.js";
2
- export default QyDB;
1
+ export { QyDB as default } from "./src/QyDB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datafolder",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "author": {
5
5
  "name": "lysh",
6
6
  "email": "datafolderdev@outlook.com"
@@ -37,7 +37,8 @@
37
37
  "easy",
38
38
  "quick",
39
39
  "millisecond",
40
- "lightweight"
40
+ "lightweight",
41
+ "LSM"
41
42
  ],
42
43
  "dependencies": {},
43
44
  "devDependencies": {
@@ -7,7 +7,7 @@ function query1(qyDB) {
7
7
  .queryFiles(["airbnb", "Loft", "Entire home/apt", "Real Bed"], {
8
8
  address: { street: "Porto, Porto, Portugal" },
9
9
  })
10
- .map((x) => x.view(["name"]).name),
10
+ .map((x) => x.prop("name")),
11
11
  [
12
12
  "Porto city centre apartment H",
13
13
  "Romantic loft near historic center",
@@ -41,7 +41,7 @@ function query2(qyDB) {
41
41
  },
42
42
  9,
43
43
  )
44
- .map((x) => x.view(["name"]).name),
44
+ .map((x) => x.prop("name")),
45
45
  [
46
46
  "Porto city centre apartment H",
47
47
  "Romantic loft near historic center",
@@ -66,7 +66,7 @@ function query3(qyDB) {
66
66
  9,
67
67
  9,
68
68
  )
69
- .map((x) => x.view(["name"]).name),
69
+ .map((x) => x.prop("name")),
70
70
  [
71
71
  "Bright Top Floor Two Rooms Apartment w/ Terrace",
72
72
  "ReUrban Flats - Santa Catarina #3",
@@ -89,7 +89,7 @@ function query4(qyDB) {
89
89
  ["airbnb/Loft/**", { minimum_nights: (x) => x >= 60 }],
90
90
  ])
91
91
  .run()[0]
92
- .map((x) => x.view(["name"]).name)
92
+ .map((x) => x.prop("name"))
93
93
  .sort(),
94
94
  [
95
95
  "Porto city centre apartment H",
@@ -128,7 +128,7 @@ function query5(qyDB) {
128
128
  ],
129
129
  3,
130
130
  )
131
- .map((x) => x.view(["name"]).name),
131
+ .map((x) => x.prop("name")),
132
132
  [
133
133
  "Porto city centre apartment H",
134
134
  "Romantic loft near historic center",
@@ -152,7 +152,7 @@ function query6(qyDB) {
152
152
  20,
153
153
  10,
154
154
  )
155
- .map((x) => x.view(["name"]).name),
155
+ .map((x) => x.prop("name")),
156
156
  [
157
157
  "ReUrban Flats - Santa Catarina #3",
158
158
  "The Blue and White Porto House - Vintage",
@@ -169,7 +169,7 @@ function query6(qyDB) {
169
169
  function query7(qyDB) {
170
170
  console.time("query7");
171
171
  deepEqual(
172
- qyDB.queryFiles(["airbnb", "Loft", "**"], { minimum_nights: (x) => x >= 60 }).map((x) => x.view(["name"]).name),
172
+ qyDB.queryFiles(["airbnb", "Loft", "**"], { minimum_nights: (x) => x >= 60 }).map((x) => x.prop("name")),
173
173
  ["Romantic loft near historic center", "Brand New Luxury Downtown Studio"],
174
174
  );
175
175
  console.timeEnd("query7");
@@ -177,9 +177,7 @@ function query7(qyDB) {
177
177
  function query8(qyDB) {
178
178
  console.time("query8");
179
179
  deepEqual(
180
- qyDB
181
- .queryFiles(["airbnb", "Loft", ""], { minimum_nights: (x) => x >= 60 }, 10, 10)
182
- .map((x) => x.view(["name"]).name),
180
+ qyDB.queryFiles(["airbnb", "Loft", ""], { minimum_nights: (x) => x >= 60 }, 10, 10).map((x) => x.prop("name")),
183
181
  [],
184
182
  );
185
183
  console.timeEnd("query8");
@@ -198,7 +196,7 @@ function query9(qyDB) {
198
196
  ],
199
197
  3,
200
198
  )
201
- .map((x) => x.view(["name"]).name),
199
+ .map((x) => x.prop("name")),
202
200
  [
203
201
  "Porto city centre apartment H",
204
202
  "Romantic loft near historic center",
@@ -10,7 +10,7 @@ function query1(qyDB) {
10
10
  bed_type: "Real Bed",
11
11
  address: { street: "Porto, Porto, Portugal" },
12
12
  })
13
- .map((x) => x.view(["name"]).name),
13
+ .map((x) => x.prop("name")),
14
14
  [
15
15
  "Porto city centre apartment H",
16
16
  "Romantic loft near historic center",
@@ -47,7 +47,7 @@ function query2(qyDB) {
47
47
  },
48
48
  9,
49
49
  )
50
- .map((x) => x.view(["name"]).name),
50
+ .map((x) => x.prop("name")),
51
51
  [
52
52
  "Porto city centre apartment H",
53
53
  "Romantic loft near historic center",
@@ -77,7 +77,7 @@ function query3(qyDB) {
77
77
  9,
78
78
  9,
79
79
  )
80
- .map((x) => x.view(["name"]).name),
80
+ .map((x) => x.prop("name")),
81
81
  [
82
82
  "Bright Top Floor Two Rooms Apartment w/ Terrace",
83
83
  "ReUrban Flats - Santa Catarina #3",
@@ -106,7 +106,7 @@ function query4(qyDB) {
106
106
  { property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 },
107
107
  ],
108
108
  })
109
- .map((x) => x.view(["name"]).name)
109
+ .map((x) => x.prop("name"))
110
110
  .sort(),
111
111
  [
112
112
  "Porto city centre apartment H",
@@ -150,7 +150,7 @@ function query5(qyDB) {
150
150
  },
151
151
  3,
152
152
  )
153
- .map((x) => x.view(["name"]).name),
153
+ .map((x) => x.prop("name")),
154
154
  [
155
155
  "Porto city centre apartment H",
156
156
  "Romantic loft near historic center",
@@ -179,7 +179,7 @@ function query6(qyDB) {
179
179
  20,
180
180
  10,
181
181
  )
182
- .map((x) => x.view(["name"]).name),
182
+ .map((x) => x.prop("name")),
183
183
  [
184
184
  "ReUrban Flats - Santa Catarina #3",
185
185
  "The Blue and White Porto House - Vintage",
@@ -198,7 +198,7 @@ function query7(qyDB) {
198
198
  deepEqual(
199
199
  qyDB
200
200
  .queryFiles("airbnb1", { property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 })
201
- .map((x) => x.view(["name"]).name),
201
+ .map((x) => x.prop("name")),
202
202
  ["Romantic loft near historic center", "Brand New Luxury Downtown Studio"],
203
203
  );
204
204
  console.timeEnd("query7");
@@ -208,7 +208,7 @@ function query8(qyDB) {
208
208
  deepEqual(
209
209
  qyDB
210
210
  .queryFiles("airbnb1", { property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 }, 10, 10)
211
- .map((x) => x.view(["name"]).name),
211
+ .map((x) => x.prop("name")),
212
212
  [],
213
213
  );
214
214
  console.timeEnd("query8");
@@ -232,7 +232,7 @@ function query9(qyDB) {
232
232
  },
233
233
  3,
234
234
  )
235
- .map((x) => x.view(["name"]).name),
235
+ .map((x) => x.prop("name")),
236
236
  [
237
237
  "Porto city centre apartment H",
238
238
  "Romantic loft near historic center",
@@ -1,5 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { QyDB } from "../src/QyDB.js";
3
+ import Express from "express";
3
4
  import { __dirname } from "../src/QyUtils.js";
4
5
 
5
6
  const config = {
@@ -10,7 +11,7 @@ const config = {
10
11
  };
11
12
 
12
13
  const { port, qyDBDataFolder } = config;
13
- const app = require("express")();
14
+ const app = Express();
14
15
  const qyDB = new QyDB(qyDBDataFolder);
15
16
 
16
17
  let server;
@@ -9,7 +9,7 @@ import { runQueries } from "./flights_queries.js";
9
9
 
10
10
  logger.level = "info";
11
11
 
12
- const arangoJsonFolderPath = "../GraphCourse_DemoData_ArangoDB-2";
12
+ const arangoJsonFolderPath = "D:\\scripts\\GraphCourse_DemoData_ArangoDB-2";
13
13
  const dataFolder = "./tmp/flights";
14
14
 
15
15
  const qyDB = new QyDB(dataFolder, { preloadFoldersAtStart: false });
@@ -6,94 +6,93 @@ import { deepEqual } from "node:assert/strict";
6
6
 
7
7
  function query1(qyDB) {
8
8
  console.time("query1");
9
- const resultMap = {};
10
- for (const x of qyDB.queryFiles("flights/**", { _from: "airports/LAX" })) {
11
- resultMap[x.fileContent._to] = 1;
12
- }
13
- deepEqual(Object.keys(resultMap), [
14
- "airports/CVG",
15
- "airports/SMF",
16
- "airports/ATL",
17
- "airports/MSP",
18
- "airports/DFW",
19
- "airports/PHL",
20
- "airports/IAH",
21
- "airports/TUS",
22
- "airports/ORD",
23
- "airports/PDX",
24
- "airports/MIA",
25
- "airports/SFO",
26
- "airports/DEN",
27
- "airports/IAD",
28
- "airports/SJC",
29
- "airports/PHX",
30
- "airports/SEA",
31
- "airports/SLC",
32
- "airports/JFK",
33
- "airports/SAN",
34
- "airports/ONT",
35
- "airports/LAS",
36
- "airports/MCI",
37
- "airports/MDW",
38
- "airports/FLL",
39
- "airports/AUS",
40
- "airports/EWR",
41
- "airports/CLE",
42
- "airports/SBP",
43
- "airports/MEM",
44
- "airports/SBA",
45
- "airports/CLT",
46
- "airports/COS",
47
- "airports/ASE",
48
- "airports/ICT",
49
- "airports/HOU",
50
- "airports/YUM",
51
- "airports/STL",
52
- "airports/FAT",
53
- "airports/ABQ",
54
- "airports/BOI",
55
- "airports/BOS",
56
- "airports/LIH",
57
- "airports/HNL",
58
- "airports/SMX",
59
- "airports/MRY",
60
- "airports/DTW",
61
- "airports/RNO",
62
- "airports/MCO",
63
- "airports/OXR",
64
- "airports/OAK",
65
- "airports/OGG",
66
- "airports/KOA",
67
- "airports/BWI",
68
- "airports/CLD",
69
- "airports/IND",
70
- "airports/PSP",
71
- "airports/ELP",
72
- "airports/TPA",
73
- "airports/OKC",
74
- "airports/MSY",
75
- "airports/SNA",
76
- "airports/IYK",
77
- "airports/IPL",
78
- "airports/SAT",
79
- "airports/MOD",
80
- "airports/BNA",
81
- "airports/DCA",
82
- "airports/SGU",
83
- "airports/BFL",
84
- "airports/EUG",
85
- "airports/EGE",
86
- "airports/GEG",
87
- "airports/BDL",
88
- "airports/JAX",
89
- "airports/CMH",
90
- "airports/PIT",
91
- "airports/RDU",
92
- "airports/SJU",
93
- "airports/XNA",
94
- "airports/MTJ",
95
- "airports/JAC",
96
- ]);
9
+ deepEqual(
10
+ [...new Set(qyDB.queryFiles("flights/**", { _from: "airports/LAX" }).map((x) => x.prop("_to"))).values()],
11
+ [
12
+ "airports/CVG",
13
+ "airports/SMF",
14
+ "airports/ATL",
15
+ "airports/MSP",
16
+ "airports/DFW",
17
+ "airports/PHL",
18
+ "airports/IAH",
19
+ "airports/TUS",
20
+ "airports/ORD",
21
+ "airports/PDX",
22
+ "airports/MIA",
23
+ "airports/SFO",
24
+ "airports/DEN",
25
+ "airports/IAD",
26
+ "airports/SJC",
27
+ "airports/PHX",
28
+ "airports/SEA",
29
+ "airports/SLC",
30
+ "airports/JFK",
31
+ "airports/SAN",
32
+ "airports/ONT",
33
+ "airports/LAS",
34
+ "airports/MCI",
35
+ "airports/MDW",
36
+ "airports/FLL",
37
+ "airports/AUS",
38
+ "airports/EWR",
39
+ "airports/CLE",
40
+ "airports/SBP",
41
+ "airports/MEM",
42
+ "airports/SBA",
43
+ "airports/CLT",
44
+ "airports/COS",
45
+ "airports/ASE",
46
+ "airports/ICT",
47
+ "airports/HOU",
48
+ "airports/YUM",
49
+ "airports/STL",
50
+ "airports/FAT",
51
+ "airports/ABQ",
52
+ "airports/BOI",
53
+ "airports/BOS",
54
+ "airports/LIH",
55
+ "airports/HNL",
56
+ "airports/SMX",
57
+ "airports/MRY",
58
+ "airports/DTW",
59
+ "airports/RNO",
60
+ "airports/MCO",
61
+ "airports/OXR",
62
+ "airports/OAK",
63
+ "airports/OGG",
64
+ "airports/KOA",
65
+ "airports/BWI",
66
+ "airports/CLD",
67
+ "airports/IND",
68
+ "airports/PSP",
69
+ "airports/ELP",
70
+ "airports/TPA",
71
+ "airports/OKC",
72
+ "airports/MSY",
73
+ "airports/SNA",
74
+ "airports/IYK",
75
+ "airports/IPL",
76
+ "airports/SAT",
77
+ "airports/MOD",
78
+ "airports/BNA",
79
+ "airports/DCA",
80
+ "airports/SGU",
81
+ "airports/BFL",
82
+ "airports/EUG",
83
+ "airports/EGE",
84
+ "airports/GEG",
85
+ "airports/BDL",
86
+ "airports/JAX",
87
+ "airports/CMH",
88
+ "airports/PIT",
89
+ "airports/RDU",
90
+ "airports/SJU",
91
+ "airports/XNA",
92
+ "airports/MTJ",
93
+ "airports/JAC",
94
+ ],
95
+ );
97
96
  console.timeEnd("query1");
98
97
  }
99
98
 
@@ -116,7 +115,7 @@ function query2(qyDB) {
116
115
  .queryFiles(["flights", "*", 1, (x) => x >= 5 && x <= 7], {
117
116
  $or: [{ _from: "airports/BIS" }, { _to: "airports/BIS" }],
118
117
  })
119
- .map((x) => x.fileContent.FlightNum)
118
+ .map((x) => x.prop("FlightNum"))
120
119
  .sort((x, y) => x - y),
121
120
  [
122
121
  6635, 646, 6541, 5651, 6541, 5648, 687, 309, 6678, 6678, 6636, 439, 1567, 6635, 5647, 6541, 5660, 6541,
@@ -370,7 +369,7 @@ function query5(qyDB) {
370
369
  deepEqual(
371
370
  qyDB
372
371
  .queryFiles("**", { vip: true })
373
- .map((x) => x.fileContent.name)
372
+ .map((x) => x.prop("name"))
374
373
  .sort(),
375
374
  [
376
375
  "Amarillo International",
@@ -414,7 +413,7 @@ function query7(qyDB) {
414
413
  .queryFiles(["flights", "*", { $or: [1] }, [5, 6, 7]], {
415
414
  $or: [{ _from: "airports/BIS" }, { _to: "airports/BIS" }],
416
415
  })
417
- .map((x) => x.fileContent.FlightNum)
416
+ .map((x) => x.prop("FlightNum"))
418
417
  .sort((x, y) => x - y),
419
418
  [
420
419
  6635, 646, 6541, 5651, 6541, 5648, 687, 309, 6678, 6678, 6636, 439, 1567, 6635, 5647, 6541, 5660, 6541,
@@ -428,7 +427,7 @@ function query7(qyDB) {
428
427
  function query8(qyDB) {
429
428
  console.time("query8");
430
429
  deepEqual(
431
- qyDB.queryFiles("**", { name: "Thigpen " }).map((x) => x.fileContent.name),
430
+ qyDB.queryFiles("**", { name: "Thigpen " }).map((x) => x.prop("name")),
432
431
  ["Thigpen "],
433
432
  );
434
433
  console.timeEnd("query8");