sehawq.db 4.0.2 → 4.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/.github/workflows/npm-publish.yml +30 -30
- package/LICENSE +21 -21
- package/index.js +1 -1
- package/package.json +36 -36
- package/readme.md +413 -413
- package/src/core/Database.js +294 -294
- package/src/core/Events.js +285 -285
- package/src/core/IndexManager.js +813 -813
- package/src/core/Persistence.js +375 -375
- package/src/core/QueryEngine.js +447 -447
- package/src/core/Storage.js +321 -321
- package/src/core/Validator.js +324 -324
- package/src/index.js +115 -115
- package/src/performance/Cache.js +338 -338
- package/src/performance/LazyLoader.js +354 -354
- package/src/performance/MemoryManager.js +495 -495
- package/src/server/api.js +687 -687
- package/src/server/websocket.js +527 -527
- package/src/utils/benchmark.js +51 -51
- package/src/utils/dot-notation.js +247 -247
- package/src/utils/helpers.js +275 -275
- package/src/utils/profiler.js +70 -70
- package/src/version.js +37 -37
package/src/utils/benchmark.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
// Path utility functions for nested object access
|
|
2
|
-
|
|
3
|
-
function getByPath(obj, pathStr) {
|
|
4
|
-
if (!pathStr) return obj;
|
|
5
|
-
|
|
6
|
-
const keys = pathStr.split(".");
|
|
7
|
-
let result = obj;
|
|
8
|
-
|
|
9
|
-
for (const k of keys) {
|
|
10
|
-
if (result && Object.prototype.hasOwnProperty.call(result, k)) {
|
|
11
|
-
result = result[k];
|
|
12
|
-
} else {
|
|
13
|
-
return undefined;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function setByPath(obj, pathStr, value) {
|
|
21
|
-
const keys = pathStr.split(".");
|
|
22
|
-
let current = obj;
|
|
23
|
-
|
|
24
|
-
while (keys.length > 1) {
|
|
25
|
-
const k = keys.shift();
|
|
26
|
-
if (!current[k] || typeof current[k] !== "object") {
|
|
27
|
-
current[k] = {};
|
|
28
|
-
}
|
|
29
|
-
current = current[k];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
current[keys[0]] = value;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function deleteByPath(obj, pathStr) {
|
|
36
|
-
const keys = pathStr.split(".");
|
|
37
|
-
let current = obj;
|
|
38
|
-
|
|
39
|
-
while (keys.length > 1) {
|
|
40
|
-
const k = keys.shift();
|
|
41
|
-
if (!current[k]) return;
|
|
42
|
-
current = current[k];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
delete current[keys[0]];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = {
|
|
49
|
-
getByPath,
|
|
50
|
-
setByPath,
|
|
51
|
-
deleteByPath
|
|
1
|
+
// Path utility functions for nested object access
|
|
2
|
+
|
|
3
|
+
function getByPath(obj, pathStr) {
|
|
4
|
+
if (!pathStr) return obj;
|
|
5
|
+
|
|
6
|
+
const keys = pathStr.split(".");
|
|
7
|
+
let result = obj;
|
|
8
|
+
|
|
9
|
+
for (const k of keys) {
|
|
10
|
+
if (result && Object.prototype.hasOwnProperty.call(result, k)) {
|
|
11
|
+
result = result[k];
|
|
12
|
+
} else {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setByPath(obj, pathStr, value) {
|
|
21
|
+
const keys = pathStr.split(".");
|
|
22
|
+
let current = obj;
|
|
23
|
+
|
|
24
|
+
while (keys.length > 1) {
|
|
25
|
+
const k = keys.shift();
|
|
26
|
+
if (!current[k] || typeof current[k] !== "object") {
|
|
27
|
+
current[k] = {};
|
|
28
|
+
}
|
|
29
|
+
current = current[k];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
current[keys[0]] = value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function deleteByPath(obj, pathStr) {
|
|
36
|
+
const keys = pathStr.split(".");
|
|
37
|
+
let current = obj;
|
|
38
|
+
|
|
39
|
+
while (keys.length > 1) {
|
|
40
|
+
const k = keys.shift();
|
|
41
|
+
if (!current[k]) return;
|
|
42
|
+
current = current[k];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
delete current[keys[0]];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
getByPath,
|
|
50
|
+
setByPath,
|
|
51
|
+
deleteByPath
|
|
52
52
|
};
|
|
@@ -1,248 +1,248 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dot Notation Parser - For nested object access 🔍
|
|
3
|
-
*
|
|
4
|
-
* Turns user.profile.name into actual value
|
|
5
|
-
* Because brackets are so 2010 😄
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
class DotNotation {
|
|
9
|
-
/**
|
|
10
|
-
* Get value using dot notation
|
|
11
|
-
*/
|
|
12
|
-
static get(obj, path, defaultValue = undefined) {
|
|
13
|
-
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
14
|
-
return defaultValue;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const keys = path.split('.');
|
|
18
|
-
let current = obj;
|
|
19
|
-
|
|
20
|
-
for (const key of keys) {
|
|
21
|
-
if (current === null || current === undefined) {
|
|
22
|
-
return defaultValue;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Handle array indices
|
|
26
|
-
if (Array.isArray(current) && !isNaN(key)) {
|
|
27
|
-
current = current[parseInt(key)];
|
|
28
|
-
} else if (this.isObject(current)) {
|
|
29
|
-
current = current[key];
|
|
30
|
-
} else {
|
|
31
|
-
return defaultValue;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return current !== undefined ? current : defaultValue;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Set value using dot notation
|
|
40
|
-
*/
|
|
41
|
-
static set(obj, path, value) {
|
|
42
|
-
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const keys = path.split('.');
|
|
47
|
-
let current = obj;
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
50
|
-
const key = keys[i];
|
|
51
|
-
const nextKey = keys[i + 1];
|
|
52
|
-
|
|
53
|
-
// Create nested objects if they don't exist
|
|
54
|
-
if (current[key] === undefined || current[key] === null) {
|
|
55
|
-
// Check if next key is numeric (array)
|
|
56
|
-
current[key] = !isNaN(nextKey) ? [] : {};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
current = current[key];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const lastKey = keys[keys.length - 1];
|
|
63
|
-
|
|
64
|
-
// Handle array indices
|
|
65
|
-
if (Array.isArray(current) && !isNaN(lastKey)) {
|
|
66
|
-
const index = parseInt(lastKey);
|
|
67
|
-
current[index] = value;
|
|
68
|
-
} else {
|
|
69
|
-
current[lastKey] = value;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Check if path exists
|
|
77
|
-
*/
|
|
78
|
-
static has(obj, path) {
|
|
79
|
-
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const keys = path.split('.');
|
|
84
|
-
let current = obj;
|
|
85
|
-
|
|
86
|
-
for (const key of keys) {
|
|
87
|
-
if (current === null || current === undefined) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (Array.isArray(current) && !isNaN(key)) {
|
|
92
|
-
const index = parseInt(key);
|
|
93
|
-
if (index < 0 || index >= current.length) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
current = current[index];
|
|
97
|
-
} else if (this.isObject(current)) {
|
|
98
|
-
if (!current.hasOwnProperty(key)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
current = current[key];
|
|
102
|
-
} else {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Delete value using dot notation
|
|
112
|
-
*/
|
|
113
|
-
static delete(obj, path) {
|
|
114
|
-
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const keys = path.split('.');
|
|
119
|
-
let current = obj;
|
|
120
|
-
|
|
121
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
122
|
-
const key = keys[i];
|
|
123
|
-
|
|
124
|
-
if (current[key] === undefined || current[key] === null) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
current = current[key];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const lastKey = keys[keys.length - 1];
|
|
132
|
-
|
|
133
|
-
if (Array.isArray(current) && !isNaN(lastKey)) {
|
|
134
|
-
const index = parseInt(lastKey);
|
|
135
|
-
if (index >= 0 && index < current.length) {
|
|
136
|
-
current.splice(index, 1);
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
} else if (this.isObject(current)) {
|
|
140
|
-
if (current.hasOwnProperty(lastKey)) {
|
|
141
|
-
delete current[lastKey];
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Get all paths in an object
|
|
151
|
-
*/
|
|
152
|
-
static getAllPaths(obj, prefix = '') {
|
|
153
|
-
if (!this.isObject(obj)) return [];
|
|
154
|
-
|
|
155
|
-
const paths = [];
|
|
156
|
-
|
|
157
|
-
for (const key in obj) {
|
|
158
|
-
if (obj.hasOwnProperty(key)) {
|
|
159
|
-
const currentPath = prefix ? `${prefix}.${key}` : key;
|
|
160
|
-
const value = obj[key];
|
|
161
|
-
|
|
162
|
-
if (this.isObject(value) && !Array.isArray(value)) {
|
|
163
|
-
// Recursively get paths for nested objects
|
|
164
|
-
paths.push(...this.getAllPaths(value, currentPath));
|
|
165
|
-
} else if (Array.isArray(value)) {
|
|
166
|
-
// Handle arrays - include index paths
|
|
167
|
-
paths.push(currentPath);
|
|
168
|
-
for (let i = 0; i < value.length; i++) {
|
|
169
|
-
const arrayPath = `${currentPath}.${i}`;
|
|
170
|
-
if (this.isObject(value[i])) {
|
|
171
|
-
paths.push(...this.getAllPaths(value[i], arrayPath));
|
|
172
|
-
} else {
|
|
173
|
-
paths.push(arrayPath);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
paths.push(currentPath);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return paths;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Flatten object using dot notation
|
|
187
|
-
*/
|
|
188
|
-
static flatten(obj) {
|
|
189
|
-
const result = {};
|
|
190
|
-
|
|
191
|
-
function flattenHelper(current, path) {
|
|
192
|
-
if (DotNotation.isObject(current) && !Array.isArray(current)) {
|
|
193
|
-
for (const key in current) {
|
|
194
|
-
if (current.hasOwnProperty(key)) {
|
|
195
|
-
const newPath = path ? `${path}.${key}` : key;
|
|
196
|
-
flattenHelper(current[key], newPath);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
} else if (Array.isArray(current)) {
|
|
200
|
-
for (let i = 0; i < current.length; i++) {
|
|
201
|
-
const newPath = `${path}.${i}`;
|
|
202
|
-
flattenHelper(current[i], newPath);
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
result[path] = current;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
flattenHelper(obj, '');
|
|
210
|
-
return result;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Unflatten object (reverse of flatten)
|
|
215
|
-
*/
|
|
216
|
-
static unflatten(flatObj) {
|
|
217
|
-
const result = {};
|
|
218
|
-
|
|
219
|
-
for (const path in flatObj) {
|
|
220
|
-
if (flatObj.hasOwnProperty(path)) {
|
|
221
|
-
this.set(result, path, flatObj[path]);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return result;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Check if value is an object
|
|
230
|
-
*/
|
|
231
|
-
static isObject(value) {
|
|
232
|
-
return value !== null && typeof value === 'object';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Parse path into keys array
|
|
237
|
-
*/
|
|
238
|
-
static parsePath(path) {
|
|
239
|
-
if (typeof path !== 'string') return [];
|
|
240
|
-
|
|
241
|
-
// Handle array indices and nested objects
|
|
242
|
-
return path.split('.').map(key => {
|
|
243
|
-
return !isNaN(key) ? parseInt(key) : key;
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Dot Notation Parser - For nested object access 🔍
|
|
3
|
+
*
|
|
4
|
+
* Turns user.profile.name into actual value
|
|
5
|
+
* Because brackets are so 2010 😄
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
class DotNotation {
|
|
9
|
+
/**
|
|
10
|
+
* Get value using dot notation
|
|
11
|
+
*/
|
|
12
|
+
static get(obj, path, defaultValue = undefined) {
|
|
13
|
+
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
14
|
+
return defaultValue;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const keys = path.split('.');
|
|
18
|
+
let current = obj;
|
|
19
|
+
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
if (current === null || current === undefined) {
|
|
22
|
+
return defaultValue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Handle array indices
|
|
26
|
+
if (Array.isArray(current) && !isNaN(key)) {
|
|
27
|
+
current = current[parseInt(key)];
|
|
28
|
+
} else if (this.isObject(current)) {
|
|
29
|
+
current = current[key];
|
|
30
|
+
} else {
|
|
31
|
+
return defaultValue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return current !== undefined ? current : defaultValue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Set value using dot notation
|
|
40
|
+
*/
|
|
41
|
+
static set(obj, path, value) {
|
|
42
|
+
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const keys = path.split('.');
|
|
47
|
+
let current = obj;
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
50
|
+
const key = keys[i];
|
|
51
|
+
const nextKey = keys[i + 1];
|
|
52
|
+
|
|
53
|
+
// Create nested objects if they don't exist
|
|
54
|
+
if (current[key] === undefined || current[key] === null) {
|
|
55
|
+
// Check if next key is numeric (array)
|
|
56
|
+
current[key] = !isNaN(nextKey) ? [] : {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
current = current[key];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const lastKey = keys[keys.length - 1];
|
|
63
|
+
|
|
64
|
+
// Handle array indices
|
|
65
|
+
if (Array.isArray(current) && !isNaN(lastKey)) {
|
|
66
|
+
const index = parseInt(lastKey);
|
|
67
|
+
current[index] = value;
|
|
68
|
+
} else {
|
|
69
|
+
current[lastKey] = value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if path exists
|
|
77
|
+
*/
|
|
78
|
+
static has(obj, path) {
|
|
79
|
+
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const keys = path.split('.');
|
|
84
|
+
let current = obj;
|
|
85
|
+
|
|
86
|
+
for (const key of keys) {
|
|
87
|
+
if (current === null || current === undefined) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (Array.isArray(current) && !isNaN(key)) {
|
|
92
|
+
const index = parseInt(key);
|
|
93
|
+
if (index < 0 || index >= current.length) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
current = current[index];
|
|
97
|
+
} else if (this.isObject(current)) {
|
|
98
|
+
if (!current.hasOwnProperty(key)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
current = current[key];
|
|
102
|
+
} else {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Delete value using dot notation
|
|
112
|
+
*/
|
|
113
|
+
static delete(obj, path) {
|
|
114
|
+
if (!this.isObject(obj) || typeof path !== 'string') {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const keys = path.split('.');
|
|
119
|
+
let current = obj;
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
122
|
+
const key = keys[i];
|
|
123
|
+
|
|
124
|
+
if (current[key] === undefined || current[key] === null) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
current = current[key];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const lastKey = keys[keys.length - 1];
|
|
132
|
+
|
|
133
|
+
if (Array.isArray(current) && !isNaN(lastKey)) {
|
|
134
|
+
const index = parseInt(lastKey);
|
|
135
|
+
if (index >= 0 && index < current.length) {
|
|
136
|
+
current.splice(index, 1);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
} else if (this.isObject(current)) {
|
|
140
|
+
if (current.hasOwnProperty(lastKey)) {
|
|
141
|
+
delete current[lastKey];
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get all paths in an object
|
|
151
|
+
*/
|
|
152
|
+
static getAllPaths(obj, prefix = '') {
|
|
153
|
+
if (!this.isObject(obj)) return [];
|
|
154
|
+
|
|
155
|
+
const paths = [];
|
|
156
|
+
|
|
157
|
+
for (const key in obj) {
|
|
158
|
+
if (obj.hasOwnProperty(key)) {
|
|
159
|
+
const currentPath = prefix ? `${prefix}.${key}` : key;
|
|
160
|
+
const value = obj[key];
|
|
161
|
+
|
|
162
|
+
if (this.isObject(value) && !Array.isArray(value)) {
|
|
163
|
+
// Recursively get paths for nested objects
|
|
164
|
+
paths.push(...this.getAllPaths(value, currentPath));
|
|
165
|
+
} else if (Array.isArray(value)) {
|
|
166
|
+
// Handle arrays - include index paths
|
|
167
|
+
paths.push(currentPath);
|
|
168
|
+
for (let i = 0; i < value.length; i++) {
|
|
169
|
+
const arrayPath = `${currentPath}.${i}`;
|
|
170
|
+
if (this.isObject(value[i])) {
|
|
171
|
+
paths.push(...this.getAllPaths(value[i], arrayPath));
|
|
172
|
+
} else {
|
|
173
|
+
paths.push(arrayPath);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
paths.push(currentPath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return paths;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Flatten object using dot notation
|
|
187
|
+
*/
|
|
188
|
+
static flatten(obj) {
|
|
189
|
+
const result = {};
|
|
190
|
+
|
|
191
|
+
function flattenHelper(current, path) {
|
|
192
|
+
if (DotNotation.isObject(current) && !Array.isArray(current)) {
|
|
193
|
+
for (const key in current) {
|
|
194
|
+
if (current.hasOwnProperty(key)) {
|
|
195
|
+
const newPath = path ? `${path}.${key}` : key;
|
|
196
|
+
flattenHelper(current[key], newPath);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} else if (Array.isArray(current)) {
|
|
200
|
+
for (let i = 0; i < current.length; i++) {
|
|
201
|
+
const newPath = `${path}.${i}`;
|
|
202
|
+
flattenHelper(current[i], newPath);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
result[path] = current;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
flattenHelper(obj, '');
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Unflatten object (reverse of flatten)
|
|
215
|
+
*/
|
|
216
|
+
static unflatten(flatObj) {
|
|
217
|
+
const result = {};
|
|
218
|
+
|
|
219
|
+
for (const path in flatObj) {
|
|
220
|
+
if (flatObj.hasOwnProperty(path)) {
|
|
221
|
+
this.set(result, path, flatObj[path]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return result;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Check if value is an object
|
|
230
|
+
*/
|
|
231
|
+
static isObject(value) {
|
|
232
|
+
return value !== null && typeof value === 'object';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Parse path into keys array
|
|
237
|
+
*/
|
|
238
|
+
static parsePath(path) {
|
|
239
|
+
if (typeof path !== 'string') return [];
|
|
240
|
+
|
|
241
|
+
// Handle array indices and nested objects
|
|
242
|
+
return path.split('.').map(key => {
|
|
243
|
+
return !isNaN(key) ? parseInt(key) : key;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
248
|
module.exports = DotNotation;
|