@wowoengine/sawitdb 2.4.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 SawitDB Community
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,245 @@
1
+ # SawitDB
2
+
3
+ ![SawitDB Banner](docs/sawitdb.jpg)
4
+
5
+ <div align="center">
6
+
7
+ [![Docs](https://img.shields.io/badge/Docs-Read%20Now-blue?style=for-the-badge&logo=googledocs)](https://wowoengine.github.io/SawitDB/)
8
+ [![Go Version](https://img.shields.io/badge/Go%20Version-Visit%20Repo-cyan?style=for-the-badge&logo=go)](https://github.com/WowoEngine/SawitDB-Go)
9
+ [![Changelog](https://img.shields.io/badge/Changelog-Read%20Updates-orange?style=for-the-badge&logo=github)](CHANGELOG.md)
10
+
11
+ </div>
12
+
13
+
14
+ **SawitDB** is a unique database solution stored in `.sawit` binary files.
15
+
16
+ The system features a custom **Paged Heap File** architecture similar to SQLite, using fixed-size 4KB pages to ensure efficient memory usage. What differentiates SawitDB is its unique **Agricultural Query Language (AQL)**, which replaces standard SQL keywords with Indonesian farming terminology.
17
+
18
+ **Now with Network Edition!** Connect via TCP using `sawitdb://` protocol similar to MongoDB.
19
+
20
+ **🚨 Emergency: Aceh Flood Relief**
21
+ Please support our brothers and sisters in Aceh.
22
+
23
+ [![Kitabisa](https://img.shields.io/badge/Kitabisa-Bantu%20Aceh-blue?style=flat&logo=heart)](https://kitabisa.com/campaign/donasipedulibanjiraceh)
24
+
25
+ *Organized by Human Initiative Aceh*
26
+
27
+ ## Features
28
+
29
+ - **Paged Architecture**: Data is stored in 4096-byte binary pages. The engine does not load the entire database into memory.
30
+ - **Single File Storage**: All data, schema, and indexes are stored in a single `.sawit` file.
31
+ - **High Stability**: Uses 4KB atomic pages. More stable than a coalition government.
32
+ - **Data Integrity (Anti-Korupsi)**: Implements strict `fsync` protocols. Data cannot be "corrupted" or "disappear" mysteriously like social aid funds (Bansos). No "Sunat Massal" here.
33
+ - **Zero Bureaucracy (Zero Deps)**: Built entirely with standard Node.js. No unnecessary "Vendor Pengadaan" or "Mark-up Anggaran".
34
+ - **Transparansi**: Query language is clear. No "Pasal Karet" (Ambiguous Laws) or "Rapat Tertutup" in 5-star hotels.
35
+ - **Speed**: Faster than printing an e-KTP at the Kelurahan.
36
+ - **Network Support (NEW)**: Client-Server architecture with Multi-database support and Authentication.
37
+
38
+ ## Filosofi
39
+
40
+ ### Filosofi (ID)
41
+ SawitDB dibangun dengan semangat "Kemandirian Data". Kami percaya database yang handal tidak butuh **Infrastruktur Langit** yang harganya triliunan tapi sering *down*. Berbeda dengan proyek negara yang mahal di *budget* tapi murah di kualitas, SawitDB menggunakan arsitektur **Single File** (`.sawit`) yang hemat biaya. Backup cukup *copy-paste*, tidak perlu sewa vendor konsultan asing. Fitur **`fsync`** kami menjamin data tertulis di *disk*, karena bagi kami, integritas data adalah harga mati, bukan sekadar bahan konferensi pers untuk minta maaf.
42
+
43
+ ### Philosophy (EN)
44
+ SawitDB is built with the spirit of "Data Sovereignty". We believe a reliable database doesn't need **"Sky Infrastructure"** that costs trillions yet goes *down* often. Unlike state projects that are expensive in budget but cheap in quality, SawitDB uses a cost-effective **Single File** (`.sawit`) architecture. Backup is just *copy-paste*, no need to hire expensive foreign consultants. Our **`fsync`** feature guarantees data is written to *disk*, because for us, data integrity is non-negotiable, not just material for a press conference to apologize.
45
+
46
+ ## File List
47
+
48
+ - `src/WowoEngine.js`: Core Database Engine (Class: `SawitDB`).
49
+ - `bin/sawit-server.js`: Server executable.
50
+ - `cli/local.js`: Interactive CLI tool (Local).
51
+ - `cli/remote.js`: Interactive CLI tool (Network).
52
+ - [CHANGELOG.md](CHANGELOG.md): Version history and release notes.
53
+ - `examples/`: Sample scripts.
54
+
55
+ ## Installation
56
+
57
+ Ensure you have Node.js installed. Clone the repository.
58
+
59
+ ```bash
60
+ # Clone
61
+ git clone https://github.com/WowoEngine/SawitDB.git
62
+ ```
63
+
64
+ ## Quick Start (Network Edition)
65
+
66
+ ### 1. Start the Server
67
+ ```bash
68
+ node src/SawitServer.js
69
+ ```
70
+ The server will start on `0.0.0.0:7878` by default.
71
+
72
+ ### 2. Connect with Client
73
+ Use [SawitClient](#client-api) or any interactive session.
74
+
75
+ ---
76
+
77
+ ## Dual Syntax Support
78
+
79
+ SawitDB 2.3 introduces the **Generic Syntax** alongside the classic **Agricultural Query Language (AQL)**, making it easier for developers familiar with standard SQL to adopt.
80
+
81
+ | Operation | Agricultural Query Language (AQL) | Generic SQL (Standard) |
82
+ | :--- | :--- | :--- |
83
+ | **Create DB** | `BUKA WILAYAH sales_db` | `CREATE DATABASE sales_db` |
84
+ | **Use DB** | `MASUK WILAYAH sales_db` | `USE sales_db` |
85
+ | **Show DBs** | `LIHAT WILAYAH` | `SHOW DATABASES` |
86
+ | **Drop DB** | `BAKAR WILAYAH sales_db` | `DROP DATABASE sales_db` |
87
+ | **Create Table** | `LAHAN products` | `CREATE TABLE products` |
88
+ | **Insert** | `TANAM KE products (...) BIBIT (...)` | `INSERT INTO products (...) VALUES (...)` |
89
+ | **Select** | `PANEN * DARI products DIMANA ...` | `SELECT * FROM products WHERE ...` |
90
+ | **Update** | `PUPUK products DENGAN ...` | `UPDATE products SET ...` |
91
+ | **Delete** | `GUSUR DARI products DIMANA ...` | `DELETE FROM products WHERE ...` |
92
+ | **Indexing** | `INDEKS products PADA price` | `CREATE INDEX ON products (price)` |
93
+ | **Aggregation** | `HITUNG SUM(stock) DARI products` | *Same Syntax* |
94
+
95
+ ---
96
+
97
+ ## Query Syntax (Detailed)
98
+
99
+ ### 1. Management Commands
100
+
101
+ #### Create Table
102
+ ```sql
103
+ -- Tani
104
+ LAHAN users
105
+ -- Generic
106
+ CREATE TABLE users
107
+ ```
108
+
109
+ #### Show Tables
110
+ ```sql
111
+ -- Tani
112
+ LIHAT LAHAN
113
+ -- Generic
114
+ SHOW TABLES
115
+ ```
116
+
117
+ #### Drop Table
118
+ ```sql
119
+ -- Tani
120
+ BAKAR LAHAN users
121
+ -- Generic
122
+ DROP TABLE users
123
+ ```
124
+
125
+ ### 2. Data Manipulation
126
+
127
+ #### Insert Data
128
+ ```sql
129
+ -- Tani
130
+ TANAM KE users (name, role) BIBIT ('Alice', 'Admin')
131
+ -- Generic
132
+ INSERT INTO users (name, role) VALUES ('Alice', 'Admin')
133
+ ```
134
+
135
+ #### Select Data
136
+ ```sql
137
+ -- Tani
138
+ PANEN name, role DARI users DIMANA role = 'Admin' ORDER BY name ASC LIMIT 10
139
+ -- Generic
140
+ SELECT name, role FROM users WHERE role = 'Admin' ORDER BY name ASC LIMIT 10
141
+ ```
142
+ *Operators*: `=`, `!=`, `>`, `<`, `>=`, `<=`
143
+ *Advanced*: `IN ('a','b')`, `LIKE 'pat%'`, `BETWEEN 10 AND 20`, `IS NULL`, `IS NOT NULL`
144
+
145
+ #### Pagination & Sorting
146
+ ```sql
147
+ SELECT * FROM users ORDER BY age DESC LIMIT 5 OFFSET 10
148
+ SELECT * FROM users WHERE age BETWEEN 18 AND 30 AND status IS NOT NULL
149
+ ```
150
+
151
+ #### Update Data
152
+ ```sql
153
+ -- Tani
154
+ PUPUK users DENGAN role='SuperAdmin' DIMANA name='Alice'
155
+ -- Generic
156
+ UPDATE users SET role='SuperAdmin' WHERE name='Alice'
157
+ ```
158
+
159
+ #### Delete Data
160
+ ```sql
161
+ -- Tani
162
+ GUSUR DARI users DIMANA name='Bob'
163
+ -- Generic
164
+ DELETE FROM users WHERE name='Bob'
165
+ ```
166
+
167
+ ### 3. Advanced Features
168
+
169
+ #### Indexing
170
+ ```sql
171
+ INDEKS [table] PADA [field]
172
+ -- or
173
+ CREATE INDEX ON [table] ([field])
174
+ ```
175
+
176
+ #### Aggregation & Grouping
177
+ ```sql
178
+ HITUNG COUNT(*) DARI [table]
179
+ HITUNG AVG(price) DARI [products] KELOMPOK [category]
180
+ -- Generic Keyword Alias
181
+ SELECT AVG(price) FROM [products] GROUP BY [category] (Coming Soon)
182
+ ```
183
+
184
+ ## Architecture Details
185
+
186
+ - **Modular Codebase**: Engine logic separated into `src/modules/` (`Pager.js`, `QueryParser.js`, `BTreeIndex.js`) for better maintainability.
187
+ - **Page 0 (Master Page)**: Contains header and Table Directory.
188
+ - **Data & Indexes**: Stored in 4KB atomic pages.
189
+
190
+ ## Benchmark Performance
191
+ Test Environment: Single Thread, Windows Node.js (Local NVMe)
192
+
193
+ | Operation | Ops/Sec | Latency (avg) |
194
+ |-----------|---------|---------------|
195
+ | **INSERT** | ~3,125 | 0.32 ms |
196
+ | **SELECT (PK Index)** | ~3,846 | 0.26 ms |
197
+ | **SELECT (Scan)** | ~4,762 | 0.21 ms |
198
+ | **UPDATE** | ~3,571 | 0.28 ms |
199
+
200
+ *Note: Hasil dapat bervariasi tergantung hardware.*
201
+
202
+ ## Full Feature Comparison
203
+
204
+ | Feature | Tani Edition (AQL) | Generic SQL (Standard) | Notes |
205
+ |---------|-------------------|------------------------|-------|
206
+ | **Create DB** | `BUKA WILAYAH [db]` | `CREATE DATABASE [db]` | Creates `.sawit` in data/ |
207
+ | **Use DB** | `MASUK WILAYAH [db]` | `USE [db]` | Switch context |
208
+ | **Show DBs** | `LIHAT WILAYAH` | `SHOW DATABASES` | Lists available DBs |
209
+ | **Drop DB** | `BAKAR WILAYAH [db]` | `DROP DATABASE [db]` | **Irreversible!** |
210
+ | **Create Table** | `LAHAN [table]` | `CREATE TABLE [table]` | Schema-less creation |
211
+ | **Show Tables** | `LIHAT LAHAN` | `SHOW TABLES` | Lists tables in DB |
212
+ | **Drop Table** | `BAKAR LAHAN [table]` | `DROP TABLE [table]` | Deletes table & data |
213
+ | **Insert** | `TANAM KE [table] ... BIBIT (...)` | `INSERT INTO [table] (...) VALUES (...)` | Auto-ID if omitted |
214
+ | **Select** | `PANEN ... DARI [table] DIMANA ...` | `SELECT ... FROM [table] WHERE ...` | Supports Projection |
215
+ | **Update** | `PUPUK [table] DENGAN ... DIMANA ...` | `UPDATE [table] SET ... WHERE ...` | Atomic update |
216
+ | **Delete** | `GUSUR DARI [table] DIMANA ...` | `DELETE FROM [table] WHERE ...` | Row-level deletion |
217
+ | **Index** | `INDEKS [table] PADA [field]` | `CREATE INDEX ON [table] (field)` | B-Tree Indexing |
218
+ | **Count** | `HITUNG COUNT(*) DARI [table]` | `SELECT COUNT(*) FROM [table]` (via HITUNG) | Aggregation |
219
+ | **Sum** | `HITUNG SUM(col) DARI [table]` | `SELECT SUM(col) FROM [table]` (via HITUNG) | Aggregation |
220
+ | **Average** | `HITUNG AVG(col) DARI [table]` | `SELECT AVG(col) FROM [table]` (via HITUNG) | Aggregation |
221
+
222
+ ### Supported Operators Table
223
+
224
+ | Operator | Syntax Example | Description |
225
+ |----------|----------------|-------------|
226
+ | **Comparison** | `=`, `!=`, `>`, `<`, `>=`, `<=` | Standard value comparison |
227
+ | **Logical** | `AND`, `OR` | Combine multiple conditions |
228
+ | **In List** | `IN ('coffee', 'tea')` | Matches any value in the list |
229
+ | **Not In** | `NOT IN ('water')` | Matches values NOT in list |
230
+ | **Pattern** | `LIKE 'Jwa%'` | Standard SQL wildcard matching |
231
+ | **Range** | `BETWEEN 1000 AND 5000` | Inclusive range check |
232
+ | **Null** | `IS NULL` | Check if field is empty/null |
233
+ | **Not Null** | `IS NOT NULL` | Check if field has value |
234
+ | **Limit** | `LIMIT 10` | Restrict number of rows |
235
+ | **Offset** | `OFFSET 5` | Skip first N rows (Pagination) |
236
+ | **Order** | `ORDER BY price DESC` | Sort by field (ASC/DESC) |
237
+ ## License
238
+
239
+ MIT License
240
+ <!-- ## Support Developer
241
+ - [![Saweria](https://img.shields.io/badge/Saweria-Support%20Me-orange?style=flat&logo=ko-fi)](https://saweria.co/patradev)
242
+
243
+ - **BTC**: `12EnneEriimQey3cqvxtv4ZUbvpmEbDinL`
244
+ - **BNB Smart Chain (BEP20)**: `0x471a58a2b5072cb50e3761dba3e15d19f080bdbc`
245
+ - **DOGE**: `DHrFZW6w9akaWuf8BCBGxxRLR3PegKTggF` -->
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Start SawitDB Server
5
+ *
6
+ * Usage:
7
+ * node start_server.js
8
+ *
9
+ * Environment Variables:
10
+ * SAWIT_PORT - Port to listen on (default: 7878)
11
+ * SAWIT_HOST - Host to bind to (default: 0.0.0.0)
12
+ * SAWIT_DATA_DIR - Directory for database files (default: ./data)
13
+ * SAWIT_AUTH - Enable authentication (format: username:password)
14
+ */
15
+
16
+ const SawitServer = require('../src/SawitServer');
17
+ const path = require('path');
18
+
19
+ // Parse configuration
20
+ const config = {
21
+ port: process.env.SAWIT_PORT || 7878,
22
+ host: process.env.SAWIT_HOST || '0.0.0.0',
23
+ dataDir: process.env.SAWIT_DATA_DIR || path.join(__dirname, '../data')
24
+ };
25
+
26
+ // Parse authentication if provided
27
+ if (process.env.SAWIT_AUTH) {
28
+ const [username, password] = process.env.SAWIT_AUTH.split(':');
29
+ if (username && password) {
30
+ config.auth = { [username]: password };
31
+ console.log(`[Config] Authentication enabled for user: ${username}`);
32
+ }
33
+ }
34
+
35
+ console.log('[Config] Server configuration:');
36
+ console.log(` - Port: ${config.port}`);
37
+ console.log(` - Host: ${config.host}`);
38
+ console.log(` - Data Directory: ${config.dataDir}`);
39
+ console.log(` - Auth: ${config.auth ? 'Enabled' : 'Disabled'}`);
40
+ console.log('');
41
+
42
+ // Create and start server
43
+ const server = new SawitServer(config);
44
+ server.start();
45
+
46
+ // Graceful shutdown
47
+ process.on('SIGINT', () => {
48
+ console.log('\n[Server] Received SIGINT, shutting down gracefully...');
49
+ server.stop();
50
+ setTimeout(() => process.exit(0), 1000);
51
+ });
52
+
53
+ process.on('SIGTERM', () => {
54
+ console.log('\n[Server] Received SIGTERM, shutting down gracefully...');
55
+ server.stop();
56
+ setTimeout(() => process.exit(0), 1000);
57
+ });
58
+
59
+ // Handle uncaught errors
60
+ process.on('uncaughtException', (err) => {
61
+ console.error('[Server] Uncaught Exception:', err);
62
+ server.stop();
63
+ process.exit(1);
64
+ });
65
+
66
+ process.on('unhandledRejection', (reason, promise) => {
67
+ console.error('[Server] Unhandled Rejection at:', promise, 'reason:', reason);
68
+ });
package/cli/local.js ADDED
@@ -0,0 +1,49 @@
1
+ const readline = require('readline');
2
+ const SawitDB = require('../src/WowoEngine');
3
+ const path = require('path');
4
+
5
+ const dbPath = path.join(__dirname, 'example.sawit');
6
+ const db = new SawitDB(dbPath);
7
+
8
+ const rl = readline.createInterface({
9
+ input: process.stdin,
10
+ output: process.stdout
11
+ });
12
+
13
+ console.log("--- WOWODB TANI EDITION V2 (SQL-Like) ---");
14
+ console.log("Perintah:");
15
+ console.log(" LAHAN [nama_kebun]");
16
+ console.log(" LIHAT LAHAN");
17
+ console.log(" TANAM KE [kebun] (col,...) BIBIT (val,...)");
18
+ console.log(" PANEN * DARI [kebun]");
19
+ console.log(" PANEN ... DIMANA col [=,>,<,!=] val");
20
+ console.log(" GUSUR DARI [kebun] DIMANA col = val");
21
+ console.log(" PUPUK [kebun] DENGAN col=val ... DIMANA col = val");
22
+ console.log(" BAKAR LAHAN [kebun]");
23
+ console.log("\nContoh:");
24
+ console.log(" TANAM KE sawit (id, bibit) BIBIT (1, 'Dura')");
25
+ console.log(" PANEN * DARI sawit DIMANA id > 0");
26
+ console.log(" BAKAR LAHAN karet");
27
+ console.log("Ketik 'EXIT' untuk pulang.");
28
+
29
+ function prompt() {
30
+ rl.question('petani> ', (line) => {
31
+ const cmd = line.trim();
32
+ if (cmd.toUpperCase() === 'EXIT') {
33
+ rl.close();
34
+ return;
35
+ }
36
+
37
+ if (cmd) {
38
+ const result = db.query(cmd);
39
+ if (typeof result === 'object') {
40
+ console.log(JSON.stringify(result, null, 2));
41
+ } else {
42
+ console.log(result);
43
+ }
44
+ }
45
+ prompt();
46
+ });
47
+ }
48
+
49
+ prompt();
package/cli/remote.js ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Interactive CLI Client for SawitDB
5
+ *
6
+ * Usage:
7
+ * node cli_client.js [connection_string]
8
+ *
9
+ * Example:
10
+ * node cli_client.js sawitdb://localhost:7878/mydb
11
+ * node cli_client.js sawitdb://user:pass@localhost:7878/mydb
12
+ */
13
+
14
+ const readline = require('readline');
15
+ const SawitClient = require('../src/SawitClient');
16
+
17
+ const connStr = process.argv[2] || 'sawitdb://localhost:7878/default';
18
+
19
+ console.log('╔══════════════════════════════════════════════════╗');
20
+ console.log('║ 🌴 SawitDB Client - Interactive CLI ║');
21
+ console.log('╚══════════════════════════════════════════════════╝');
22
+ console.log('');
23
+ console.log(`Connecting to: ${connStr}`);
24
+ console.log('');
25
+
26
+ const client = new SawitClient(connStr);
27
+ let rl;
28
+
29
+ async function init() {
30
+ try {
31
+ await client.connect();
32
+ console.log('✓ Connected to SawitDB server\n');
33
+ console.log('Commands:');
34
+ console.log(' LAHAN [nama] - Create table');
35
+ console.log(' LIHAT LAHAN - Show tables');
36
+ console.log(' LIHAT INDEKS [table] - Show indexes');
37
+ console.log(' TANAM KE ... - Insert data');
38
+ console.log(' PANEN ... DARI ... - Select data');
39
+ console.log(' PUPUK ... DENGAN ... - Update data');
40
+ console.log(' GUSUR DARI ... - Delete data');
41
+ console.log(' BAKAR LAHAN [nama] - Drop table');
42
+ console.log(' INDEKS [table] PADA [field] - Create index');
43
+ console.log(' HITUNG FUNC(...) DARI ... - Aggregate');
44
+ console.log(' .databases - List all databases');
45
+ console.log(' .use [db] - Switch database');
46
+ console.log(' .ping - Ping server');
47
+ console.log(' .help - Show this help');
48
+ console.log(' EXIT - Disconnect and exit');
49
+ console.log('');
50
+
51
+ rl = readline.createInterface({
52
+ input: process.stdin,
53
+ output: process.stdout
54
+ });
55
+
56
+ prompt();
57
+ } catch (error) {
58
+ console.error('Failed to connect:', error.message);
59
+ process.exit(1);
60
+ }
61
+ }
62
+
63
+ function prompt() {
64
+ rl.question(`${client.currentDatabase || 'none'}> `, async (line) => {
65
+ const cmd = line.trim();
66
+
67
+ if (!cmd) {
68
+ return prompt();
69
+ }
70
+
71
+ if (cmd.toUpperCase() === 'EXIT') {
72
+ console.log('\nDisconnecting...');
73
+ client.disconnect();
74
+ rl.close();
75
+ process.exit(0);
76
+ return;
77
+ }
78
+
79
+ // Special commands
80
+ if (cmd.startsWith('.')) {
81
+ await handleSpecialCommand(cmd);
82
+ return prompt();
83
+ }
84
+
85
+ // Regular query
86
+ try {
87
+ const result = await client.query(cmd);
88
+ if (typeof result === 'object') {
89
+ console.log(JSON.stringify(result, null, 2));
90
+ } else {
91
+ console.log(result);
92
+ }
93
+ } catch (error) {
94
+ console.error('Error:', error.message);
95
+ }
96
+
97
+ prompt();
98
+ });
99
+ }
100
+
101
+ async function handleSpecialCommand(cmd) {
102
+ const parts = cmd.split(' ');
103
+ const command = parts[0];
104
+
105
+ try {
106
+ switch (command) {
107
+ case '.databases':
108
+ const dbs = await client.listDatabases();
109
+ console.log('Databases:', dbs.join(', '));
110
+ break;
111
+
112
+ case '.use':
113
+ if (parts.length < 2) {
114
+ console.log('Usage: .use [database]');
115
+ } else {
116
+ await client.use(parts[1]);
117
+ }
118
+ break;
119
+
120
+ case '.ping':
121
+ const ping = await client.ping();
122
+ console.log(`Pong! Latency: ${ping.latency}ms`);
123
+ break;
124
+
125
+ case '.stats':
126
+ const stats = await client.stats();
127
+ console.log('\nServer Statistics:');
128
+ console.log(` Uptime: ${stats.uptimeFormatted}`);
129
+ console.log(` Total Connections: ${stats.totalConnections}`);
130
+ console.log(` Active Connections: ${stats.activeConnections}`);
131
+ console.log(` Total Queries: ${stats.totalQueries}`);
132
+ console.log(` Errors: ${stats.errors}`);
133
+ console.log(` Databases: ${stats.databases}`);
134
+ console.log(` Memory: ${Math.round(stats.memoryUsage.heapUsed / 1024 / 1024)}MB / ${Math.round(stats.memoryUsage.heapTotal / 1024 / 1024)}MB`);
135
+ break;
136
+
137
+ case '.help':
138
+ console.log('\nAvailable commands:');
139
+ console.log(' .databases - List all databases');
140
+ console.log(' .use [db] - Switch to database');
141
+ console.log(' .ping - Test connection');
142
+ console.log(' .stats - Show server statistics');
143
+ console.log(' .help - Show this help');
144
+ console.log('');
145
+ break;
146
+
147
+ default:
148
+ console.log(`Unknown command: ${command}`);
149
+ console.log('Type .help for available commands');
150
+ }
151
+ } catch (error) {
152
+ console.error('Error:', error.message);
153
+ }
154
+ }
155
+
156
+ // Start
157
+ init();
158
+
159
+ // Handle exit
160
+ process.on('SIGINT', () => {
161
+ console.log('\n\nDisconnecting...');
162
+ client.disconnect();
163
+ if (rl) rl.close();
164
+ process.exit(0);
165
+ });