jsql-neo 6.3.10 → 6.4.0-beta.10

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
@@ -3,7 +3,7 @@
3
3
  > **One engine to rule them all** — a Rust-powered embedded database that speaks your language:
4
4
  > MySQL, PostgreSQL, MongoDB, Redis, SQL, TypeScript, **and the browser**.
5
5
 
6
- > **v6.3.10** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
6
+ > **v6.4.0-beta.10** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
7
7
 
8
8
  ![Engines](https://img.shields.io/badge/engines-Native%20%7C%20WASM%20%7C%20Pure%20JS-7ee787)
9
9
  ![MySQL](https://img.shields.io/badge/protocol-MySQL%20compatible-1f6feb)
@@ -112,6 +112,27 @@ const db = new Database(':memory:');
112
112
  // same API as Node.js
113
113
  ```
114
114
 
115
+ ### 🦀 NativeJSQL
116
+
117
+ Pure Rust native bindings — the highest-performance way to run JSQL-NEO:
118
+
119
+ - **Zero abstraction overhead** — direct calls into the Rust core
120
+ - **Batch operations** — up to **1.54M rows/sec** peak throughput
121
+ - **Automatic memory management** with smart caching
122
+
123
+ **Install:**
124
+
125
+ ```bash
126
+ npm install jsql-neo
127
+ ```
128
+
129
+ **Usage:**
130
+
131
+ ```javascript
132
+ import { Database } from 'jsql-neo';
133
+ const db = new Database('mydb.jsql');
134
+ ```
135
+
115
136
  ### Storage modes
116
137
 
117
138
  | Mode | Usage | Use Case |
package/bin/jsql CHANGED
@@ -247,6 +247,96 @@ const cli = yaggs({ pkg: require('../package.json') })
247
247
  console.log(`jsql-neo Redis server on ${argv.host || '127.0.0.1'}:${argv.port != null ? argv.port : 6379}${argv['data-dir'] ? ' (data: ' + argv['data-dir'] + ')' : ''}`);
248
248
  setInterval(() => {}, 1 << 30);
249
249
  })
250
+ .command('plugin', 'Plugin registry management (list, search, install, uninstall, info)', (sub) => {
251
+ sub.option('json', { type: 'boolean', description: 'Output as JSON' });
252
+ sub.option('category', { type: 'string', description: 'Filter by category' });
253
+ sub.option('limit', { type: 'number', description: 'Max results per page' });
254
+ }, async (argv) => {
255
+ const pluginMgr = require('../src/cli/plugin');
256
+ const action = argv._[0];
257
+ const arg = argv._[1];
258
+ const useJson = !!argv.json;
259
+
260
+ const fail = (e) => { console.error(`Error: ${e.message}`); process.exitCode = 1; };
261
+ const out = (obj) => {
262
+ if (obj === undefined) return;
263
+ if (useJson) console.log(JSON.stringify(obj, null, 2));
264
+ else console.log(obj);
265
+ };
266
+
267
+ try {
268
+ switch (action) {
269
+ case 'list':
270
+ case 'ls': {
271
+ const opts = {};
272
+ if (argv.category) opts.category = argv.category;
273
+ if (argv.limit) opts.limit = argv.limit;
274
+ const plugins = await pluginMgr.listPlugins(opts);
275
+ out(useJson ? plugins : pluginMgr.formatPluginList(plugins));
276
+ break;
277
+ }
278
+ case 'search': {
279
+ if (!arg) throw new Error('Usage: jsql plugin search <query>');
280
+ const opts = {};
281
+ if (argv.category) opts.category = argv.category;
282
+ const data = await pluginMgr.searchPlugins(arg, opts);
283
+ // search 返回 { results: [...], query, total } 或 [...]
284
+ const plugins = Array.isArray(data) ? data : (data.results || []);
285
+ if (useJson) {
286
+ out(data);
287
+ } else {
288
+ if (!plugins.length) {
289
+ console.log(`No plugins found for '${arg}'.`);
290
+ } else {
291
+ console.log(`Found ${plugins.length} plugin(s) for '${arg}':`);
292
+ console.log(pluginMgr.formatPluginList(plugins.map(p => p.plugin || p)));
293
+ }
294
+ }
295
+ break;
296
+ }
297
+ case 'install': {
298
+ if (!arg) throw new Error('Usage: jsql plugin install <name>');
299
+ const manifest = await pluginMgr.installPlugin(arg);
300
+ out(useJson ? manifest : `Installed plugin '${manifest.name}' (${manifest.version})`);
301
+ break;
302
+ }
303
+ case 'uninstall':
304
+ case 'remove': {
305
+ if (!arg) throw new Error('Usage: jsql plugin uninstall <name>');
306
+ const r = pluginMgr.uninstallPlugin(arg);
307
+ out(useJson ? r : `Uninstalled plugin '${r.name}'.`);
308
+ break;
309
+ }
310
+ case 'info': {
311
+ if (!arg) throw new Error('Usage: jsql plugin info <name>');
312
+ const p = await pluginMgr.getPluginInfo(arg);
313
+ out(useJson ? p : pluginMgr.formatPluginInfo(p));
314
+ break;
315
+ }
316
+ case undefined:
317
+ // 无子命令 → 显示已安装插件
318
+ const installed = pluginMgr.listInstalled();
319
+ if (useJson) {
320
+ out(installed);
321
+ } else {
322
+ if (!installed.length) {
323
+ console.log('No plugins installed.');
324
+ console.log(`Plugin directory: ${pluginMgr.PLUGIN_DIR}`);
325
+ } else {
326
+ console.log(`Installed plugins (${installed.length}):`);
327
+ installed.forEach(p => {
328
+ console.log(` ${p.name.padEnd(24)} ${p.version || '?'}`);
329
+ });
330
+ }
331
+ }
332
+ break;
333
+ default:
334
+ throw new Error(`Unknown plugin action: ${action}`);
335
+ }
336
+ } catch (e) {
337
+ fail(e);
338
+ }
339
+ })
250
340
  .command('version', 'Show version', null, () => {
251
341
  console.log(require('../package.json').version);
252
342
  })
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * JSQL-NEO v6.3.10 — Rust-Powered Embedded Database (WASM + HTTP)
2
+ * JSQL-NEO v6.4.0-beta.10 — Rust-Powered Embedded Database (WASM + HTTP)
3
3
  *
4
4
  * @example
5
5
  * const jsql = require('jsql-neo');
package/lib/cache.js CHANGED
@@ -50,7 +50,7 @@ class Cache {
50
50
  if (typeof val === 'string') return 'string';
51
51
  if (val instanceof Set) return 'set';
52
52
  if (Array.isArray(val)) return val._type === 'hash' ? 'hash' : 'list';
53
- if (typeof val === 'object' && val._type === 'hash') return 'hash';
53
+ if (val !== null && typeof val === 'object' && val._type === 'hash') return 'hash';
54
54
  return 'string';
55
55
  }
56
56
  expire(key, seconds) {
@@ -85,7 +85,10 @@ class Cache {
85
85
  hset(key, field, value) {
86
86
  const k = String(key);
87
87
  let hash = this._getData().get(k);
88
- if (!hash || hash._type !== 'hash') { hash = { _type: 'hash' }; this._getData().set(k, hash); }
88
+ if (hash !== undefined && (typeof hash !== 'object' || hash._type !== 'hash')) {
89
+ throw new Error('WRONGTYPE Operation against a key holding the wrong kind of value');
90
+ }
91
+ if (!hash) { hash = { _type: 'hash' }; this._getData().set(k, hash); }
89
92
  const existed = hash[field] !== undefined;
90
93
  hash[field] = String(value);
91
94
  this._dirty = true;
@@ -134,7 +137,10 @@ class Cache {
134
137
  lpush(key, ...values) {
135
138
  const k = String(key);
136
139
  let list = this._getData().get(k);
137
- if (!list || !Array.isArray(list) || list._type === 'hash') { list = []; this._getData().set(k, list); }
140
+ if (list !== undefined && (!Array.isArray(list) || list._type === 'hash')) {
141
+ throw new Error('WRONGTYPE Operation against a key holding the wrong kind of value');
142
+ }
143
+ if (!list) { list = []; this._getData().set(k, list); }
138
144
  list.unshift(...values.map(String).reverse());
139
145
  this._dirty = true;
140
146
  return list.length;
@@ -142,7 +148,10 @@ class Cache {
142
148
  rpush(key, ...values) {
143
149
  const k = String(key);
144
150
  let list = this._getData().get(k);
145
- if (!list || !Array.isArray(list) || list._type === 'hash') { list = []; this._getData().set(k, list); }
151
+ if (list !== undefined && (!Array.isArray(list) || list._type === 'hash')) {
152
+ throw new Error('WRONGTYPE Operation against a key holding the wrong kind of value');
153
+ }
154
+ if (!list) { list = []; this._getData().set(k, list); }
146
155
  list.push(...values.map(String));
147
156
  this._dirty = true;
148
157
  return list.length;
@@ -185,7 +194,10 @@ class Cache {
185
194
  sadd(key, ...members) {
186
195
  const k = String(key);
187
196
  let set = this._getData().get(k);
188
- if (!set || !(set instanceof Set)) { set = new Set(); this._getData().set(k, set); }
197
+ if (set !== undefined && !(set instanceof Set)) {
198
+ throw new Error('WRONGTYPE Operation against a key holding the wrong kind of value');
199
+ }
200
+ if (!set) { set = new Set(); this._getData().set(k, set); }
189
201
  let count = 0;
190
202
  for (const m of members) { if (!set.has(String(m))) { set.add(String(m)); count++; } }
191
203
  if (count > 0) this._dirty = true;
@@ -223,10 +235,11 @@ class Cache {
223
235
  }
224
236
 
225
237
  flushall() {
238
+ const currentDb = this._db;
226
239
  for (let i = 0; i < this._dbs.length; i++) { if (this._dbs[i]) this._dbs[i].clear(); if (this._dbsExpires[i]) this._dbsExpires[i].clear(); }
227
- this._data = this._dbs[0] = new Map();
228
- this._expires = this._dbsExpires[0] = new Map();
229
- this._db = 0;
240
+ this._data = this._dbs[currentDb] = new Map();
241
+ this._expires = this._dbsExpires[currentDb] = new Map();
242
+ this._db = currentDb;
230
243
  this._dirty = true;
231
244
  return 'OK';
232
245
  }