@yanit/jsondb 0.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.
- package/README.md +903 -0
- package/dist/bin/cli-export.d.ts +7 -0
- package/dist/bin/cli-export.d.ts.map +1 -0
- package/dist/bin/cli-export.js +318 -0
- package/dist/bin/cli-export.js.map +1 -0
- package/dist/bin/cli-import.d.ts +7 -0
- package/dist/bin/cli-import.d.ts.map +1 -0
- package/dist/bin/cli-import.js +298 -0
- package/dist/bin/cli-import.js.map +1 -0
- package/dist/bin/server.d.ts +7 -0
- package/dist/bin/server.d.ts.map +1 -0
- package/dist/bin/server.js +92 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/examples/sql-example.d.ts +7 -0
- package/dist/examples/sql-example.d.ts.map +1 -0
- package/dist/examples/sql-example.js +131 -0
- package/dist/examples/sql-example.js.map +1 -0
- package/dist/src/BulkOp.d.ts +74 -0
- package/dist/src/BulkOp.d.ts.map +1 -0
- package/dist/src/BulkOp.js +143 -0
- package/dist/src/BulkOp.js.map +1 -0
- package/dist/src/Collection.d.ts +232 -0
- package/dist/src/Collection.d.ts.map +1 -0
- package/dist/src/Collection.js +705 -0
- package/dist/src/Collection.js.map +1 -0
- package/dist/src/Cursor.d.ts +94 -0
- package/dist/src/Cursor.d.ts.map +1 -0
- package/dist/src/Cursor.js +259 -0
- package/dist/src/Cursor.js.map +1 -0
- package/dist/src/Database.d.ts +98 -0
- package/dist/src/Database.d.ts.map +1 -0
- package/dist/src/Database.js +198 -0
- package/dist/src/Database.js.map +1 -0
- package/dist/src/Operators.d.ts +73 -0
- package/dist/src/Operators.d.ts.map +1 -0
- package/dist/src/Operators.js +339 -0
- package/dist/src/Operators.js.map +1 -0
- package/dist/src/QueryCache.d.ts +87 -0
- package/dist/src/QueryCache.d.ts.map +1 -0
- package/dist/src/QueryCache.js +155 -0
- package/dist/src/QueryCache.js.map +1 -0
- package/dist/src/SQLExecutor.d.ts +60 -0
- package/dist/src/SQLExecutor.d.ts.map +1 -0
- package/dist/src/SQLExecutor.js +317 -0
- package/dist/src/SQLExecutor.js.map +1 -0
- package/dist/src/SQLParser.d.ts +181 -0
- package/dist/src/SQLParser.d.ts.map +1 -0
- package/dist/src/SQLParser.js +640 -0
- package/dist/src/SQLParser.js.map +1 -0
- package/dist/src/Schema.d.ts +92 -0
- package/dist/src/Schema.d.ts.map +1 -0
- package/dist/src/Schema.js +253 -0
- package/dist/src/Schema.js.map +1 -0
- package/dist/src/Transaction.d.ts +118 -0
- package/dist/src/Transaction.d.ts.map +1 -0
- package/dist/src/Transaction.js +233 -0
- package/dist/src/Transaction.js.map +1 -0
- package/dist/src/Utils.d.ts +68 -0
- package/dist/src/Utils.d.ts.map +1 -0
- package/dist/src/Utils.js +187 -0
- package/dist/src/Utils.js.map +1 -0
- package/dist/src/errors.d.ts +58 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +85 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/index.d.ts +39 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +44 -0
- package/dist/src/index.js.map +1 -0
- package/dist/test/basic.test.d.ts +5 -0
- package/dist/test/basic.test.d.ts.map +1 -0
- package/dist/test/basic.test.js +283 -0
- package/dist/test/basic.test.js.map +1 -0
- package/dist/test/index.test.d.ts +5 -0
- package/dist/test/index.test.d.ts.map +1 -0
- package/dist/test/index.test.js +126 -0
- package/dist/test/index.test.js.map +1 -0
- package/dist/test/jsonb.test.d.ts +5 -0
- package/dist/test/jsonb.test.d.ts.map +1 -0
- package/dist/test/jsonb.test.js +165 -0
- package/dist/test/jsonb.test.js.map +1 -0
- package/dist/test/optimization.test.d.ts +6 -0
- package/dist/test/optimization.test.d.ts.map +1 -0
- package/dist/test/optimization.test.js +196 -0
- package/dist/test/optimization.test.js.map +1 -0
- package/dist/test/schema.test.d.ts +5 -0
- package/dist/test/schema.test.d.ts.map +1 -0
- package/dist/test/schema.test.js +197 -0
- package/dist/test/schema.test.js.map +1 -0
- package/dist/test/sql.test.d.ts +7 -0
- package/dist/test/sql.test.d.ts.map +1 -0
- package/dist/test/sql.test.js +21 -0
- package/dist/test/sql.test.js.map +1 -0
- package/package.json +73 -0
- package/src/BulkOp.js +181 -0
- package/src/BulkOp.ts +191 -0
- package/src/Collection.js +843 -0
- package/src/Collection.ts +896 -0
- package/src/Cursor.js +315 -0
- package/src/Cursor.ts +319 -0
- package/src/Database.js +244 -0
- package/src/Database.ts +268 -0
- package/src/Operators.js +382 -0
- package/src/Operators.ts +375 -0
- package/src/QueryCache.js +190 -0
- package/src/QueryCache.ts +208 -0
- package/src/SQLExecutor.ts +391 -0
- package/src/SQLParser.ts +814 -0
- package/src/Schema.js +292 -0
- package/src/Schema.ts +317 -0
- package/src/Transaction.js +291 -0
- package/src/Transaction.ts +313 -0
- package/src/Utils.js +205 -0
- package/src/Utils.ts +205 -0
- package/src/errors.js +93 -0
- package/src/errors.ts +93 -0
- package/src/index.js +90 -0
- package/src/index.ts +106 -0
package/src/Database.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据库类 - 管理数据库和集合
|
|
3
|
+
* 支持 async/await 异步操作
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, writeFile, access, mkdir, readdir, rm } from 'fs/promises';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { Collection } from './Collection.js';
|
|
10
|
+
import { ensureDir } from './Utils.js';
|
|
11
|
+
import { DatabaseNotFoundError, CollectionExistsError } from './errors.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Database 类
|
|
15
|
+
* 表示一个数据库,提供集合管理和数据库操作
|
|
16
|
+
*/
|
|
17
|
+
export class Database {
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} dbPath - 数据库路径
|
|
20
|
+
* @param {Object} options - 数据库选项
|
|
21
|
+
* @param {boolean} options.jsonb - 是否启用 JSONB 二进制存储(默认 false)
|
|
22
|
+
* @param {number} options.cacheTTL - 内存缓存过期时间(毫秒,默认 5000)
|
|
23
|
+
* @param {boolean} options.enableQueryCache - 是否启用查询结果缓存(默认 true)
|
|
24
|
+
* @param {number} options.queryCacheTTL - 查询缓存过期时间(毫秒,默认 30000)
|
|
25
|
+
*/
|
|
26
|
+
constructor(dbPath, options = {}) {
|
|
27
|
+
this.dbPath = dbPath;
|
|
28
|
+
this._metaFile = join(dbPath, '_meta.json');
|
|
29
|
+
this._meta = null;
|
|
30
|
+
this._collections = new Map();
|
|
31
|
+
this.options = {
|
|
32
|
+
jsonb: options.jsonb || false, // JSONB 二进制存储模式
|
|
33
|
+
cacheTTL: options.cacheTTL || 5000, // 内存缓存 TTL
|
|
34
|
+
enableQueryCache: options.enableQueryCache !== false, // 查询结果缓存
|
|
35
|
+
queryCacheTTL: options.queryCacheTTL || 30000 // 查询缓存 TTL
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 打开数据库
|
|
41
|
+
* @returns {Promise<Database>} 返回自身以支持链式调用
|
|
42
|
+
*/
|
|
43
|
+
async open() {
|
|
44
|
+
// 如果数据库不存在,创建它
|
|
45
|
+
if (!existsSync(this.dbPath)) {
|
|
46
|
+
await mkdir(this.dbPath, { recursive: true });
|
|
47
|
+
this._meta = {
|
|
48
|
+
name: this.dbNameFromPath,
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
createdAt: new Date().toISOString(),
|
|
51
|
+
collections: []
|
|
52
|
+
};
|
|
53
|
+
await this._saveMeta();
|
|
54
|
+
} else {
|
|
55
|
+
// 加载元数据
|
|
56
|
+
await this._loadMeta();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 从路径获取数据库名
|
|
64
|
+
* @returns {string} 数据库名
|
|
65
|
+
*/
|
|
66
|
+
get dbNameFromPath() {
|
|
67
|
+
return this.dbPath.split(/[\\/]/).pop() || 'default';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 加载元数据
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
async _loadMeta() {
|
|
75
|
+
if (!existsSync(this._metaFile)) {
|
|
76
|
+
throw new DatabaseNotFoundError(this.dbPath);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const content = await readFile(this._metaFile, 'utf-8');
|
|
80
|
+
this._meta = JSON.parse(content);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 保存元数据
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
async _saveMeta() {
|
|
88
|
+
ensureDir(this._metaFile);
|
|
89
|
+
const content = JSON.stringify(this._meta, null, 2);
|
|
90
|
+
await writeFile(this._metaFile, content, 'utf-8');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 关闭数据库
|
|
95
|
+
* @returns {Promise<void>}
|
|
96
|
+
*/
|
|
97
|
+
async close() {
|
|
98
|
+
// 保存所有集合数据
|
|
99
|
+
for (const collection of this._collections.values()) {
|
|
100
|
+
// Collection 会自动保存
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this._collections.clear();
|
|
104
|
+
this._meta = null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 获取集合
|
|
109
|
+
* @param {string} name - 集合名称
|
|
110
|
+
* @returns {Collection} 集合实例
|
|
111
|
+
*/
|
|
112
|
+
collection(name) {
|
|
113
|
+
// 检查缓存
|
|
114
|
+
if (this._collections.has(name)) {
|
|
115
|
+
return this._collections.get(name);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 创建新集合
|
|
119
|
+
const collection = new Collection(this, name);
|
|
120
|
+
this._collections.set(name, collection);
|
|
121
|
+
|
|
122
|
+
return collection;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 创建集合
|
|
127
|
+
* @param {string} name - 集合名称
|
|
128
|
+
* @param {Object} options - 选项
|
|
129
|
+
* @returns {Promise<Collection>} 集合实例
|
|
130
|
+
*/
|
|
131
|
+
async createCollection(name, options = {}) {
|
|
132
|
+
const collectionFile = join(this.dbPath, `${name}.json`);
|
|
133
|
+
|
|
134
|
+
// 检查集合是否已存在
|
|
135
|
+
if (existsSync(collectionFile)) {
|
|
136
|
+
throw new CollectionExistsError(name);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 创建集合文件
|
|
140
|
+
const initialData = {
|
|
141
|
+
_meta: {
|
|
142
|
+
name,
|
|
143
|
+
count: 0,
|
|
144
|
+
indexes: options.indexes || []
|
|
145
|
+
},
|
|
146
|
+
_documents: [],
|
|
147
|
+
_indexes: {}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
ensureDir(collectionFile);
|
|
151
|
+
await writeFile(collectionFile, JSON.stringify(initialData, null, 2), 'utf-8');
|
|
152
|
+
|
|
153
|
+
// 更新元数据
|
|
154
|
+
if (!this._meta.collections.includes(name)) {
|
|
155
|
+
this._meta.collections.push(name);
|
|
156
|
+
await this._saveMeta();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const collection = new Collection(this, name);
|
|
160
|
+
this._collections.set(name, collection);
|
|
161
|
+
|
|
162
|
+
return collection;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 删除集合
|
|
167
|
+
* @param {string} name - 集合名称
|
|
168
|
+
* @returns {Promise<Object>} 删除结果
|
|
169
|
+
*/
|
|
170
|
+
async dropCollection(name) {
|
|
171
|
+
const collectionFile = join(this.dbPath, `${name}.json`);
|
|
172
|
+
|
|
173
|
+
if (!existsSync(collectionFile)) {
|
|
174
|
+
return { acknowledged: false };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 删除文件
|
|
178
|
+
await rm(collectionFile);
|
|
179
|
+
|
|
180
|
+
// 更新元数据
|
|
181
|
+
this._meta.collections = this._meta.collections.filter(c => c !== name);
|
|
182
|
+
await this._saveMeta();
|
|
183
|
+
|
|
184
|
+
// 清除缓存
|
|
185
|
+
this._collections.delete(name);
|
|
186
|
+
|
|
187
|
+
return { acknowledged: true };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 列出所有集合
|
|
192
|
+
* @returns {Promise<Array<string>>} 集合名称数组
|
|
193
|
+
*/
|
|
194
|
+
async listCollections() {
|
|
195
|
+
// 从文件系统读取最新的集合列表
|
|
196
|
+
const files = await readdir(this.dbPath);
|
|
197
|
+
const collectionFiles = files
|
|
198
|
+
.filter(file => file.endsWith('.json') && file !== '_meta.json')
|
|
199
|
+
.map(file => file.replace('.json', ''));
|
|
200
|
+
|
|
201
|
+
return collectionFiles;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 获取数据库统计信息
|
|
206
|
+
* @returns {Promise<Object>} 统计信息
|
|
207
|
+
*/
|
|
208
|
+
async stats() {
|
|
209
|
+
const collections = await this.listCollections();
|
|
210
|
+
let totalDocuments = 0;
|
|
211
|
+
let totalSize = 0;
|
|
212
|
+
|
|
213
|
+
for (const name of collections) {
|
|
214
|
+
const collection = this.collection(name);
|
|
215
|
+
const stats = await collection.stats();
|
|
216
|
+
totalDocuments += stats.count;
|
|
217
|
+
totalSize += stats.size;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
db: this.dbNameFromPath,
|
|
222
|
+
collections: collections.length,
|
|
223
|
+
totalDocuments,
|
|
224
|
+
totalSize,
|
|
225
|
+
path: this.dbPath,
|
|
226
|
+
jsonb: this.options.jsonb
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 删除数据库
|
|
232
|
+
* @returns {Promise<Object>} 删除结果
|
|
233
|
+
*/
|
|
234
|
+
async drop() {
|
|
235
|
+
if (existsSync(this.dbPath)) {
|
|
236
|
+
await rm(this.dbPath, { recursive: true, force: true });
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this._meta = null;
|
|
240
|
+
this._collections.clear();
|
|
241
|
+
|
|
242
|
+
return { acknowledged: true };
|
|
243
|
+
}
|
|
244
|
+
}
|
package/src/Database.ts
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据库类 - 管理数据库和集合
|
|
3
|
+
* 支持 async/await 异步操作
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, writeFile, mkdir, readdir, rm } from 'fs/promises';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { Collection } from './Collection.js';
|
|
10
|
+
import { ensureDir } from './Utils.js';
|
|
11
|
+
import { DatabaseNotFoundError, CollectionExistsError } from './errors.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 数据库选项接口
|
|
15
|
+
*/
|
|
16
|
+
interface DatabaseOptions {
|
|
17
|
+
jsonb?: boolean;
|
|
18
|
+
cacheTTL?: number;
|
|
19
|
+
enableQueryCache?: boolean;
|
|
20
|
+
queryCacheTTL?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 数据库统计信息接口
|
|
25
|
+
*/
|
|
26
|
+
interface DatabaseStats {
|
|
27
|
+
db: string;
|
|
28
|
+
collections: number;
|
|
29
|
+
totalDocuments: number;
|
|
30
|
+
totalSize: number;
|
|
31
|
+
path: string;
|
|
32
|
+
jsonb: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 数据库元数据接口
|
|
37
|
+
*/
|
|
38
|
+
interface DatabaseMeta {
|
|
39
|
+
name: string;
|
|
40
|
+
version: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
collections: string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Database 类
|
|
47
|
+
* 表示一个数据库,提供集合管理和数据库操作
|
|
48
|
+
*/
|
|
49
|
+
export class Database {
|
|
50
|
+
dbPath: string;
|
|
51
|
+
private _metaFile: string;
|
|
52
|
+
private _meta: DatabaseMeta | null;
|
|
53
|
+
private _collections: Map<string, Collection>;
|
|
54
|
+
options: {
|
|
55
|
+
jsonb: boolean;
|
|
56
|
+
cacheTTL: number;
|
|
57
|
+
enableQueryCache: boolean;
|
|
58
|
+
queryCacheTTL: number;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param dbPath - 数据库路径
|
|
63
|
+
* @param options - 数据库选项
|
|
64
|
+
*/
|
|
65
|
+
constructor(dbPath: string, options: DatabaseOptions = {}) {
|
|
66
|
+
this.dbPath = dbPath;
|
|
67
|
+
this._metaFile = join(dbPath, '_meta.json');
|
|
68
|
+
this._meta = null;
|
|
69
|
+
this._collections = new Map();
|
|
70
|
+
this.options = {
|
|
71
|
+
jsonb: options.jsonb || false,
|
|
72
|
+
cacheTTL: options.cacheTTL || 5000,
|
|
73
|
+
enableQueryCache: options.enableQueryCache !== false,
|
|
74
|
+
queryCacheTTL: options.queryCacheTTL || 30000
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 打开数据库
|
|
80
|
+
*/
|
|
81
|
+
async open(): Promise<Database> {
|
|
82
|
+
// 如果数据库不存在,创建它
|
|
83
|
+
if (!existsSync(this.dbPath)) {
|
|
84
|
+
await mkdir(this.dbPath, { recursive: true });
|
|
85
|
+
this._meta = {
|
|
86
|
+
name: this.dbNameFromPath,
|
|
87
|
+
version: '1.0.0',
|
|
88
|
+
createdAt: new Date().toISOString(),
|
|
89
|
+
collections: []
|
|
90
|
+
};
|
|
91
|
+
await this._saveMeta();
|
|
92
|
+
} else {
|
|
93
|
+
// 加载元数据
|
|
94
|
+
await this._loadMeta();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 从路径获取数据库名
|
|
102
|
+
*/
|
|
103
|
+
get dbNameFromPath(): string {
|
|
104
|
+
return this.dbPath.split(/[\\/]/).pop() || 'default';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 加载元数据
|
|
109
|
+
*/
|
|
110
|
+
private async _loadMeta(): Promise<void> {
|
|
111
|
+
if (!existsSync(this._metaFile)) {
|
|
112
|
+
throw new DatabaseNotFoundError(this.dbPath);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const content = await readFile(this._metaFile, 'utf-8');
|
|
116
|
+
this._meta = JSON.parse(content) as DatabaseMeta;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 保存元数据
|
|
121
|
+
*/
|
|
122
|
+
private async _saveMeta(): Promise<void> {
|
|
123
|
+
ensureDir(this._metaFile);
|
|
124
|
+
const content = JSON.stringify(this._meta, null, 2);
|
|
125
|
+
await writeFile(this._metaFile, content, 'utf-8');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 关闭数据库
|
|
130
|
+
*/
|
|
131
|
+
async close(): Promise<void> {
|
|
132
|
+
// 保存所有集合数据
|
|
133
|
+
for (const collection of this._collections.values()) {
|
|
134
|
+
// Collection 会自动保存
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this._collections.clear();
|
|
138
|
+
this._meta = null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 获取集合
|
|
143
|
+
*/
|
|
144
|
+
collection(name: string): Collection {
|
|
145
|
+
// 检查缓存
|
|
146
|
+
if (this._collections.has(name)) {
|
|
147
|
+
return this._collections.get(name)!;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 创建新集合
|
|
151
|
+
const collection = new Collection(this, name);
|
|
152
|
+
this._collections.set(name, collection);
|
|
153
|
+
|
|
154
|
+
return collection;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 创建集合
|
|
159
|
+
*/
|
|
160
|
+
async createCollection(name: string, options: { indexes?: unknown[] } = {}): Promise<Collection> {
|
|
161
|
+
const collectionFile = join(this.dbPath, `${name}.json`);
|
|
162
|
+
|
|
163
|
+
// 检查集合是否已存在
|
|
164
|
+
if (existsSync(collectionFile)) {
|
|
165
|
+
throw new CollectionExistsError(name);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 创建集合文件
|
|
169
|
+
const initialData = {
|
|
170
|
+
_meta: {
|
|
171
|
+
name,
|
|
172
|
+
count: 0,
|
|
173
|
+
indexes: options.indexes || []
|
|
174
|
+
},
|
|
175
|
+
_documents: [],
|
|
176
|
+
_indexes: {}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
ensureDir(collectionFile);
|
|
180
|
+
await writeFile(collectionFile, JSON.stringify(initialData, null, 2), 'utf-8');
|
|
181
|
+
|
|
182
|
+
// 更新元数据
|
|
183
|
+
if (!this._meta!.collections.includes(name)) {
|
|
184
|
+
this._meta!.collections.push(name);
|
|
185
|
+
await this._saveMeta();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const collection = new Collection(this, name);
|
|
189
|
+
this._collections.set(name, collection);
|
|
190
|
+
|
|
191
|
+
return collection;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 删除集合
|
|
196
|
+
*/
|
|
197
|
+
async dropCollection(name: string): Promise<{ acknowledged: boolean }> {
|
|
198
|
+
const collectionFile = join(this.dbPath, `${name}.json`);
|
|
199
|
+
|
|
200
|
+
if (!existsSync(collectionFile)) {
|
|
201
|
+
return { acknowledged: false };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 删除文件
|
|
205
|
+
await rm(collectionFile);
|
|
206
|
+
|
|
207
|
+
// 更新元数据
|
|
208
|
+
this._meta!.collections = this._meta!.collections.filter(c => c !== name);
|
|
209
|
+
await this._saveMeta();
|
|
210
|
+
|
|
211
|
+
// 清除缓存
|
|
212
|
+
this._collections.delete(name);
|
|
213
|
+
|
|
214
|
+
return { acknowledged: true };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 列出所有集合
|
|
219
|
+
*/
|
|
220
|
+
async listCollections(): Promise<string[]> {
|
|
221
|
+
// 从文件系统读取最新的集合列表
|
|
222
|
+
const files = await readdir(this.dbPath);
|
|
223
|
+
const collectionFiles = files
|
|
224
|
+
.filter(file => file.endsWith('.json') && file !== '_meta.json')
|
|
225
|
+
.map(file => file.replace('.json', ''));
|
|
226
|
+
|
|
227
|
+
return collectionFiles;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 获取数据库统计信息
|
|
232
|
+
*/
|
|
233
|
+
async stats(): Promise<DatabaseStats> {
|
|
234
|
+
const collections = await this.listCollections();
|
|
235
|
+
let totalDocuments = 0;
|
|
236
|
+
let totalSize = 0;
|
|
237
|
+
|
|
238
|
+
for (const name of collections) {
|
|
239
|
+
const collection = this.collection(name);
|
|
240
|
+
const stats = await collection.stats();
|
|
241
|
+
totalDocuments += stats.count;
|
|
242
|
+
totalSize += stats.size;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
db: this.dbNameFromPath,
|
|
247
|
+
collections: collections.length,
|
|
248
|
+
totalDocuments,
|
|
249
|
+
totalSize,
|
|
250
|
+
path: this.dbPath,
|
|
251
|
+
jsonb: this.options.jsonb
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 删除数据库
|
|
257
|
+
*/
|
|
258
|
+
async drop(): Promise<{ acknowledged: boolean }> {
|
|
259
|
+
if (existsSync(this.dbPath)) {
|
|
260
|
+
await rm(this.dbPath, { recursive: true, force: true });
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
this._meta = null;
|
|
264
|
+
this._collections.clear();
|
|
265
|
+
|
|
266
|
+
return { acknowledged: true };
|
|
267
|
+
}
|
|
268
|
+
}
|