simple-json-db-lite 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Simple JSON DB Lite
2
+
3
+ A lightweight JSON database with CRUD operations and pagination. This package allows you to use a JSON file as a simple database with collections and documents.
4
+
5
+ ## Features
6
+
7
+ - Simple API for CRUD operations
8
+ - Support for collections (similar to tables in SQL)
9
+ - Query filtering with `where` conditions
10
+ - Pagination support
11
+ - Sorting capabilities
12
+ - Works with ES modules, CommonJS, and TypeScript
13
+ - MIT licensed
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install simple-json-db-lite
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### ES Modules
24
+
25
+ ```javascript
26
+ import { JsonDB } from 'simple-json-db-lite';
27
+
28
+ const db = new JsonDB('./data/database.json');
29
+ ```
30
+
31
+ ### CommonJS
32
+
33
+ ```javascript
34
+ const { JsonDB } = require('simple-json-db-lite');
35
+
36
+ const db = new JsonDB('./data/database.json');
37
+ ```
38
+
39
+ ### Basic Operations
40
+
41
+ ```javascript
42
+ // Create a collection (if it doesn't exist)
43
+ db.createCollection('users');
44
+
45
+ // Insert a document
46
+ const user = db.insert('users', {
47
+ name: 'John Doe',
48
+ email: 'john@example.com',
49
+ age: 30
50
+ });
51
+ console.log(user.id); // Automatically generated ID
52
+
53
+ // Find documents
54
+ const allUsers = db.find('users');
55
+ const youngUsers = db.find('users', {
56
+ where: { age: 30 }
57
+ });
58
+
59
+ // Find by ID
60
+ const john = db.findById('users', user.id);
61
+
62
+ // Update documents
63
+ const updatedCount = db.update('users',
64
+ { status: 'active' },
65
+ { where: { age: 30 } }
66
+ );
67
+
68
+ // Delete documents
69
+ const deletedCount = db.delete('users', {
70
+ where: { status: 'inactive' }
71
+ });
72
+
73
+ // Delete by ID
74
+ const deleted = db.deleteById('users', user.id);
75
+
76
+ // Count documents
77
+ const totalUsers = db.count('users');
78
+ const activeUsers = db.count('users', { status: 'active' });
79
+ ```
80
+
81
+ ### Pagination
82
+
83
+ ```javascript
84
+ const { data, pagination } = db.paginate('users', 1, 10, { status: 'active' });
85
+
86
+ console.log(data); // Array of users for page 1
87
+ console.log(pagination);
88
+ // {
89
+ // total: 25,
90
+ // page: 1,
91
+ // pageSize: 10,
92
+ // totalPages: 3,
93
+ // hasNext: true,
94
+ // hasPrev: false
95
+ // }
96
+ ```
97
+
98
+ ### Sorting
99
+
100
+ ```javascript
101
+ const sortedUsers = db.find('users', {
102
+ orderBy: {
103
+ field: 'age',
104
+ direction: 'desc'
105
+ }
106
+ });
107
+ ```
108
+
109
+ ## API Reference
110
+
111
+ ### Constructor
112
+
113
+ ```typescript
114
+ new JsonDB(filePath: string)
115
+ ```
116
+
117
+ ### Methods
118
+
119
+ - `createCollection(collectionName: string): void`
120
+ - `insert<T>(collectionName: string, document: T): T & { id: string }`
121
+ - `find<T>(collectionName: string, options?: QueryOptions): T[]`
122
+ - `findById<T>(collectionName: string, id: string): T | null`
123
+ - `update(collectionName: string, update: Record<string, any>, options?: UpdateOptions): number`
124
+ - `delete(collectionName: string, options?: DeleteOptions): number`
125
+ - `deleteById(collectionName: string, id: string): boolean`
126
+ - `count(collectionName: string, where?: Record<string, any>): number`
127
+ - `paginate<T>(collectionName: string, page?: number, pageSize?: number, where?: Record<string, any>): { data: T[], pagination: { ... } }`
128
+
129
+ ## Development
130
+
131
+ ```bash
132
+ # Install dependencies
133
+ npm install
134
+
135
+ # Run tests
136
+ npm test
137
+
138
+ # Build the package
139
+ npm run build
140
+ ```
141
+
142
+ ## License
143
+
144
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => {
5
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+ return value;
7
+ };
8
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ class JsonDB {
12
+ /**
13
+ * Initialize the JSON database
14
+ * @param filePath Path to the JSON file
15
+ */
16
+ constructor(filePath) {
17
+ __publicField(this, "filePath");
18
+ __publicField(this, "data", {});
19
+ this.filePath = path.resolve(filePath);
20
+ this.loadData();
21
+ }
22
+ /**
23
+ * Load data from the JSON file
24
+ * @private
25
+ */
26
+ loadData() {
27
+ try {
28
+ if (fs.existsSync(this.filePath)) {
29
+ const fileContent = fs.readFileSync(this.filePath, "utf-8");
30
+ this.data = JSON.parse(fileContent);
31
+ } else {
32
+ this.saveData();
33
+ }
34
+ } catch (error) {
35
+ throw new Error(
36
+ `Failed to load data: ${error instanceof Error ? error.message : String(error)}`
37
+ );
38
+ }
39
+ }
40
+ /**
41
+ * Save data to the JSON file
42
+ * @private
43
+ */
44
+ saveData() {
45
+ try {
46
+ const dirPath = path.dirname(this.filePath);
47
+ if (!fs.existsSync(dirPath)) {
48
+ fs.mkdirSync(dirPath, { recursive: true });
49
+ }
50
+ fs.writeFileSync(
51
+ this.filePath,
52
+ JSON.stringify(this.data, null, 2),
53
+ "utf-8"
54
+ );
55
+ } catch (error) {
56
+ throw new Error(
57
+ `Failed to save data: ${error instanceof Error ? error.message : String(error)}`
58
+ );
59
+ }
60
+ }
61
+ /**
62
+ * Create a collection if it doesn't exist
63
+ * @param collectionName Name of the collection
64
+ */
65
+ createCollection(collectionName) {
66
+ if (!this.data[collectionName]) {
67
+ this.data[collectionName] = [];
68
+ this.saveData();
69
+ }
70
+ }
71
+ /**
72
+ * Insert a document into a collection
73
+ * @param collectionName Name of the collection
74
+ * @param document Document to insert
75
+ * @returns The inserted document with ID
76
+ */
77
+ insert(collectionName, document) {
78
+ this.createCollection(collectionName);
79
+ const id = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).substring(2);
80
+ const newDocument = { ...document, id };
81
+ this.data[collectionName].push(newDocument);
82
+ this.saveData();
83
+ return newDocument;
84
+ }
85
+ /**
86
+ * Find documents in a collection
87
+ * @param collectionName Name of the collection
88
+ * @param options Query options
89
+ * @returns Array of matching documents
90
+ */
91
+ find(collectionName, options = {}) {
92
+ if (!this.data[collectionName]) {
93
+ return [];
94
+ }
95
+ let result = [...this.data[collectionName]];
96
+ if (options.where) {
97
+ result = result.filter(
98
+ (item) => Object.entries(options.where || {}).every(
99
+ ([key, value]) => item[key] === value
100
+ )
101
+ );
102
+ }
103
+ if (options.orderBy) {
104
+ const { field, direction } = options.orderBy;
105
+ result.sort((a, b) => {
106
+ const valueA = a[field];
107
+ const valueB = b[field];
108
+ if (valueA < valueB)
109
+ return direction === "asc" ? -1 : 1;
110
+ if (valueA > valueB)
111
+ return direction === "asc" ? 1 : -1;
112
+ return 0;
113
+ });
114
+ }
115
+ if (options.offset !== void 0) {
116
+ result = result.slice(options.offset);
117
+ }
118
+ if (options.limit !== void 0) {
119
+ result = result.slice(0, options.limit);
120
+ }
121
+ return result;
122
+ }
123
+ /**
124
+ * Find a single document by ID
125
+ * @param collectionName Name of the collection
126
+ * @param id Document ID
127
+ * @returns The document or null if not found
128
+ */
129
+ findById(collectionName, id) {
130
+ if (!this.data[collectionName]) {
131
+ return null;
132
+ }
133
+ const document = this.data[collectionName].find((item) => item.id === id);
134
+ return document ? document : null;
135
+ }
136
+ /**
137
+ * Update documents in a collection
138
+ * @param collectionName Name of the collection
139
+ * @param update Update object
140
+ * @param options Update options
141
+ * @returns Number of updated documents
142
+ */
143
+ update(collectionName, update, options = {}) {
144
+ if (!this.data[collectionName]) {
145
+ return 0;
146
+ }
147
+ let updatedCount = 0;
148
+ this.data[collectionName] = this.data[collectionName].map((item) => {
149
+ if (options.where && !Object.entries(options.where).every(
150
+ ([key, value]) => item[key] === value
151
+ )) {
152
+ return item;
153
+ }
154
+ updatedCount++;
155
+ return { ...item, ...update };
156
+ });
157
+ if (updatedCount > 0) {
158
+ this.saveData();
159
+ }
160
+ return updatedCount;
161
+ }
162
+ /**
163
+ * Delete documents from a collection
164
+ * @param collectionName Name of the collection
165
+ * @param options Delete options
166
+ * @returns Number of deleted documents
167
+ */
168
+ delete(collectionName, options = {}) {
169
+ if (!this.data[collectionName]) {
170
+ return 0;
171
+ }
172
+ const originalLength = this.data[collectionName].length;
173
+ if (options.where) {
174
+ this.data[collectionName] = this.data[collectionName].filter(
175
+ (item) => !Object.entries(options.where || {}).every(
176
+ ([key, value]) => item[key] === value
177
+ )
178
+ );
179
+ } else {
180
+ this.data[collectionName] = [];
181
+ }
182
+ const deletedCount = originalLength - this.data[collectionName].length;
183
+ if (deletedCount > 0) {
184
+ this.saveData();
185
+ }
186
+ return deletedCount;
187
+ }
188
+ /**
189
+ * Delete a document by ID
190
+ * @param collectionName Name of the collection
191
+ * @param id Document ID
192
+ * @returns True if document was deleted, false otherwise
193
+ */
194
+ deleteById(collectionName, id) {
195
+ if (!this.data[collectionName]) {
196
+ return false;
197
+ }
198
+ const originalLength = this.data[collectionName].length;
199
+ this.data[collectionName] = this.data[collectionName].filter(
200
+ (item) => item.id !== id
201
+ );
202
+ const deleted = originalLength > this.data[collectionName].length;
203
+ if (deleted) {
204
+ this.saveData();
205
+ }
206
+ return deleted;
207
+ }
208
+ /**
209
+ * Count documents in a collection
210
+ * @param collectionName Name of the collection
211
+ * @param where Optional filter
212
+ * @returns Number of documents
213
+ */
214
+ count(collectionName, where) {
215
+ if (!this.data[collectionName]) {
216
+ return 0;
217
+ }
218
+ if (where) {
219
+ return this.data[collectionName].filter(
220
+ (item) => Object.entries(where).every(([key, value]) => item[key] === value)
221
+ ).length;
222
+ }
223
+ return this.data[collectionName].length;
224
+ }
225
+ /**
226
+ * Get pagination information
227
+ * @param collectionName Name of the collection
228
+ * @param page Page number (1-based)
229
+ * @param pageSize Number of items per page
230
+ * @param where Optional filter
231
+ * @returns Pagination information and data
232
+ */
233
+ paginate(collectionName, page = 1, pageSize = 10, where) {
234
+ const offset = (page - 1) * pageSize;
235
+ const total = this.count(collectionName, where);
236
+ const totalPages = Math.ceil(total / pageSize);
237
+ const data = this.find(collectionName, {
238
+ where,
239
+ limit: pageSize,
240
+ offset
241
+ });
242
+ return {
243
+ data,
244
+ pagination: {
245
+ total,
246
+ page,
247
+ pageSize,
248
+ totalPages,
249
+ hasNext: page < totalPages,
250
+ hasPrev: page > 1
251
+ }
252
+ };
253
+ }
254
+ }
255
+ exports.JsonDB = JsonDB;
256
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface QueryOptions {\r\n where?: Record<string, any>;\r\n limit?: number;\r\n offset?: number;\r\n orderBy?: {\r\n field: string;\r\n direction: \"asc\" | \"desc\";\r\n };\r\n}\r\n\r\nexport interface UpdateOptions {\r\n where?: Record<string, any>;\r\n}\r\n\r\nexport interface DeleteOptions {\r\n where?: Record<string, any>;\r\n}\r\n\r\nexport class JsonDB {\r\n private filePath: string;\r\n private data: Record<string, any[]> = {};\r\n\r\n /**\r\n * Initialize the JSON database\r\n * @param filePath Path to the JSON file\r\n */\r\n constructor(filePath: string) {\r\n this.filePath = path.resolve(filePath);\r\n this.loadData();\r\n }\r\n\r\n /**\r\n * Load data from the JSON file\r\n * @private\r\n */\r\n private loadData(): void {\r\n try {\r\n if (fs.existsSync(this.filePath)) {\r\n const fileContent = fs.readFileSync(this.filePath, \"utf-8\");\r\n this.data = JSON.parse(fileContent);\r\n } else {\r\n // Create the file if it doesn't exist\r\n this.saveData();\r\n }\r\n } catch (error) {\r\n throw new Error(\r\n `Failed to load data: ${\r\n error instanceof Error ? error.message : String(error)\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Save data to the JSON file\r\n * @private\r\n */\r\n private saveData(): void {\r\n try {\r\n const dirPath = path.dirname(this.filePath);\r\n\r\n // Create directory if it doesn't exist\r\n if (!fs.existsSync(dirPath)) {\r\n fs.mkdirSync(dirPath, { recursive: true });\r\n }\r\n\r\n fs.writeFileSync(\r\n this.filePath,\r\n JSON.stringify(this.data, null, 2),\r\n \"utf-8\"\r\n );\r\n } catch (error) {\r\n throw new Error(\r\n `Failed to save data: ${\r\n error instanceof Error ? error.message : String(error)\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Create a collection if it doesn't exist\r\n * @param collectionName Name of the collection\r\n */\r\n public createCollection(collectionName: string): void {\r\n if (!this.data[collectionName]) {\r\n this.data[collectionName] = [];\r\n this.saveData();\r\n }\r\n }\r\n\r\n /**\r\n * Insert a document into a collection\r\n * @param collectionName Name of the collection\r\n * @param document Document to insert\r\n * @returns The inserted document with ID\r\n */\r\n public insert<T extends Record<string, any>>(\r\n collectionName: string,\r\n document: T\r\n ): T & { id: string } {\r\n this.createCollection(collectionName);\r\n\r\n const id = crypto.randomUUID\r\n ? crypto.randomUUID()\r\n : Date.now().toString(36) + Math.random().toString(36).substring(2);\r\n const newDocument = { ...document, id };\r\n\r\n this.data[collectionName].push(newDocument);\r\n this.saveData();\r\n\r\n return newDocument as T & { id: string };\r\n }\r\n\r\n /**\r\n * Find documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param options Query options\r\n * @returns Array of matching documents\r\n */\r\n public find<T>(collectionName: string, options: QueryOptions = {}): T[] {\r\n if (!this.data[collectionName]) {\r\n return [];\r\n }\r\n\r\n let result = [...this.data[collectionName]] as T[];\r\n\r\n // Apply where filter\r\n if (options.where) {\r\n result = result.filter((item) =>\r\n Object.entries(options.where || {}).every(\r\n ([key, value]) => item[key as keyof T] === value\r\n )\r\n );\r\n }\r\n\r\n // Apply orderBy\r\n if (options.orderBy) {\r\n const { field, direction } = options.orderBy;\r\n result.sort((a, b) => {\r\n const valueA = a[field as keyof T];\r\n const valueB = b[field as keyof T];\r\n\r\n if (valueA < valueB) return direction === \"asc\" ? -1 : 1;\r\n if (valueA > valueB) return direction === \"asc\" ? 1 : -1;\r\n return 0;\r\n });\r\n }\r\n\r\n // Apply pagination\r\n if (options.offset !== undefined) {\r\n result = result.slice(options.offset);\r\n }\r\n\r\n if (options.limit !== undefined) {\r\n result = result.slice(0, options.limit);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Find a single document by ID\r\n * @param collectionName Name of the collection\r\n * @param id Document ID\r\n * @returns The document or null if not found\r\n */\r\n public findById<T>(collectionName: string, id: string): T | null {\r\n if (!this.data[collectionName]) {\r\n return null;\r\n }\r\n\r\n const document = this.data[collectionName].find((item) => item.id === id);\r\n return document ? (document as T) : null;\r\n }\r\n\r\n /**\r\n * Update documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param update Update object\r\n * @param options Update options\r\n * @returns Number of updated documents\r\n */\r\n public update(\r\n collectionName: string,\r\n update: Record<string, any>,\r\n options: UpdateOptions = {}\r\n ): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n let updatedCount = 0;\r\n\r\n this.data[collectionName] = this.data[collectionName].map((item) => {\r\n // Check if the item matches the where condition\r\n if (\r\n options.where &&\r\n !Object.entries(options.where).every(\r\n ([key, value]) => item[key] === value\r\n )\r\n ) {\r\n return item;\r\n }\r\n\r\n updatedCount++;\r\n return { ...item, ...update };\r\n });\r\n\r\n if (updatedCount > 0) {\r\n this.saveData();\r\n }\r\n\r\n return updatedCount;\r\n }\r\n\r\n /**\r\n * Delete documents from a collection\r\n * @param collectionName Name of the collection\r\n * @param options Delete options\r\n * @returns Number of deleted documents\r\n */\r\n public delete(collectionName: string, options: DeleteOptions = {}): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n const originalLength = this.data[collectionName].length;\r\n\r\n if (options.where) {\r\n this.data[collectionName] = this.data[collectionName].filter(\r\n (item) =>\r\n !Object.entries(options.where || {}).every(\r\n ([key, value]) => item[key] === value\r\n )\r\n );\r\n } else {\r\n // Delete all documents if no where clause\r\n this.data[collectionName] = [];\r\n }\r\n\r\n const deletedCount = originalLength - this.data[collectionName].length;\r\n\r\n if (deletedCount > 0) {\r\n this.saveData();\r\n }\r\n\r\n return deletedCount;\r\n }\r\n\r\n /**\r\n * Delete a document by ID\r\n * @param collectionName Name of the collection\r\n * @param id Document ID\r\n * @returns True if document was deleted, false otherwise\r\n */\r\n public deleteById(collectionName: string, id: string): boolean {\r\n if (!this.data[collectionName]) {\r\n return false;\r\n }\r\n\r\n const originalLength = this.data[collectionName].length;\r\n this.data[collectionName] = this.data[collectionName].filter(\r\n (item) => item.id !== id\r\n );\r\n\r\n const deleted = originalLength > this.data[collectionName].length;\r\n\r\n if (deleted) {\r\n this.saveData();\r\n }\r\n\r\n return deleted;\r\n }\r\n\r\n /**\r\n * Count documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param where Optional filter\r\n * @returns Number of documents\r\n */\r\n public count(collectionName: string, where?: Record<string, any>): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n if (where) {\r\n return this.data[collectionName].filter((item) =>\r\n Object.entries(where).every(([key, value]) => item[key] === value)\r\n ).length;\r\n }\r\n\r\n return this.data[collectionName].length;\r\n }\r\n\r\n /**\r\n * Get pagination information\r\n * @param collectionName Name of the collection\r\n * @param page Page number (1-based)\r\n * @param pageSize Number of items per page\r\n * @param where Optional filter\r\n * @returns Pagination information and data\r\n */\r\n public paginate<T>(\r\n collectionName: string,\r\n page = 1,\r\n pageSize = 10,\r\n where?: Record<string, any>\r\n ): {\r\n data: T[];\r\n pagination: {\r\n total: number;\r\n page: number;\r\n pageSize: number;\r\n totalPages: number;\r\n hasNext: boolean;\r\n hasPrev: boolean;\r\n };\r\n } {\r\n const offset = (page - 1) * pageSize;\r\n const total = this.count(collectionName, where);\r\n const totalPages = Math.ceil(total / pageSize);\r\n\r\n const data = this.find<T>(collectionName, {\r\n where,\r\n limit: pageSize,\r\n offset,\r\n });\r\n\r\n return {\r\n data,\r\n pagination: {\r\n total,\r\n page,\r\n pageSize,\r\n totalPages,\r\n hasNext: page < totalPages,\r\n hasPrev: page > 1,\r\n },\r\n };\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ export interface QueryOptions {
2
+ where?: Record<string, any>;
3
+ limit?: number;
4
+ offset?: number;
5
+ orderBy?: {
6
+ field: string;
7
+ direction: "asc" | "desc";
8
+ };
9
+ }
10
+ export interface UpdateOptions {
11
+ where?: Record<string, any>;
12
+ }
13
+ export interface DeleteOptions {
14
+ where?: Record<string, any>;
15
+ }
16
+ export declare class JsonDB {
17
+ private filePath;
18
+ private data;
19
+ /**
20
+ * Initialize the JSON database
21
+ * @param filePath Path to the JSON file
22
+ */
23
+ constructor(filePath: string);
24
+ /**
25
+ * Load data from the JSON file
26
+ * @private
27
+ */
28
+ private loadData;
29
+ /**
30
+ * Save data to the JSON file
31
+ * @private
32
+ */
33
+ private saveData;
34
+ /**
35
+ * Create a collection if it doesn't exist
36
+ * @param collectionName Name of the collection
37
+ */
38
+ createCollection(collectionName: string): void;
39
+ /**
40
+ * Insert a document into a collection
41
+ * @param collectionName Name of the collection
42
+ * @param document Document to insert
43
+ * @returns The inserted document with ID
44
+ */
45
+ insert<T extends Record<string, any>>(collectionName: string, document: T): T & {
46
+ id: string;
47
+ };
48
+ /**
49
+ * Find documents in a collection
50
+ * @param collectionName Name of the collection
51
+ * @param options Query options
52
+ * @returns Array of matching documents
53
+ */
54
+ find<T>(collectionName: string, options?: QueryOptions): T[];
55
+ /**
56
+ * Find a single document by ID
57
+ * @param collectionName Name of the collection
58
+ * @param id Document ID
59
+ * @returns The document or null if not found
60
+ */
61
+ findById<T>(collectionName: string, id: string): T | null;
62
+ /**
63
+ * Update documents in a collection
64
+ * @param collectionName Name of the collection
65
+ * @param update Update object
66
+ * @param options Update options
67
+ * @returns Number of updated documents
68
+ */
69
+ update(collectionName: string, update: Record<string, any>, options?: UpdateOptions): number;
70
+ /**
71
+ * Delete documents from a collection
72
+ * @param collectionName Name of the collection
73
+ * @param options Delete options
74
+ * @returns Number of deleted documents
75
+ */
76
+ delete(collectionName: string, options?: DeleteOptions): number;
77
+ /**
78
+ * Delete a document by ID
79
+ * @param collectionName Name of the collection
80
+ * @param id Document ID
81
+ * @returns True if document was deleted, false otherwise
82
+ */
83
+ deleteById(collectionName: string, id: string): boolean;
84
+ /**
85
+ * Count documents in a collection
86
+ * @param collectionName Name of the collection
87
+ * @param where Optional filter
88
+ * @returns Number of documents
89
+ */
90
+ count(collectionName: string, where?: Record<string, any>): number;
91
+ /**
92
+ * Get pagination information
93
+ * @param collectionName Name of the collection
94
+ * @param page Page number (1-based)
95
+ * @param pageSize Number of items per page
96
+ * @param where Optional filter
97
+ * @returns Pagination information and data
98
+ */
99
+ paginate<T>(collectionName: string, page?: number, pageSize?: number, where?: Record<string, any>): {
100
+ data: T[];
101
+ pagination: {
102
+ total: number;
103
+ page: number;
104
+ pageSize: number;
105
+ totalPages: number;
106
+ hasNext: boolean;
107
+ hasPrev: boolean;
108
+ };
109
+ };
110
+ }
package/dist/index.js ADDED
@@ -0,0 +1,256 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import fs from "fs";
8
+ import path from "path";
9
+ class JsonDB {
10
+ /**
11
+ * Initialize the JSON database
12
+ * @param filePath Path to the JSON file
13
+ */
14
+ constructor(filePath) {
15
+ __publicField(this, "filePath");
16
+ __publicField(this, "data", {});
17
+ this.filePath = path.resolve(filePath);
18
+ this.loadData();
19
+ }
20
+ /**
21
+ * Load data from the JSON file
22
+ * @private
23
+ */
24
+ loadData() {
25
+ try {
26
+ if (fs.existsSync(this.filePath)) {
27
+ const fileContent = fs.readFileSync(this.filePath, "utf-8");
28
+ this.data = JSON.parse(fileContent);
29
+ } else {
30
+ this.saveData();
31
+ }
32
+ } catch (error) {
33
+ throw new Error(
34
+ `Failed to load data: ${error instanceof Error ? error.message : String(error)}`
35
+ );
36
+ }
37
+ }
38
+ /**
39
+ * Save data to the JSON file
40
+ * @private
41
+ */
42
+ saveData() {
43
+ try {
44
+ const dirPath = path.dirname(this.filePath);
45
+ if (!fs.existsSync(dirPath)) {
46
+ fs.mkdirSync(dirPath, { recursive: true });
47
+ }
48
+ fs.writeFileSync(
49
+ this.filePath,
50
+ JSON.stringify(this.data, null, 2),
51
+ "utf-8"
52
+ );
53
+ } catch (error) {
54
+ throw new Error(
55
+ `Failed to save data: ${error instanceof Error ? error.message : String(error)}`
56
+ );
57
+ }
58
+ }
59
+ /**
60
+ * Create a collection if it doesn't exist
61
+ * @param collectionName Name of the collection
62
+ */
63
+ createCollection(collectionName) {
64
+ if (!this.data[collectionName]) {
65
+ this.data[collectionName] = [];
66
+ this.saveData();
67
+ }
68
+ }
69
+ /**
70
+ * Insert a document into a collection
71
+ * @param collectionName Name of the collection
72
+ * @param document Document to insert
73
+ * @returns The inserted document with ID
74
+ */
75
+ insert(collectionName, document) {
76
+ this.createCollection(collectionName);
77
+ const id = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).substring(2);
78
+ const newDocument = { ...document, id };
79
+ this.data[collectionName].push(newDocument);
80
+ this.saveData();
81
+ return newDocument;
82
+ }
83
+ /**
84
+ * Find documents in a collection
85
+ * @param collectionName Name of the collection
86
+ * @param options Query options
87
+ * @returns Array of matching documents
88
+ */
89
+ find(collectionName, options = {}) {
90
+ if (!this.data[collectionName]) {
91
+ return [];
92
+ }
93
+ let result = [...this.data[collectionName]];
94
+ if (options.where) {
95
+ result = result.filter(
96
+ (item) => Object.entries(options.where || {}).every(
97
+ ([key, value]) => item[key] === value
98
+ )
99
+ );
100
+ }
101
+ if (options.orderBy) {
102
+ const { field, direction } = options.orderBy;
103
+ result.sort((a, b) => {
104
+ const valueA = a[field];
105
+ const valueB = b[field];
106
+ if (valueA < valueB)
107
+ return direction === "asc" ? -1 : 1;
108
+ if (valueA > valueB)
109
+ return direction === "asc" ? 1 : -1;
110
+ return 0;
111
+ });
112
+ }
113
+ if (options.offset !== void 0) {
114
+ result = result.slice(options.offset);
115
+ }
116
+ if (options.limit !== void 0) {
117
+ result = result.slice(0, options.limit);
118
+ }
119
+ return result;
120
+ }
121
+ /**
122
+ * Find a single document by ID
123
+ * @param collectionName Name of the collection
124
+ * @param id Document ID
125
+ * @returns The document or null if not found
126
+ */
127
+ findById(collectionName, id) {
128
+ if (!this.data[collectionName]) {
129
+ return null;
130
+ }
131
+ const document = this.data[collectionName].find((item) => item.id === id);
132
+ return document ? document : null;
133
+ }
134
+ /**
135
+ * Update documents in a collection
136
+ * @param collectionName Name of the collection
137
+ * @param update Update object
138
+ * @param options Update options
139
+ * @returns Number of updated documents
140
+ */
141
+ update(collectionName, update, options = {}) {
142
+ if (!this.data[collectionName]) {
143
+ return 0;
144
+ }
145
+ let updatedCount = 0;
146
+ this.data[collectionName] = this.data[collectionName].map((item) => {
147
+ if (options.where && !Object.entries(options.where).every(
148
+ ([key, value]) => item[key] === value
149
+ )) {
150
+ return item;
151
+ }
152
+ updatedCount++;
153
+ return { ...item, ...update };
154
+ });
155
+ if (updatedCount > 0) {
156
+ this.saveData();
157
+ }
158
+ return updatedCount;
159
+ }
160
+ /**
161
+ * Delete documents from a collection
162
+ * @param collectionName Name of the collection
163
+ * @param options Delete options
164
+ * @returns Number of deleted documents
165
+ */
166
+ delete(collectionName, options = {}) {
167
+ if (!this.data[collectionName]) {
168
+ return 0;
169
+ }
170
+ const originalLength = this.data[collectionName].length;
171
+ if (options.where) {
172
+ this.data[collectionName] = this.data[collectionName].filter(
173
+ (item) => !Object.entries(options.where || {}).every(
174
+ ([key, value]) => item[key] === value
175
+ )
176
+ );
177
+ } else {
178
+ this.data[collectionName] = [];
179
+ }
180
+ const deletedCount = originalLength - this.data[collectionName].length;
181
+ if (deletedCount > 0) {
182
+ this.saveData();
183
+ }
184
+ return deletedCount;
185
+ }
186
+ /**
187
+ * Delete a document by ID
188
+ * @param collectionName Name of the collection
189
+ * @param id Document ID
190
+ * @returns True if document was deleted, false otherwise
191
+ */
192
+ deleteById(collectionName, id) {
193
+ if (!this.data[collectionName]) {
194
+ return false;
195
+ }
196
+ const originalLength = this.data[collectionName].length;
197
+ this.data[collectionName] = this.data[collectionName].filter(
198
+ (item) => item.id !== id
199
+ );
200
+ const deleted = originalLength > this.data[collectionName].length;
201
+ if (deleted) {
202
+ this.saveData();
203
+ }
204
+ return deleted;
205
+ }
206
+ /**
207
+ * Count documents in a collection
208
+ * @param collectionName Name of the collection
209
+ * @param where Optional filter
210
+ * @returns Number of documents
211
+ */
212
+ count(collectionName, where) {
213
+ if (!this.data[collectionName]) {
214
+ return 0;
215
+ }
216
+ if (where) {
217
+ return this.data[collectionName].filter(
218
+ (item) => Object.entries(where).every(([key, value]) => item[key] === value)
219
+ ).length;
220
+ }
221
+ return this.data[collectionName].length;
222
+ }
223
+ /**
224
+ * Get pagination information
225
+ * @param collectionName Name of the collection
226
+ * @param page Page number (1-based)
227
+ * @param pageSize Number of items per page
228
+ * @param where Optional filter
229
+ * @returns Pagination information and data
230
+ */
231
+ paginate(collectionName, page = 1, pageSize = 10, where) {
232
+ const offset = (page - 1) * pageSize;
233
+ const total = this.count(collectionName, where);
234
+ const totalPages = Math.ceil(total / pageSize);
235
+ const data = this.find(collectionName, {
236
+ where,
237
+ limit: pageSize,
238
+ offset
239
+ });
240
+ return {
241
+ data,
242
+ pagination: {
243
+ total,
244
+ page,
245
+ pageSize,
246
+ totalPages,
247
+ hasNext: page < totalPages,
248
+ hasPrev: page > 1
249
+ }
250
+ };
251
+ }
252
+ }
253
+ export {
254
+ JsonDB
255
+ };
256
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface QueryOptions {\r\n where?: Record<string, any>;\r\n limit?: number;\r\n offset?: number;\r\n orderBy?: {\r\n field: string;\r\n direction: \"asc\" | \"desc\";\r\n };\r\n}\r\n\r\nexport interface UpdateOptions {\r\n where?: Record<string, any>;\r\n}\r\n\r\nexport interface DeleteOptions {\r\n where?: Record<string, any>;\r\n}\r\n\r\nexport class JsonDB {\r\n private filePath: string;\r\n private data: Record<string, any[]> = {};\r\n\r\n /**\r\n * Initialize the JSON database\r\n * @param filePath Path to the JSON file\r\n */\r\n constructor(filePath: string) {\r\n this.filePath = path.resolve(filePath);\r\n this.loadData();\r\n }\r\n\r\n /**\r\n * Load data from the JSON file\r\n * @private\r\n */\r\n private loadData(): void {\r\n try {\r\n if (fs.existsSync(this.filePath)) {\r\n const fileContent = fs.readFileSync(this.filePath, \"utf-8\");\r\n this.data = JSON.parse(fileContent);\r\n } else {\r\n // Create the file if it doesn't exist\r\n this.saveData();\r\n }\r\n } catch (error) {\r\n throw new Error(\r\n `Failed to load data: ${\r\n error instanceof Error ? error.message : String(error)\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Save data to the JSON file\r\n * @private\r\n */\r\n private saveData(): void {\r\n try {\r\n const dirPath = path.dirname(this.filePath);\r\n\r\n // Create directory if it doesn't exist\r\n if (!fs.existsSync(dirPath)) {\r\n fs.mkdirSync(dirPath, { recursive: true });\r\n }\r\n\r\n fs.writeFileSync(\r\n this.filePath,\r\n JSON.stringify(this.data, null, 2),\r\n \"utf-8\"\r\n );\r\n } catch (error) {\r\n throw new Error(\r\n `Failed to save data: ${\r\n error instanceof Error ? error.message : String(error)\r\n }`\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Create a collection if it doesn't exist\r\n * @param collectionName Name of the collection\r\n */\r\n public createCollection(collectionName: string): void {\r\n if (!this.data[collectionName]) {\r\n this.data[collectionName] = [];\r\n this.saveData();\r\n }\r\n }\r\n\r\n /**\r\n * Insert a document into a collection\r\n * @param collectionName Name of the collection\r\n * @param document Document to insert\r\n * @returns The inserted document with ID\r\n */\r\n public insert<T extends Record<string, any>>(\r\n collectionName: string,\r\n document: T\r\n ): T & { id: string } {\r\n this.createCollection(collectionName);\r\n\r\n const id = crypto.randomUUID\r\n ? crypto.randomUUID()\r\n : Date.now().toString(36) + Math.random().toString(36).substring(2);\r\n const newDocument = { ...document, id };\r\n\r\n this.data[collectionName].push(newDocument);\r\n this.saveData();\r\n\r\n return newDocument as T & { id: string };\r\n }\r\n\r\n /**\r\n * Find documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param options Query options\r\n * @returns Array of matching documents\r\n */\r\n public find<T>(collectionName: string, options: QueryOptions = {}): T[] {\r\n if (!this.data[collectionName]) {\r\n return [];\r\n }\r\n\r\n let result = [...this.data[collectionName]] as T[];\r\n\r\n // Apply where filter\r\n if (options.where) {\r\n result = result.filter((item) =>\r\n Object.entries(options.where || {}).every(\r\n ([key, value]) => item[key as keyof T] === value\r\n )\r\n );\r\n }\r\n\r\n // Apply orderBy\r\n if (options.orderBy) {\r\n const { field, direction } = options.orderBy;\r\n result.sort((a, b) => {\r\n const valueA = a[field as keyof T];\r\n const valueB = b[field as keyof T];\r\n\r\n if (valueA < valueB) return direction === \"asc\" ? -1 : 1;\r\n if (valueA > valueB) return direction === \"asc\" ? 1 : -1;\r\n return 0;\r\n });\r\n }\r\n\r\n // Apply pagination\r\n if (options.offset !== undefined) {\r\n result = result.slice(options.offset);\r\n }\r\n\r\n if (options.limit !== undefined) {\r\n result = result.slice(0, options.limit);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Find a single document by ID\r\n * @param collectionName Name of the collection\r\n * @param id Document ID\r\n * @returns The document or null if not found\r\n */\r\n public findById<T>(collectionName: string, id: string): T | null {\r\n if (!this.data[collectionName]) {\r\n return null;\r\n }\r\n\r\n const document = this.data[collectionName].find((item) => item.id === id);\r\n return document ? (document as T) : null;\r\n }\r\n\r\n /**\r\n * Update documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param update Update object\r\n * @param options Update options\r\n * @returns Number of updated documents\r\n */\r\n public update(\r\n collectionName: string,\r\n update: Record<string, any>,\r\n options: UpdateOptions = {}\r\n ): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n let updatedCount = 0;\r\n\r\n this.data[collectionName] = this.data[collectionName].map((item) => {\r\n // Check if the item matches the where condition\r\n if (\r\n options.where &&\r\n !Object.entries(options.where).every(\r\n ([key, value]) => item[key] === value\r\n )\r\n ) {\r\n return item;\r\n }\r\n\r\n updatedCount++;\r\n return { ...item, ...update };\r\n });\r\n\r\n if (updatedCount > 0) {\r\n this.saveData();\r\n }\r\n\r\n return updatedCount;\r\n }\r\n\r\n /**\r\n * Delete documents from a collection\r\n * @param collectionName Name of the collection\r\n * @param options Delete options\r\n * @returns Number of deleted documents\r\n */\r\n public delete(collectionName: string, options: DeleteOptions = {}): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n const originalLength = this.data[collectionName].length;\r\n\r\n if (options.where) {\r\n this.data[collectionName] = this.data[collectionName].filter(\r\n (item) =>\r\n !Object.entries(options.where || {}).every(\r\n ([key, value]) => item[key] === value\r\n )\r\n );\r\n } else {\r\n // Delete all documents if no where clause\r\n this.data[collectionName] = [];\r\n }\r\n\r\n const deletedCount = originalLength - this.data[collectionName].length;\r\n\r\n if (deletedCount > 0) {\r\n this.saveData();\r\n }\r\n\r\n return deletedCount;\r\n }\r\n\r\n /**\r\n * Delete a document by ID\r\n * @param collectionName Name of the collection\r\n * @param id Document ID\r\n * @returns True if document was deleted, false otherwise\r\n */\r\n public deleteById(collectionName: string, id: string): boolean {\r\n if (!this.data[collectionName]) {\r\n return false;\r\n }\r\n\r\n const originalLength = this.data[collectionName].length;\r\n this.data[collectionName] = this.data[collectionName].filter(\r\n (item) => item.id !== id\r\n );\r\n\r\n const deleted = originalLength > this.data[collectionName].length;\r\n\r\n if (deleted) {\r\n this.saveData();\r\n }\r\n\r\n return deleted;\r\n }\r\n\r\n /**\r\n * Count documents in a collection\r\n * @param collectionName Name of the collection\r\n * @param where Optional filter\r\n * @returns Number of documents\r\n */\r\n public count(collectionName: string, where?: Record<string, any>): number {\r\n if (!this.data[collectionName]) {\r\n return 0;\r\n }\r\n\r\n if (where) {\r\n return this.data[collectionName].filter((item) =>\r\n Object.entries(where).every(([key, value]) => item[key] === value)\r\n ).length;\r\n }\r\n\r\n return this.data[collectionName].length;\r\n }\r\n\r\n /**\r\n * Get pagination information\r\n * @param collectionName Name of the collection\r\n * @param page Page number (1-based)\r\n * @param pageSize Number of items per page\r\n * @param where Optional filter\r\n * @returns Pagination information and data\r\n */\r\n public paginate<T>(\r\n collectionName: string,\r\n page = 1,\r\n pageSize = 10,\r\n where?: Record<string, any>\r\n ): {\r\n data: T[];\r\n pagination: {\r\n total: number;\r\n page: number;\r\n pageSize: number;\r\n totalPages: number;\r\n hasNext: boolean;\r\n hasPrev: boolean;\r\n };\r\n } {\r\n const offset = (page - 1) * pageSize;\r\n const total = this.count(collectionName, where);\r\n const totalPages = Math.ceil(total / pageSize);\r\n\r\n const data = this.find<T>(collectionName, {\r\n where,\r\n limit: pageSize,\r\n offset,\r\n });\r\n\r\n return {\r\n data,\r\n pagination: {\r\n total,\r\n page,\r\n pageSize,\r\n totalPages,\r\n hasNext: page < totalPages,\r\n hasPrev: page > 1,\r\n },\r\n };\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "simple-json-db-lite",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight JSON database with CRUD operations and pagination",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "dev": "vite build --watch",
22
+ "build": "vite build",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "json",
29
+ "database",
30
+ "db",
31
+ "crud",
32
+ "file",
33
+ "storage",
34
+ "lightweight"
35
+ ],
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/iiniit/simple-json-db-lite.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/iiniit/simple-json-db-lite/issues"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "homepage": "https://github.com/iiniit/simple-json-db-lite#readme",
48
+ "devDependencies": {
49
+ "@types/node": "^18.0.0",
50
+ "typescript": "^5.0.4",
51
+ "vite": "^4.3.9",
52
+ "vite-plugin-dts": "^2.3.0",
53
+ "vitest": "^0.32.0"
54
+ },
55
+ "engines": {
56
+ "node": ">=14.0.0"
57
+ }
58
+ }