Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12102255c4 | |||
| a0df731bc0 |
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-02-01 - 3.0.0 - BREAKING CHANGE(tsmdb)
|
||||||
|
rename CongoDB to TsmDB and relocate/rename wire-protocol server implementation and public exports
|
||||||
|
|
||||||
|
- Project refactor renames the in-memory wire-protocol server from CongoDB -> TsmDB (identifiers, files and namespaces changed).
|
||||||
|
- ts/index.ts now exports tsmdb instead of congodb (public API change; consumers must update imports).
|
||||||
|
- All congodb sources under ts/congodb were removed and equivalent implementations added under ts/tsmdb (errors, engines, storage adapters, server, handlers, WireProtocol, types).
|
||||||
|
- Readme and usage examples updated to reference TsmDB/tsmdb and example code updated accordingly.
|
||||||
|
- Tests renamed/updated from test.congodb.ts -> test.tsmdb.ts to exercise the new tsmdb export and server.
|
||||||
|
|
||||||
## 2026-01-31 - 2.2.0 - feat(readme)
|
## 2026-01-31 - 2.2.0 - feat(readme)
|
||||||
update README with expanded documentation covering CongoDB and SmartMongo, installation, quick start examples, architecture, usage examples, and legal/company information
|
update README with expanded documentation covering CongoDB and SmartMongo, installation, quick start examples, architecture, usage examples, and legal/company information
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartmongo",
|
"name": "@push.rocks/smartmongo",
|
||||||
"version": "2.2.0",
|
"version": "3.0.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A module for creating and managing a local MongoDB instance for testing purposes.",
|
"description": "A module for creating and managing a local MongoDB instance for testing purposes.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
|
|||||||
@@ -9,21 +9,21 @@
|
|||||||
- **Why:** Deno wraps CommonJS exports in a `default` property, so default imports are required
|
- **Why:** Deno wraps CommonJS exports in a `default` property, so default imports are required
|
||||||
- Fixed in version 2.0.13 (changed from `import * as mongoPlugin`)
|
- Fixed in version 2.0.13 (changed from `import * as mongoPlugin`)
|
||||||
|
|
||||||
## CongoDB - MongoDB Wire Protocol Server
|
## TsmDB - MongoDB Wire Protocol Server
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
CongoDB implements the MongoDB binary wire protocol (OP_MSG, OP_QUERY) allowing official MongoDB drivers to connect directly.
|
TsmDB implements the MongoDB binary wire protocol (OP_MSG, OP_QUERY) allowing official MongoDB drivers to connect directly.
|
||||||
|
|
||||||
```
|
```
|
||||||
Official MongoClient → TCP (wire protocol) → CongoServer → Engines → Storage
|
Official MongoClient → TCP (wire protocol) → TsmdbServer → Engines → Storage
|
||||||
(mongodb npm) OP_MSG/BSON (port)
|
(mongodb npm) OP_MSG/BSON (port)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Module Structure
|
### Module Structure
|
||||||
```
|
```
|
||||||
ts/congodb/
|
ts/tsmdb/
|
||||||
├── server/ # Wire protocol server
|
├── server/ # Wire protocol server
|
||||||
│ ├── CongoServer.ts # TCP server, connection handling
|
│ ├── TsmdbServer.ts # TCP server, connection handling
|
||||||
│ ├── WireProtocol.ts # OP_MSG/OP_QUERY parsing & encoding
|
│ ├── WireProtocol.ts # OP_MSG/OP_QUERY parsing & encoding
|
||||||
│ ├── CommandRouter.ts # Route commands to handlers
|
│ ├── CommandRouter.ts # Route commands to handlers
|
||||||
│ └── handlers/ # Command implementations
|
│ └── handlers/ # Command implementations
|
||||||
@@ -53,11 +53,11 @@ ts/congodb/
|
|||||||
|
|
||||||
### Usage Example
|
### Usage Example
|
||||||
```typescript
|
```typescript
|
||||||
import { CongoServer } from '@push.rocks/smartmongo/congodb';
|
import { TsmdbServer } from '@push.rocks/smartmongo/tsmdb';
|
||||||
import { MongoClient } from 'mongodb';
|
import { MongoClient } from 'mongodb';
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
const server = new CongoServer({ port: 27117 });
|
const server = new TsmdbServer({ port: 27117 });
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
// Connect with official MongoDB driver
|
// Connect with official MongoDB driver
|
||||||
@@ -82,8 +82,3 @@ await server.stop();
|
|||||||
- **Aggregation**: aggregate, count, distinct
|
- **Aggregation**: aggregate, count, distinct
|
||||||
- **Indexes**: createIndexes, dropIndexes, listIndexes
|
- **Indexes**: createIndexes, dropIndexes, listIndexes
|
||||||
- **Admin**: ping, listDatabases, listCollections, drop, dropDatabase, create, serverStatus, buildInfo
|
- **Admin**: ping, listDatabases, listCollections, drop, dropDatabase, create, serverStatus, buildInfo
|
||||||
|
|
||||||
### Notes
|
|
||||||
- The old CongoClient/CongoDb/CongoCollection classes have been removed
|
|
||||||
- Use the official `mongodb` npm package's MongoClient instead
|
|
||||||
- Server supports MongoDB wire protocol versions 0-21 (MongoDB 3.6 through 7.0 compatible)
|
|
||||||
|
|||||||
50
readme.md
50
readme.md
@@ -1,6 +1,6 @@
|
|||||||
# @push.rocks/smartmongo
|
# @push.rocks/smartmongo
|
||||||
|
|
||||||
A powerful MongoDB toolkit for testing and development — featuring both a real MongoDB memory server (**SmartMongo**) and an ultra-fast, lightweight wire-protocol-compatible in-memory database server (**CongoDB**). 🚀
|
A powerful MongoDB toolkit for testing and development — featuring both a real MongoDB memory server (**SmartMongo**) and an ultra-fast, lightweight wire-protocol-compatible in-memory database server (**TsmDB**). 🚀
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|||||||
|
|
||||||
`@push.rocks/smartmongo` provides two powerful approaches for MongoDB in testing and development:
|
`@push.rocks/smartmongo` provides two powerful approaches for MongoDB in testing and development:
|
||||||
|
|
||||||
| Feature | SmartMongo | CongoDB |
|
| Feature | SmartMongo | TsmDB |
|
||||||
|---------|------------|---------|
|
|---------|------------|---------|
|
||||||
| **Type** | Real MongoDB (memory server) | Pure TypeScript wire protocol server |
|
| **Type** | Real MongoDB (memory server) | Pure TypeScript wire protocol server |
|
||||||
| **Speed** | ~2-5s startup | ⚡ Instant startup (~5ms) |
|
| **Speed** | ~2-5s startup | ⚡ Instant startup (~5ms) |
|
||||||
@@ -51,16 +51,16 @@ console.log(descriptor.mongoDbUrl); // mongodb://127.0.0.1:xxxxx/...
|
|||||||
await mongo.stop();
|
await mongo.stop();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option 2: CongoDB (Wire Protocol Server)
|
### Option 2: TsmDB (Wire Protocol Server)
|
||||||
|
|
||||||
A lightweight, pure TypeScript MongoDB-compatible server that speaks the wire protocol — use the official `mongodb` driver directly!
|
A lightweight, pure TypeScript MongoDB-compatible server that speaks the wire protocol — use the official `mongodb` driver directly!
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { congodb } from '@push.rocks/smartmongo';
|
import { tsmdb } from '@push.rocks/smartmongo';
|
||||||
import { MongoClient } from 'mongodb';
|
import { MongoClient } from 'mongodb';
|
||||||
|
|
||||||
// Start CongoDB server
|
// Start TsmDB server
|
||||||
const server = new congodb.CongoServer({ port: 27017 });
|
const server = new tsmdb.TsmdbServer({ port: 27017 });
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
// Connect with the official MongoDB driver!
|
// Connect with the official MongoDB driver!
|
||||||
@@ -116,14 +116,14 @@ await mongo.stopAndDumpToDir('./test-data');
|
|||||||
await mongo.stopAndDumpToDir('./test-data', (doc) => `${doc.collection}-${doc._id}.bson`);
|
await mongo.stopAndDumpToDir('./test-data', (doc) => `${doc.collection}-${doc._id}.bson`);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔧 CongoDB API
|
## 🔧 TsmDB API
|
||||||
|
|
||||||
### Server Configuration
|
### Server Configuration
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { congodb } from '@push.rocks/smartmongo';
|
import { tsmdb } from '@push.rocks/smartmongo';
|
||||||
|
|
||||||
const server = new congodb.CongoServer({
|
const server = new tsmdb.TsmdbServer({
|
||||||
port: 27017, // Default MongoDB port
|
port: 27017, // Default MongoDB port
|
||||||
host: '127.0.0.1', // Bind address
|
host: '127.0.0.1', // Bind address
|
||||||
storage: 'memory', // 'memory' or 'file'
|
storage: 'memory', // 'memory' or 'file'
|
||||||
@@ -143,7 +143,7 @@ await server.stop();
|
|||||||
|
|
||||||
### Supported MongoDB Operations
|
### Supported MongoDB Operations
|
||||||
|
|
||||||
CongoDB supports the core MongoDB operations via the wire protocol:
|
TsmDB supports the core MongoDB operations via the wire protocol:
|
||||||
|
|
||||||
#### 🔹 CRUD Operations
|
#### 🔹 CRUD Operations
|
||||||
```typescript
|
```typescript
|
||||||
@@ -279,23 +279,23 @@ console.log(result.deletedCount); // 1
|
|||||||
|
|
||||||
### Storage Adapters
|
### Storage Adapters
|
||||||
|
|
||||||
CongoDB supports pluggable storage:
|
TsmDB supports pluggable storage:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// In-memory (default) - fast, data lost on stop
|
// In-memory (default) - fast, data lost on stop
|
||||||
const server = new congodb.CongoServer({ storage: 'memory' });
|
const server = new tsmdb.TsmdbServer({ storage: 'memory' });
|
||||||
|
|
||||||
// In-memory with persistence - periodic snapshots to disk
|
// In-memory with persistence - periodic snapshots to disk
|
||||||
const server = new congodb.CongoServer({
|
const server = new tsmdb.TsmdbServer({
|
||||||
storage: 'memory',
|
storage: 'memory',
|
||||||
persistPath: './data/snapshot.json',
|
persistPath: './data/snapshot.json',
|
||||||
persistIntervalMs: 30000 // Save every 30 seconds
|
persistIntervalMs: 30000 // Save every 30 seconds
|
||||||
});
|
});
|
||||||
|
|
||||||
// File-based - persistent storage
|
// File-based - persistent storage
|
||||||
const server = new congodb.CongoServer({
|
const server = new tsmdb.TsmdbServer({
|
||||||
storage: 'file',
|
storage: 'file',
|
||||||
storagePath: './data/congodb'
|
storagePath: './data/tsmdb'
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -309,22 +309,22 @@ const server = new congodb.CongoServer({
|
|||||||
| **Indexes** | `createIndexes`, `dropIndexes`, `listIndexes` |
|
| **Indexes** | `createIndexes`, `dropIndexes`, `listIndexes` |
|
||||||
| **Admin** | `ping`, `listDatabases`, `listCollections`, `drop`, `dropDatabase`, `create`, `serverStatus`, `buildInfo` |
|
| **Admin** | `ping`, `listDatabases`, `listCollections`, `drop`, `dropDatabase`, `create`, `serverStatus`, `buildInfo` |
|
||||||
|
|
||||||
CongoDB supports MongoDB wire protocol versions 0-21, compatible with MongoDB 3.6 through 7.0 drivers.
|
TsmDB supports MongoDB wire protocol versions 0-21, compatible with MongoDB 3.6 through 7.0 drivers.
|
||||||
|
|
||||||
## 🧪 Testing Examples
|
## 🧪 Testing Examples
|
||||||
|
|
||||||
### Jest/Mocha with CongoDB
|
### Jest/Mocha with TsmDB
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { congodb } from '@push.rocks/smartmongo';
|
import { tsmdb } from '@push.rocks/smartmongo';
|
||||||
import { MongoClient } from 'mongodb';
|
import { MongoClient } from 'mongodb';
|
||||||
|
|
||||||
let server: congodb.CongoServer;
|
let server: tsmdb.TsmdbServer;
|
||||||
let client: MongoClient;
|
let client: MongoClient;
|
||||||
let db: Db;
|
let db: Db;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
server = new congodb.CongoServer({ port: 27117 });
|
server = new tsmdb.TsmdbServer({ port: 27117 });
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
client = new MongoClient('mongodb://127.0.0.1:27117');
|
client = new MongoClient('mongodb://127.0.0.1:27117');
|
||||||
@@ -355,14 +355,14 @@ test('should insert and find user', async () => {
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||||
import { congodb } from '@push.rocks/smartmongo';
|
import { tsmdb } from '@push.rocks/smartmongo';
|
||||||
import { MongoClient } from 'mongodb';
|
import { MongoClient } from 'mongodb';
|
||||||
|
|
||||||
let server: congodb.CongoServer;
|
let server: tsmdb.TsmdbServer;
|
||||||
let client: MongoClient;
|
let client: MongoClient;
|
||||||
|
|
||||||
tap.test('setup', async () => {
|
tap.test('setup', async () => {
|
||||||
server = new congodb.CongoServer({ port: 27117 });
|
server = new tsmdb.TsmdbServer({ port: 27117 });
|
||||||
await server.start();
|
await server.start();
|
||||||
client = new MongoClient('mongodb://127.0.0.1:27117');
|
client = new MongoClient('mongodb://127.0.0.1:27117');
|
||||||
await client.connect();
|
await client.connect();
|
||||||
@@ -401,7 +401,7 @@ export default tap.start();
|
|||||||
|
|
||||||
## 🏗️ Architecture
|
## 🏗️ Architecture
|
||||||
|
|
||||||
### CongoDB Wire Protocol Stack
|
### TsmDB Wire Protocol Stack
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
@@ -411,7 +411,7 @@ export default tap.start();
|
|||||||
│ TCP + OP_MSG/BSON
|
│ TCP + OP_MSG/BSON
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
│ CongoServer │
|
│ TsmdbServer │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
||||||
│ │ WireProtocol │→ │CommandRouter │→ │ Handlers │ │
|
│ │ WireProtocol │→ │CommandRouter │→ │ Handlers │ │
|
||||||
│ │ (OP_MSG) │ │ │ │ (Find, Insert..) │ │
|
│ │ (OP_MSG) │ │ │ │ (Find, Insert..) │ │
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|||||||
import * as smartmongo from '../ts/index.js';
|
import * as smartmongo from '../ts/index.js';
|
||||||
import { MongoClient, Db, Collection } from 'mongodb';
|
import { MongoClient, Db, Collection } from 'mongodb';
|
||||||
|
|
||||||
const { congodb } = smartmongo;
|
const { tsmdb } = smartmongo;
|
||||||
|
|
||||||
let server: smartmongo.congodb.CongoServer;
|
let server: smartmongo.tsmdb.TsmdbServer;
|
||||||
let client: MongoClient;
|
let client: MongoClient;
|
||||||
let db: Db;
|
let db: Db;
|
||||||
|
|
||||||
@@ -12,13 +12,13 @@ let db: Db;
|
|||||||
// Server Startup
|
// Server Startup
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: should start the server', async () => {
|
tap.test('tsmdb: should start the server', async () => {
|
||||||
server = new congodb.CongoServer({ port: 27117 }); // Use non-standard port for tests
|
server = new tsmdb.TsmdbServer({ port: 27117 }); // Use non-standard port for tests
|
||||||
await server.start();
|
await server.start();
|
||||||
expect(server.running).toBeTrue();
|
expect(server.running).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: should connect with official MongoClient', async () => {
|
tap.test('tsmdb: should connect with official MongoClient', async () => {
|
||||||
client = new MongoClient('mongodb://127.0.0.1:27117', {
|
client = new MongoClient('mongodb://127.0.0.1:27117', {
|
||||||
directConnection: true,
|
directConnection: true,
|
||||||
serverSelectionTimeoutMS: 5000,
|
serverSelectionTimeoutMS: 5000,
|
||||||
@@ -27,7 +27,7 @@ tap.test('congodb: should connect with official MongoClient', async () => {
|
|||||||
expect(client).toBeTruthy();
|
expect(client).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: should get a database instance', async () => {
|
tap.test('tsmdb: should get a database instance', async () => {
|
||||||
db = client.db('testdb');
|
db = client.db('testdb');
|
||||||
expect(db).toBeTruthy();
|
expect(db).toBeTruthy();
|
||||||
expect(db.databaseName).toEqual('testdb');
|
expect(db.databaseName).toEqual('testdb');
|
||||||
@@ -37,7 +37,7 @@ tap.test('congodb: should get a database instance', async () => {
|
|||||||
// Basic CRUD Tests
|
// Basic CRUD Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: insertOne - should insert a document', async () => {
|
tap.test('tsmdb: insertOne - should insert a document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.insertOne({
|
const result = await collection.insertOne({
|
||||||
name: 'John Doe',
|
name: 'John Doe',
|
||||||
@@ -49,7 +49,7 @@ tap.test('congodb: insertOne - should insert a document', async () => {
|
|||||||
expect(result.insertedId).toBeTruthy();
|
expect(result.insertedId).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: insertMany - should insert multiple documents', async () => {
|
tap.test('tsmdb: insertMany - should insert multiple documents', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.insertMany([
|
const result = await collection.insertMany([
|
||||||
{ name: 'Jane Doe', email: 'jane@example.com', age: 25 },
|
{ name: 'Jane Doe', email: 'jane@example.com', age: 25 },
|
||||||
@@ -62,7 +62,7 @@ tap.test('congodb: insertMany - should insert multiple documents', async () => {
|
|||||||
expect(Object.keys(result.insertedIds).length).toEqual(3);
|
expect(Object.keys(result.insertedIds).length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: findOne - should find a single document', async () => {
|
tap.test('tsmdb: findOne - should find a single document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const doc = await collection.findOne({ name: 'John Doe' });
|
const doc = await collection.findOne({ name: 'John Doe' });
|
||||||
|
|
||||||
@@ -71,14 +71,14 @@ tap.test('congodb: findOne - should find a single document', async () => {
|
|||||||
expect(doc!.email).toEqual('john@example.com');
|
expect(doc!.email).toEqual('john@example.com');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: find - should find multiple documents', async () => {
|
tap.test('tsmdb: find - should find multiple documents', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ age: { $gte: 28 } }).toArray();
|
const docs = await collection.find({ age: { $gte: 28 } }).toArray();
|
||||||
|
|
||||||
expect(docs.length).toEqual(3);
|
expect(docs.length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: updateOne - should update a single document', async () => {
|
tap.test('tsmdb: updateOne - should update a single document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.updateOne(
|
const result = await collection.updateOne(
|
||||||
{ name: 'John Doe' },
|
{ name: 'John Doe' },
|
||||||
@@ -93,7 +93,7 @@ tap.test('congodb: updateOne - should update a single document', async () => {
|
|||||||
expect(updated!.age).toEqual(31);
|
expect(updated!.age).toEqual(31);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: updateMany - should update multiple documents', async () => {
|
tap.test('tsmdb: updateMany - should update multiple documents', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.updateMany(
|
const result = await collection.updateMany(
|
||||||
{ age: { $gte: 30 } },
|
{ age: { $gte: 30 } },
|
||||||
@@ -105,7 +105,7 @@ tap.test('congodb: updateMany - should update multiple documents', async () => {
|
|||||||
expect(result.modifiedCount).toEqual(2);
|
expect(result.modifiedCount).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: deleteOne - should delete a single document', async () => {
|
tap.test('tsmdb: deleteOne - should delete a single document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.deleteOne({ name: 'Bob Smith' });
|
const result = await collection.deleteOne({ name: 'Bob Smith' });
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ tap.test('congodb: deleteOne - should delete a single document', async () => {
|
|||||||
expect(result.deletedCount).toEqual(1);
|
expect(result.deletedCount).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: deleteMany - should delete multiple documents', async () => {
|
tap.test('tsmdb: deleteMany - should delete multiple documents', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
|
|
||||||
// First add some test docs to delete
|
// First add some test docs to delete
|
||||||
@@ -132,32 +132,32 @@ tap.test('congodb: deleteMany - should delete multiple documents', async () => {
|
|||||||
// Query Operator Tests
|
// Query Operator Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: query - $eq operator', async () => {
|
tap.test('tsmdb: query - $eq operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ name: { $eq: 'Jane Doe' } }).toArray();
|
const docs = await collection.find({ name: { $eq: 'Jane Doe' } }).toArray();
|
||||||
expect(docs.length).toEqual(1);
|
expect(docs.length).toEqual(1);
|
||||||
expect(docs[0].name).toEqual('Jane Doe');
|
expect(docs[0].name).toEqual('Jane Doe');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $ne operator', async () => {
|
tap.test('tsmdb: query - $ne operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ name: { $ne: 'Jane Doe' } }).toArray();
|
const docs = await collection.find({ name: { $ne: 'Jane Doe' } }).toArray();
|
||||||
expect(docs.every(d => d.name !== 'Jane Doe')).toBeTrue();
|
expect(docs.every(d => d.name !== 'Jane Doe')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $gt and $lt operators', async () => {
|
tap.test('tsmdb: query - $gt and $lt operators', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ age: { $gt: 25, $lt: 35 } }).toArray();
|
const docs = await collection.find({ age: { $gt: 25, $lt: 35 } }).toArray();
|
||||||
expect(docs.every(d => d.age > 25 && d.age < 35)).toBeTrue();
|
expect(docs.every(d => d.age > 25 && d.age < 35)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $in operator', async () => {
|
tap.test('tsmdb: query - $in operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ name: { $in: ['Jane Doe', 'Alice Johnson'] } }).toArray();
|
const docs = await collection.find({ name: { $in: ['Jane Doe', 'Alice Johnson'] } }).toArray();
|
||||||
expect(docs.length).toEqual(2);
|
expect(docs.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $or operator', async () => {
|
tap.test('tsmdb: query - $or operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({
|
const docs = await collection.find({
|
||||||
$or: [
|
$or: [
|
||||||
@@ -168,7 +168,7 @@ tap.test('congodb: query - $or operator', async () => {
|
|||||||
expect(docs.length).toBeGreaterThanOrEqual(1);
|
expect(docs.length).toBeGreaterThanOrEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $and operator', async () => {
|
tap.test('tsmdb: query - $and operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({
|
const docs = await collection.find({
|
||||||
$and: [
|
$and: [
|
||||||
@@ -179,7 +179,7 @@ tap.test('congodb: query - $and operator', async () => {
|
|||||||
expect(docs.every(d => d.age >= 25 && d.age <= 30)).toBeTrue();
|
expect(docs.every(d => d.age >= 25 && d.age <= 30)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: query - $exists operator', async () => {
|
tap.test('tsmdb: query - $exists operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({ senior: { $exists: true } }).toArray();
|
const docs = await collection.find({ senior: { $exists: true } }).toArray();
|
||||||
expect(docs.every(d => 'senior' in d)).toBeTrue();
|
expect(docs.every(d => 'senior' in d)).toBeTrue();
|
||||||
@@ -189,7 +189,7 @@ tap.test('congodb: query - $exists operator', async () => {
|
|||||||
// Update Operator Tests
|
// Update Operator Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: update - $inc operator', async () => {
|
tap.test('tsmdb: update - $inc operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
await collection.updateOne(
|
await collection.updateOne(
|
||||||
{ name: 'Jane Doe' },
|
{ name: 'Jane Doe' },
|
||||||
@@ -200,7 +200,7 @@ tap.test('congodb: update - $inc operator', async () => {
|
|||||||
expect(updated!.age).toEqual(26);
|
expect(updated!.age).toEqual(26);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: update - $unset operator', async () => {
|
tap.test('tsmdb: update - $unset operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
await collection.updateOne(
|
await collection.updateOne(
|
||||||
{ name: 'Jane Doe' },
|
{ name: 'Jane Doe' },
|
||||||
@@ -211,7 +211,7 @@ tap.test('congodb: update - $unset operator', async () => {
|
|||||||
expect('senior' in updated!).toBeFalse();
|
expect('senior' in updated!).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: update - $push operator', async () => {
|
tap.test('tsmdb: update - $push operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
await collection.updateOne(
|
await collection.updateOne(
|
||||||
{ name: 'Jane Doe' },
|
{ name: 'Jane Doe' },
|
||||||
@@ -227,7 +227,7 @@ tap.test('congodb: update - $push operator', async () => {
|
|||||||
expect(updated!.tags).toContain('tester');
|
expect(updated!.tags).toContain('tester');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: update - $pull operator', async () => {
|
tap.test('tsmdb: update - $pull operator', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
await collection.updateOne(
|
await collection.updateOne(
|
||||||
{ name: 'Jane Doe' },
|
{ name: 'Jane Doe' },
|
||||||
@@ -238,7 +238,7 @@ tap.test('congodb: update - $pull operator', async () => {
|
|||||||
expect(updated!.tags).not.toContain('tester');
|
expect(updated!.tags).not.toContain('tester');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: update - upsert creates new document', async () => {
|
tap.test('tsmdb: update - upsert creates new document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.updateOne(
|
const result = await collection.updateOne(
|
||||||
{ name: 'New User' },
|
{ name: 'New User' },
|
||||||
@@ -258,7 +258,7 @@ tap.test('congodb: update - upsert creates new document', async () => {
|
|||||||
// Cursor Tests
|
// Cursor Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: cursor - sort', async () => {
|
tap.test('tsmdb: cursor - sort', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({}).sort({ age: -1 }).toArray();
|
const docs = await collection.find({}).sort({ age: -1 }).toArray();
|
||||||
|
|
||||||
@@ -269,13 +269,13 @@ tap.test('congodb: cursor - sort', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: cursor - limit', async () => {
|
tap.test('tsmdb: cursor - limit', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({}).limit(2).toArray();
|
const docs = await collection.find({}).limit(2).toArray();
|
||||||
expect(docs.length).toBeLessThanOrEqual(2);
|
expect(docs.length).toBeLessThanOrEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: cursor - skip', async () => {
|
tap.test('tsmdb: cursor - skip', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const allDocs = await collection.find({}).toArray();
|
const allDocs = await collection.find({}).toArray();
|
||||||
const skippedDocs = await collection.find({}).skip(1).toArray();
|
const skippedDocs = await collection.find({}).skip(1).toArray();
|
||||||
@@ -283,7 +283,7 @@ tap.test('congodb: cursor - skip', async () => {
|
|||||||
expect(skippedDocs.length).toEqual(Math.max(0, allDocs.length - 1));
|
expect(skippedDocs.length).toEqual(Math.max(0, allDocs.length - 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: cursor - project', async () => {
|
tap.test('tsmdb: cursor - project', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const docs = await collection.find({}).project({ name: 1, _id: 0 }).toArray();
|
const docs = await collection.find({}).project({ name: 1, _id: 0 }).toArray();
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ tap.test('congodb: cursor - project', async () => {
|
|||||||
// FindOneAnd* Tests
|
// FindOneAnd* Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: findOneAndUpdate - returns updated document', async () => {
|
tap.test('tsmdb: findOneAndUpdate - returns updated document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const result = await collection.findOneAndUpdate(
|
const result = await collection.findOneAndUpdate(
|
||||||
{ name: 'Jane Doe' },
|
{ name: 'Jane Doe' },
|
||||||
@@ -308,7 +308,7 @@ tap.test('congodb: findOneAndUpdate - returns updated document', async () => {
|
|||||||
expect(result!.status).toEqual('active');
|
expect(result!.status).toEqual('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: findOneAndDelete - returns deleted document', async () => {
|
tap.test('tsmdb: findOneAndDelete - returns deleted document', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
|
|
||||||
// Insert a temp doc to delete
|
// Insert a temp doc to delete
|
||||||
@@ -328,19 +328,19 @@ tap.test('congodb: findOneAndDelete - returns deleted document', async () => {
|
|||||||
// Count and Distinct Tests
|
// Count and Distinct Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: countDocuments - counts matching documents', async () => {
|
tap.test('tsmdb: countDocuments - counts matching documents', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const count = await collection.countDocuments({ age: { $gte: 25 } });
|
const count = await collection.countDocuments({ age: { $gte: 25 } });
|
||||||
expect(count).toBeGreaterThan(0);
|
expect(count).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: estimatedDocumentCount - returns total count', async () => {
|
tap.test('tsmdb: estimatedDocumentCount - returns total count', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const count = await collection.estimatedDocumentCount();
|
const count = await collection.estimatedDocumentCount();
|
||||||
expect(count).toBeGreaterThan(0);
|
expect(count).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: distinct - returns unique values', async () => {
|
tap.test('tsmdb: distinct - returns unique values', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const names = await collection.distinct('name');
|
const names = await collection.distinct('name');
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ tap.test('congodb: distinct - returns unique values', async () => {
|
|||||||
// Index Tests
|
// Index Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: createIndex - creates a single index', async () => {
|
tap.test('tsmdb: createIndex - creates a single index', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const indexName = await collection.createIndex({ email: 1 });
|
const indexName = await collection.createIndex({ email: 1 });
|
||||||
|
|
||||||
@@ -361,14 +361,14 @@ tap.test('congodb: createIndex - creates a single index', async () => {
|
|||||||
expect(indexName).toContain('email');
|
expect(indexName).toContain('email');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: createIndex - creates compound index', async () => {
|
tap.test('tsmdb: createIndex - creates compound index', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const indexName = await collection.createIndex({ name: 1, age: -1 });
|
const indexName = await collection.createIndex({ name: 1, age: -1 });
|
||||||
|
|
||||||
expect(indexName).toBeTruthy();
|
expect(indexName).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: listIndexes - lists all indexes', async () => {
|
tap.test('tsmdb: listIndexes - lists all indexes', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const indexes = await collection.listIndexes().toArray();
|
const indexes = await collection.listIndexes().toArray();
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ tap.test('congodb: listIndexes - lists all indexes', async () => {
|
|||||||
expect(indexes.some(i => i.name === '_id_')).toBeTrue();
|
expect(indexes.some(i => i.name === '_id_')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: dropIndex - drops an index', async () => {
|
tap.test('tsmdb: dropIndex - drops an index', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const indexName = await collection.createIndex({ toDropField: 1 });
|
const indexName = await collection.createIndex({ toDropField: 1 });
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ tap.test('congodb: dropIndex - drops an index', async () => {
|
|||||||
// Aggregation Tests
|
// Aggregation Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: aggregate - $match stage', async () => {
|
tap.test('tsmdb: aggregate - $match stage', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const results = await collection.aggregate([
|
const results = await collection.aggregate([
|
||||||
{ $match: { age: { $gte: 25 } } }
|
{ $match: { age: { $gte: 25 } } }
|
||||||
@@ -400,7 +400,7 @@ tap.test('congodb: aggregate - $match stage', async () => {
|
|||||||
expect(results.every(d => d.age >= 25)).toBeTrue();
|
expect(results.every(d => d.age >= 25)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: aggregate - $project stage', async () => {
|
tap.test('tsmdb: aggregate - $project stage', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const results = await collection.aggregate([
|
const results = await collection.aggregate([
|
||||||
{ $project: { name: 1, _id: 0 } }
|
{ $project: { name: 1, _id: 0 } }
|
||||||
@@ -411,7 +411,7 @@ tap.test('congodb: aggregate - $project stage', async () => {
|
|||||||
expect(results[0].email).toBeUndefined();
|
expect(results[0].email).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: aggregate - $sort stage', async () => {
|
tap.test('tsmdb: aggregate - $sort stage', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const results = await collection.aggregate([
|
const results = await collection.aggregate([
|
||||||
{ $match: { age: { $exists: true } } },
|
{ $match: { age: { $exists: true } } },
|
||||||
@@ -423,7 +423,7 @@ tap.test('congodb: aggregate - $sort stage', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: aggregate - $group stage', async () => {
|
tap.test('tsmdb: aggregate - $group stage', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
|
|
||||||
// Add some categorized data
|
// Add some categorized data
|
||||||
@@ -445,7 +445,7 @@ tap.test('congodb: aggregate - $group stage', async () => {
|
|||||||
expect(groupB!.total).toEqual(30);
|
expect(groupB!.total).toEqual(30);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: aggregate - $limit and $skip stages', async () => {
|
tap.test('tsmdb: aggregate - $limit and $skip stages', async () => {
|
||||||
const collection = db.collection('users');
|
const collection = db.collection('users');
|
||||||
const results = await collection.aggregate([
|
const results = await collection.aggregate([
|
||||||
{ $skip: 1 },
|
{ $skip: 1 },
|
||||||
@@ -459,7 +459,7 @@ tap.test('congodb: aggregate - $limit and $skip stages', async () => {
|
|||||||
// Bulk Operations Tests
|
// Bulk Operations Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: bulkWrite - executes multiple operations', async () => {
|
tap.test('tsmdb: bulkWrite - executes multiple operations', async () => {
|
||||||
const collection = db.collection('bulktest');
|
const collection = db.collection('bulktest');
|
||||||
|
|
||||||
const result = await collection.bulkWrite([
|
const result = await collection.bulkWrite([
|
||||||
@@ -476,18 +476,18 @@ tap.test('congodb: bulkWrite - executes multiple operations', async () => {
|
|||||||
// Database Operations Tests
|
// Database Operations Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: listCollections - lists all collections', async () => {
|
tap.test('tsmdb: listCollections - lists all collections', async () => {
|
||||||
const collections = await db.listCollections().toArray();
|
const collections = await db.listCollections().toArray();
|
||||||
expect(collections.length).toBeGreaterThan(0);
|
expect(collections.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: createCollection - creates a new collection', async () => {
|
tap.test('tsmdb: createCollection - creates a new collection', async () => {
|
||||||
await db.createCollection('newcollection');
|
await db.createCollection('newcollection');
|
||||||
const collections = await db.listCollections().toArray();
|
const collections = await db.listCollections().toArray();
|
||||||
expect(collections.some(c => c.name === 'newcollection')).toBeTrue();
|
expect(collections.some(c => c.name === 'newcollection')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: dropCollection - drops a collection', async () => {
|
tap.test('tsmdb: dropCollection - drops a collection', async () => {
|
||||||
await db.createCollection('todrop');
|
await db.createCollection('todrop');
|
||||||
await db.dropCollection('todrop');
|
await db.dropCollection('todrop');
|
||||||
const collections = await db.listCollections().toArray();
|
const collections = await db.listCollections().toArray();
|
||||||
@@ -498,20 +498,20 @@ tap.test('congodb: dropCollection - drops a collection', async () => {
|
|||||||
// Admin Tests
|
// Admin Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: admin - listDatabases', async () => {
|
tap.test('tsmdb: admin - listDatabases', async () => {
|
||||||
const admin = client.db().admin();
|
const admin = client.db().admin();
|
||||||
const result = await admin.listDatabases();
|
const result = await admin.listDatabases();
|
||||||
expect(result.ok).toEqual(1);
|
expect(result.ok).toEqual(1);
|
||||||
expect(result.databases).toBeArray();
|
expect(result.databases).toBeArray();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: admin - serverStatus', async () => {
|
tap.test('tsmdb: admin - serverStatus', async () => {
|
||||||
const admin = client.db().admin();
|
const admin = client.db().admin();
|
||||||
const status = await admin.serverStatus();
|
const status = await admin.serverStatus();
|
||||||
expect(status.ok).toEqual(1);
|
expect(status.ok).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: admin - ping', async () => {
|
tap.test('tsmdb: admin - ping', async () => {
|
||||||
const admin = client.db().admin();
|
const admin = client.db().admin();
|
||||||
const result = await admin.ping();
|
const result = await admin.ping();
|
||||||
expect(result.ok).toEqual(1);
|
expect(result.ok).toEqual(1);
|
||||||
@@ -521,7 +521,7 @@ tap.test('congodb: admin - ping', async () => {
|
|||||||
// Replace Operations Tests
|
// Replace Operations Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: replaceOne - replaces entire document', async () => {
|
tap.test('tsmdb: replaceOne - replaces entire document', async () => {
|
||||||
const collection = db.collection('replacetest');
|
const collection = db.collection('replacetest');
|
||||||
await collection.insertOne({ name: 'Original', field1: 'value1', field2: 'value2' });
|
await collection.insertOne({ name: 'Original', field1: 'value1', field2: 'value2' });
|
||||||
|
|
||||||
@@ -540,7 +540,7 @@ tap.test('congodb: replaceOne - replaces entire document', async () => {
|
|||||||
expect(replaced!.field2).toBeUndefined();
|
expect(replaced!.field2).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: findOneAndReplace - returns replaced document', async () => {
|
tap.test('tsmdb: findOneAndReplace - returns replaced document', async () => {
|
||||||
const collection = db.collection('replacetest');
|
const collection = db.collection('replacetest');
|
||||||
await collection.insertOne({ name: 'ToReplace', data: 'old' });
|
await collection.insertOne({ name: 'ToReplace', data: 'old' });
|
||||||
|
|
||||||
@@ -558,12 +558,12 @@ tap.test('congodb: findOneAndReplace - returns replaced document', async () => {
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
tap.test('congodb: cleanup - drop database', async () => {
|
tap.test('tsmdb: cleanup - drop database', async () => {
|
||||||
const result = await db.dropDatabase();
|
const result = await db.dropDatabase();
|
||||||
expect(result).toBeTrue();
|
expect(result).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('congodb: cleanup - close client and server', async () => {
|
tap.test('tsmdb: cleanup - close client and server', async () => {
|
||||||
await client.close();
|
await client.close();
|
||||||
await server.stop();
|
await server.stop();
|
||||||
expect(server.running).toBeFalse();
|
expect(server.running).toBeFalse();
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartmongo',
|
name: '@push.rocks/smartmongo',
|
||||||
version: '2.2.0',
|
version: '3.0.0',
|
||||||
description: 'A module for creating and managing a local MongoDB instance for testing purposes.'
|
description: 'A module for creating and managing a local MongoDB instance for testing purposes.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { commitinfo } from './00_commitinfo_data.js';
|
import { commitinfo } from './00_commitinfo_data.js';
|
||||||
import * as plugins from './smartmongo.plugins.js';
|
import * as plugins from './smartmongo.plugins.js';
|
||||||
|
|
||||||
// Export CongoDB module
|
// Export TsmDB module
|
||||||
export * as congodb from './congodb/index.js';
|
export * as tsmdb from './tsmdb/index.js';
|
||||||
|
|
||||||
export class SmartMongo {
|
export class SmartMongo {
|
||||||
// STATIC
|
// STATIC
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { Document, IStoredDocument, IAggregateOptions } from '../types/interfaces.js';
|
import type { Document, IStoredDocument, IAggregateOptions } from '../types/interfaces.js';
|
||||||
|
|
||||||
// Import mingo Aggregator
|
// Import mingo Aggregator
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
||||||
import type {
|
import type {
|
||||||
Document,
|
Document,
|
||||||
@@ -7,7 +7,7 @@ import type {
|
|||||||
IIndexInfo,
|
IIndexInfo,
|
||||||
ICreateIndexOptions,
|
ICreateIndexOptions,
|
||||||
} from '../types/interfaces.js';
|
} from '../types/interfaces.js';
|
||||||
import { CongoDuplicateKeyError, CongoIndexError } from '../errors/CongoErrors.js';
|
import { TsmdbDuplicateKeyError, TsmdbIndexError } from '../errors/TsmdbErrors.js';
|
||||||
import { QueryEngine } from './QueryEngine.js';
|
import { QueryEngine } from './QueryEngine.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +116,7 @@ export class IndexEngine {
|
|||||||
const keyStr = JSON.stringify(keyValue);
|
const keyStr = JSON.stringify(keyValue);
|
||||||
|
|
||||||
if (indexData.unique && indexData.entries.has(keyStr)) {
|
if (indexData.unique && indexData.entries.has(keyStr)) {
|
||||||
throw new CongoDuplicateKeyError(
|
throw new TsmdbDuplicateKeyError(
|
||||||
`E11000 duplicate key error index: ${this.dbName}.${this.collName}.$${name}`,
|
`E11000 duplicate key error index: ${this.dbName}.${this.collName}.$${name}`,
|
||||||
key as Record<string, 1>,
|
key as Record<string, 1>,
|
||||||
keyValue
|
keyValue
|
||||||
@@ -148,11 +148,11 @@ export class IndexEngine {
|
|||||||
await this.initialize();
|
await this.initialize();
|
||||||
|
|
||||||
if (name === '_id_') {
|
if (name === '_id_') {
|
||||||
throw new CongoIndexError('cannot drop _id index');
|
throw new TsmdbIndexError('cannot drop _id index');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.indexes.has(name)) {
|
if (!this.indexes.has(name)) {
|
||||||
throw new CongoIndexError(`index not found: ${name}`);
|
throw new TsmdbIndexError(`index not found: ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.indexes.delete(name);
|
this.indexes.delete(name);
|
||||||
@@ -215,7 +215,7 @@ export class IndexEngine {
|
|||||||
if (indexData.unique) {
|
if (indexData.unique) {
|
||||||
const existing = indexData.entries.get(keyStr);
|
const existing = indexData.entries.get(keyStr);
|
||||||
if (existing && existing.size > 0) {
|
if (existing && existing.size > 0) {
|
||||||
throw new CongoDuplicateKeyError(
|
throw new TsmdbDuplicateKeyError(
|
||||||
`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`,
|
`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`,
|
||||||
indexData.key as Record<string, 1>,
|
indexData.key as Record<string, 1>,
|
||||||
keyValue
|
keyValue
|
||||||
@@ -260,7 +260,7 @@ export class IndexEngine {
|
|||||||
if (indexData.unique) {
|
if (indexData.unique) {
|
||||||
const existing = indexData.entries.get(newKeyStr);
|
const existing = indexData.entries.get(newKeyStr);
|
||||||
if (existing && existing.size > 0) {
|
if (existing && existing.size > 0) {
|
||||||
throw new CongoDuplicateKeyError(
|
throw new TsmdbDuplicateKeyError(
|
||||||
`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`,
|
`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`,
|
||||||
indexData.key as Record<string, 1>,
|
indexData.key as Record<string, 1>,
|
||||||
newKeyValue
|
newKeyValue
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { Document, IStoredDocument, ISortSpecification, ISortDirection } from '../types/interfaces.js';
|
import type { Document, IStoredDocument, ISortSpecification, ISortDirection } from '../types/interfaces.js';
|
||||||
|
|
||||||
// Import mingo Query class
|
// Import mingo Query class
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
||||||
import type { Document, IStoredDocument, ITransactionOptions } from '../types/interfaces.js';
|
import type { Document, IStoredDocument, ITransactionOptions } from '../types/interfaces.js';
|
||||||
import { CongoTransactionError, CongoWriteConflictError } from '../errors/CongoErrors.js';
|
import { TsmdbTransactionError, TsmdbWriteConflictError } from '../errors/TsmdbErrors.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction state
|
* Transaction state
|
||||||
@@ -70,7 +70,7 @@ export class TransactionEngine {
|
|||||||
async getSnapshot(txnId: string, dbName: string, collName: string): Promise<IStoredDocument[]> {
|
async getSnapshot(txnId: string, dbName: string, collName: string): Promise<IStoredDocument[]> {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn || txn.status !== 'active') {
|
if (!txn || txn.status !== 'active') {
|
||||||
throw new CongoTransactionError('Transaction is not active');
|
throw new TsmdbTransactionError('Transaction is not active');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ns = `${dbName}.${collName}`;
|
const ns = `${dbName}.${collName}`;
|
||||||
@@ -148,7 +148,7 @@ export class TransactionEngine {
|
|||||||
recordInsert(txnId: string, dbName: string, collName: string, doc: IStoredDocument): void {
|
recordInsert(txnId: string, dbName: string, collName: string, doc: IStoredDocument): void {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn || txn.status !== 'active') {
|
if (!txn || txn.status !== 'active') {
|
||||||
throw new CongoTransactionError('Transaction is not active');
|
throw new TsmdbTransactionError('Transaction is not active');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ns = `${dbName}.${collName}`;
|
const ns = `${dbName}.${collName}`;
|
||||||
@@ -174,7 +174,7 @@ export class TransactionEngine {
|
|||||||
): void {
|
): void {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn || txn.status !== 'active') {
|
if (!txn || txn.status !== 'active') {
|
||||||
throw new CongoTransactionError('Transaction is not active');
|
throw new TsmdbTransactionError('Transaction is not active');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ns = `${dbName}.${collName}`;
|
const ns = `${dbName}.${collName}`;
|
||||||
@@ -203,7 +203,7 @@ export class TransactionEngine {
|
|||||||
recordDelete(txnId: string, dbName: string, collName: string, doc: IStoredDocument): void {
|
recordDelete(txnId: string, dbName: string, collName: string, doc: IStoredDocument): void {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn || txn.status !== 'active') {
|
if (!txn || txn.status !== 'active') {
|
||||||
throw new CongoTransactionError('Transaction is not active');
|
throw new TsmdbTransactionError('Transaction is not active');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ns = `${dbName}.${collName}`;
|
const ns = `${dbName}.${collName}`;
|
||||||
@@ -231,10 +231,10 @@ export class TransactionEngine {
|
|||||||
async commitTransaction(txnId: string): Promise<void> {
|
async commitTransaction(txnId: string): Promise<void> {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn) {
|
if (!txn) {
|
||||||
throw new CongoTransactionError('Transaction not found');
|
throw new TsmdbTransactionError('Transaction not found');
|
||||||
}
|
}
|
||||||
if (txn.status !== 'active') {
|
if (txn.status !== 'active') {
|
||||||
throw new CongoTransactionError(`Cannot commit transaction in state: ${txn.status}`);
|
throw new TsmdbTransactionError(`Cannot commit transaction in state: ${txn.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for write conflicts
|
// Check for write conflicts
|
||||||
@@ -245,7 +245,7 @@ export class TransactionEngine {
|
|||||||
const hasConflicts = await this.storage.hasConflicts(dbName, collName, ids, txn.startTime);
|
const hasConflicts = await this.storage.hasConflicts(dbName, collName, ids, txn.startTime);
|
||||||
if (hasConflicts) {
|
if (hasConflicts) {
|
||||||
txn.status = 'aborted';
|
txn.status = 'aborted';
|
||||||
throw new CongoWriteConflictError();
|
throw new TsmdbWriteConflictError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ export class TransactionEngine {
|
|||||||
async abortTransaction(txnId: string): Promise<void> {
|
async abortTransaction(txnId: string): Promise<void> {
|
||||||
const txn = this.transactions.get(txnId);
|
const txn = this.transactions.get(txnId);
|
||||||
if (!txn) {
|
if (!txn) {
|
||||||
throw new CongoTransactionError('Transaction not found');
|
throw new TsmdbTransactionError('Transaction not found');
|
||||||
}
|
}
|
||||||
if (txn.status !== 'active') {
|
if (txn.status !== 'active') {
|
||||||
// Already committed or aborted, just return
|
// Already committed or aborted, just return
|
||||||
@@ -336,7 +336,7 @@ export class TransactionEngine {
|
|||||||
await this.abortTransaction(txnId);
|
await this.abortTransaction(txnId);
|
||||||
this.endTransaction(txnId);
|
this.endTransaction(txnId);
|
||||||
|
|
||||||
if (error instanceof CongoWriteConflictError && attempt < maxRetries - 1) {
|
if (error instanceof TsmdbWriteConflictError && attempt < maxRetries - 1) {
|
||||||
// Retry on write conflict
|
// Retry on write conflict
|
||||||
lastError = error;
|
lastError = error;
|
||||||
continue;
|
continue;
|
||||||
@@ -346,6 +346,6 @@ export class TransactionEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw lastError || new CongoTransactionError('Transaction failed after max retries');
|
throw lastError || new TsmdbTransactionError('Transaction failed after max retries');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { Document, IStoredDocument } from '../types/interfaces.js';
|
import type { Document, IStoredDocument } from '../types/interfaces.js';
|
||||||
import { QueryEngine } from './QueryEngine.js';
|
import { QueryEngine } from './QueryEngine.js';
|
||||||
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* Base error class for all CongoDB errors
|
* Base error class for all TsmDB errors
|
||||||
* Mirrors MongoDB driver error hierarchy
|
* Mirrors MongoDB driver error hierarchy
|
||||||
*/
|
*/
|
||||||
export class CongoError extends Error {
|
export class TsmdbError extends Error {
|
||||||
public code?: number;
|
public code?: number;
|
||||||
public codeName?: string;
|
public codeName?: string;
|
||||||
|
|
||||||
constructor(message: string, code?: number, codeName?: string) {
|
constructor(message: string, code?: number, codeName?: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'CongoError';
|
this.name = 'TsmdbError';
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.codeName = codeName;
|
this.codeName = codeName;
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
@@ -18,33 +18,33 @@ export class CongoError extends Error {
|
|||||||
/**
|
/**
|
||||||
* Error thrown during connection issues
|
* Error thrown during connection issues
|
||||||
*/
|
*/
|
||||||
export class CongoConnectionError extends CongoError {
|
export class TsmdbConnectionError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'CongoConnectionError';
|
this.name = 'TsmdbConnectionError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when an operation times out
|
* Error thrown when an operation times out
|
||||||
*/
|
*/
|
||||||
export class CongoTimeoutError extends CongoError {
|
export class TsmdbTimeoutError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 50, 'MaxTimeMSExpired');
|
super(message, 50, 'MaxTimeMSExpired');
|
||||||
this.name = 'CongoTimeoutError';
|
this.name = 'TsmdbTimeoutError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown during write operations
|
* Error thrown during write operations
|
||||||
*/
|
*/
|
||||||
export class CongoWriteError extends CongoError {
|
export class TsmdbWriteError extends TsmdbError {
|
||||||
public writeErrors?: IWriteError[];
|
public writeErrors?: IWriteError[];
|
||||||
public result?: any;
|
public result?: any;
|
||||||
|
|
||||||
constructor(message: string, code?: number, writeErrors?: IWriteError[]) {
|
constructor(message: string, code?: number, writeErrors?: IWriteError[]) {
|
||||||
super(message, code);
|
super(message, code);
|
||||||
this.name = 'CongoWriteError';
|
this.name = 'TsmdbWriteError';
|
||||||
this.writeErrors = writeErrors;
|
this.writeErrors = writeErrors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,13 +52,13 @@ export class CongoWriteError extends CongoError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown for duplicate key violations
|
* Error thrown for duplicate key violations
|
||||||
*/
|
*/
|
||||||
export class CongoDuplicateKeyError extends CongoWriteError {
|
export class TsmdbDuplicateKeyError extends TsmdbWriteError {
|
||||||
public keyPattern?: Record<string, 1>;
|
public keyPattern?: Record<string, 1>;
|
||||||
public keyValue?: Record<string, any>;
|
public keyValue?: Record<string, any>;
|
||||||
|
|
||||||
constructor(message: string, keyPattern?: Record<string, 1>, keyValue?: Record<string, any>) {
|
constructor(message: string, keyPattern?: Record<string, 1>, keyValue?: Record<string, any>) {
|
||||||
super(message, 11000);
|
super(message, 11000);
|
||||||
this.name = 'CongoDuplicateKeyError';
|
this.name = 'TsmdbDuplicateKeyError';
|
||||||
this.codeName = 'DuplicateKey';
|
this.codeName = 'DuplicateKey';
|
||||||
this.keyPattern = keyPattern;
|
this.keyPattern = keyPattern;
|
||||||
this.keyValue = keyValue;
|
this.keyValue = keyValue;
|
||||||
@@ -68,13 +68,13 @@ export class CongoDuplicateKeyError extends CongoWriteError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown for bulk write failures
|
* Error thrown for bulk write failures
|
||||||
*/
|
*/
|
||||||
export class CongoBulkWriteError extends CongoError {
|
export class TsmdbBulkWriteError extends TsmdbError {
|
||||||
public writeErrors: IWriteError[];
|
public writeErrors: IWriteError[];
|
||||||
public result: any;
|
public result: any;
|
||||||
|
|
||||||
constructor(message: string, writeErrors: IWriteError[], result: any) {
|
constructor(message: string, writeErrors: IWriteError[], result: any) {
|
||||||
super(message, 65);
|
super(message, 65);
|
||||||
this.name = 'CongoBulkWriteError';
|
this.name = 'TsmdbBulkWriteError';
|
||||||
this.writeErrors = writeErrors;
|
this.writeErrors = writeErrors;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
@@ -83,20 +83,20 @@ export class CongoBulkWriteError extends CongoError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown during transaction operations
|
* Error thrown during transaction operations
|
||||||
*/
|
*/
|
||||||
export class CongoTransactionError extends CongoError {
|
export class TsmdbTransactionError extends TsmdbError {
|
||||||
constructor(message: string, code?: number) {
|
constructor(message: string, code?: number) {
|
||||||
super(message, code);
|
super(message, code);
|
||||||
this.name = 'CongoTransactionError';
|
this.name = 'TsmdbTransactionError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when a transaction is aborted due to conflict
|
* Error thrown when a transaction is aborted due to conflict
|
||||||
*/
|
*/
|
||||||
export class CongoWriteConflictError extends CongoTransactionError {
|
export class TsmdbWriteConflictError extends TsmdbTransactionError {
|
||||||
constructor(message: string = 'Write conflict during transaction') {
|
constructor(message: string = 'Write conflict during transaction') {
|
||||||
super(message, 112);
|
super(message, 112);
|
||||||
this.name = 'CongoWriteConflictError';
|
this.name = 'TsmdbWriteConflictError';
|
||||||
this.codeName = 'WriteConflict';
|
this.codeName = 'WriteConflict';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,20 +104,20 @@ export class CongoWriteConflictError extends CongoTransactionError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown for invalid arguments
|
* Error thrown for invalid arguments
|
||||||
*/
|
*/
|
||||||
export class CongoArgumentError extends CongoError {
|
export class TsmdbArgumentError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'CongoArgumentError';
|
this.name = 'TsmdbArgumentError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when an operation is not supported
|
* Error thrown when an operation is not supported
|
||||||
*/
|
*/
|
||||||
export class CongoNotSupportedError extends CongoError {
|
export class TsmdbNotSupportedError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 115);
|
super(message, 115);
|
||||||
this.name = 'CongoNotSupportedError';
|
this.name = 'TsmdbNotSupportedError';
|
||||||
this.codeName = 'CommandNotSupported';
|
this.codeName = 'CommandNotSupported';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,20 +125,20 @@ export class CongoNotSupportedError extends CongoError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown when cursor is exhausted or closed
|
* Error thrown when cursor is exhausted or closed
|
||||||
*/
|
*/
|
||||||
export class CongoCursorError extends CongoError {
|
export class TsmdbCursorError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'CongoCursorError';
|
this.name = 'TsmdbCursorError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when a namespace (database.collection) is invalid
|
* Error thrown when a namespace (database.collection) is invalid
|
||||||
*/
|
*/
|
||||||
export class CongoNamespaceError extends CongoError {
|
export class TsmdbNamespaceError extends TsmdbError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 73);
|
super(message, 73);
|
||||||
this.name = 'CongoNamespaceError';
|
this.name = 'TsmdbNamespaceError';
|
||||||
this.codeName = 'InvalidNamespace';
|
this.codeName = 'InvalidNamespace';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,10 +146,10 @@ export class CongoNamespaceError extends CongoError {
|
|||||||
/**
|
/**
|
||||||
* Error thrown when an index operation fails
|
* Error thrown when an index operation fails
|
||||||
*/
|
*/
|
||||||
export class CongoIndexError extends CongoError {
|
export class TsmdbIndexError extends TsmdbError {
|
||||||
constructor(message: string, code?: number) {
|
constructor(message: string, code?: number) {
|
||||||
super(message, code || 86);
|
super(message, code || 86);
|
||||||
this.name = 'CongoIndexError';
|
this.name = 'TsmdbIndexError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,18 +164,18 @@ export interface IWriteError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert any error to a CongoError
|
* Convert any error to a TsmdbError
|
||||||
*/
|
*/
|
||||||
export function toCongoError(error: any): CongoError {
|
export function toTsmdbError(error: any): TsmdbError {
|
||||||
if (error instanceof CongoError) {
|
if (error instanceof TsmdbError) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
const congoError = new CongoError(error.message || String(error));
|
const tsmdbError = new TsmdbError(error.message || String(error));
|
||||||
if (error.code) {
|
if (error.code) {
|
||||||
congoError.code = error.code;
|
tsmdbError.code = error.code;
|
||||||
}
|
}
|
||||||
if (error.codeName) {
|
if (error.codeName) {
|
||||||
congoError.codeName = error.codeName;
|
tsmdbError.codeName = error.codeName;
|
||||||
}
|
}
|
||||||
return congoError;
|
return tsmdbError;
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// CongoDB - MongoDB Wire Protocol compatible in-memory database server
|
// TsmDB - MongoDB Wire Protocol compatible in-memory database server
|
||||||
// Use the official MongoDB driver to connect to CongoServer
|
// Use the official MongoDB driver to connect to TsmdbServer
|
||||||
|
|
||||||
// Re-export plugins for external use
|
// Re-export plugins for external use
|
||||||
import * as plugins from './congodb.plugins.js';
|
import * as plugins from './tsmdb.plugins.js';
|
||||||
export { plugins };
|
export { plugins };
|
||||||
|
|
||||||
// Export BSON types for convenience
|
// Export BSON types for convenience
|
||||||
@@ -12,7 +12,7 @@ export { ObjectId, Binary, Timestamp, Long, Decimal128, UUID } from 'bson';
|
|||||||
export * from './types/interfaces.js';
|
export * from './types/interfaces.js';
|
||||||
|
|
||||||
// Export errors
|
// Export errors
|
||||||
export * from './errors/CongoErrors.js';
|
export * from './errors/TsmdbErrors.js';
|
||||||
|
|
||||||
// Export storage adapters
|
// Export storage adapters
|
||||||
export type { IStorageAdapter } from './storage/IStorageAdapter.js';
|
export type { IStorageAdapter } from './storage/IStorageAdapter.js';
|
||||||
@@ -27,9 +27,9 @@ export { AggregationEngine } from './engine/AggregationEngine.js';
|
|||||||
export { IndexEngine } from './engine/IndexEngine.js';
|
export { IndexEngine } from './engine/IndexEngine.js';
|
||||||
export { TransactionEngine } from './engine/TransactionEngine.js';
|
export { TransactionEngine } from './engine/TransactionEngine.js';
|
||||||
|
|
||||||
// Export server (the main entry point for using CongoDB)
|
// Export server (the main entry point for using TsmDB)
|
||||||
export { CongoServer } from './server/CongoServer.js';
|
export { TsmdbServer } from './server/TsmdbServer.js';
|
||||||
export type { ICongoServerOptions } from './server/CongoServer.js';
|
export type { ITsmdbServerOptions } from './server/TsmdbServer.js';
|
||||||
|
|
||||||
// Export wire protocol utilities (for advanced usage)
|
// Export wire protocol utilities (for advanced usage)
|
||||||
export { WireProtocol } from './server/WireProtocol.js';
|
export { WireProtocol } from './server/WireProtocol.js';
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
||||||
import type { IParsedCommand } from './WireProtocol.js';
|
import type { IParsedCommand } from './WireProtocol.js';
|
||||||
import type { CongoServer } from './CongoServer.js';
|
import type { TsmdbServer } from './TsmdbServer.js';
|
||||||
|
|
||||||
// Import handlers
|
// Import handlers
|
||||||
import { HelloHandler } from './handlers/HelloHandler.js';
|
import { HelloHandler } from './handlers/HelloHandler.js';
|
||||||
@@ -18,7 +18,7 @@ import { AdminHandler } from './handlers/AdminHandler.js';
|
|||||||
*/
|
*/
|
||||||
export interface IHandlerContext {
|
export interface IHandlerContext {
|
||||||
storage: IStorageAdapter;
|
storage: IStorageAdapter;
|
||||||
server: CongoServer;
|
server: TsmdbServer;
|
||||||
database: string;
|
database: string;
|
||||||
command: plugins.bson.Document;
|
command: plugins.bson.Document;
|
||||||
documentSequences?: Map<string, plugins.bson.Document[]>;
|
documentSequences?: Map<string, plugins.bson.Document[]>;
|
||||||
@@ -36,14 +36,14 @@ export interface ICommandHandler {
|
|||||||
*/
|
*/
|
||||||
export class CommandRouter {
|
export class CommandRouter {
|
||||||
private storage: IStorageAdapter;
|
private storage: IStorageAdapter;
|
||||||
private server: CongoServer;
|
private server: TsmdbServer;
|
||||||
private handlers: Map<string, ICommandHandler> = new Map();
|
private handlers: Map<string, ICommandHandler> = new Map();
|
||||||
|
|
||||||
// Cursor state for getMore operations
|
// Cursor state for getMore operations
|
||||||
private cursors: Map<bigint, ICursorState> = new Map();
|
private cursors: Map<bigint, ICursorState> = new Map();
|
||||||
private cursorIdCounter: bigint = BigInt(1);
|
private cursorIdCounter: bigint = BigInt(1);
|
||||||
|
|
||||||
constructor(storage: IStorageAdapter, server: CongoServer) {
|
constructor(storage: IStorageAdapter, server: TsmdbServer) {
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.registerHandlers();
|
this.registerHandlers();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as net from 'net';
|
import * as net from 'net';
|
||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import { WireProtocol, OP_QUERY } from './WireProtocol.js';
|
import { WireProtocol, OP_QUERY } from './WireProtocol.js';
|
||||||
import { CommandRouter } from './CommandRouter.js';
|
import { CommandRouter } from './CommandRouter.js';
|
||||||
import { MemoryStorageAdapter } from '../storage/MemoryStorageAdapter.js';
|
import { MemoryStorageAdapter } from '../storage/MemoryStorageAdapter.js';
|
||||||
@@ -9,7 +9,7 @@ import type { IStorageAdapter } from '../storage/IStorageAdapter.js';
|
|||||||
/**
|
/**
|
||||||
* Server configuration options
|
* Server configuration options
|
||||||
*/
|
*/
|
||||||
export interface ICongoServerOptions {
|
export interface ITsmdbServerOptions {
|
||||||
/** Port to listen on (default: 27017) */
|
/** Port to listen on (default: 27017) */
|
||||||
port?: number;
|
port?: number;
|
||||||
/** Host to bind to (default: 127.0.0.1) */
|
/** Host to bind to (default: 127.0.0.1) */
|
||||||
@@ -36,25 +36,25 @@ interface IConnectionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CongoServer - MongoDB Wire Protocol compatible server
|
* TsmdbServer - MongoDB Wire Protocol compatible server
|
||||||
*
|
*
|
||||||
* This server implements the MongoDB wire protocol (OP_MSG) to allow
|
* This server implements the MongoDB wire protocol (OP_MSG) to allow
|
||||||
* official MongoDB drivers to connect and perform operations.
|
* official MongoDB drivers to connect and perform operations.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* import { CongoServer } from '@push.rocks/smartmongo/congodb';
|
* import { TsmdbServer } from '@push.rocks/smartmongo/tsmdb';
|
||||||
* import { MongoClient } from 'mongodb';
|
* import { MongoClient } from 'mongodb';
|
||||||
*
|
*
|
||||||
* const server = new CongoServer({ port: 27017 });
|
* const server = new TsmdbServer({ port: 27017 });
|
||||||
* await server.start();
|
* await server.start();
|
||||||
*
|
*
|
||||||
* const client = new MongoClient('mongodb://127.0.0.1:27017');
|
* const client = new MongoClient('mongodb://127.0.0.1:27017');
|
||||||
* await client.connect();
|
* await client.connect();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export class CongoServer {
|
export class TsmdbServer {
|
||||||
private options: Required<ICongoServerOptions>;
|
private options: Required<ITsmdbServerOptions>;
|
||||||
private server: net.Server | null = null;
|
private server: net.Server | null = null;
|
||||||
private storage: IStorageAdapter;
|
private storage: IStorageAdapter;
|
||||||
private commandRouter: CommandRouter;
|
private commandRouter: CommandRouter;
|
||||||
@@ -63,7 +63,7 @@ export class CongoServer {
|
|||||||
private isRunning = false;
|
private isRunning = false;
|
||||||
private startTime: Date = new Date();
|
private startTime: Date = new Date();
|
||||||
|
|
||||||
constructor(options: ICongoServerOptions = {}) {
|
constructor(options: ITsmdbServerOptions = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
port: options.port ?? 27017,
|
port: options.port ?? 27017,
|
||||||
host: options.host ?? '127.0.0.1',
|
host: options.host ?? '127.0.0.1',
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MongoDB Wire Protocol Implementation
|
* MongoDB Wire Protocol Implementation
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,7 +246,7 @@ export class AdminHandler implements ICommandHandler {
|
|||||||
ok: 1,
|
ok: 1,
|
||||||
host: `${server.host}:${server.port}`,
|
host: `${server.host}:${server.port}`,
|
||||||
version: '7.0.0',
|
version: '7.0.0',
|
||||||
process: 'congodb',
|
process: 'tsmdb',
|
||||||
pid: process.pid,
|
pid: process.pid,
|
||||||
uptime,
|
uptime,
|
||||||
uptimeMillis: uptime * 1000,
|
uptimeMillis: uptime * 1000,
|
||||||
@@ -269,7 +269,7 @@ export class AdminHandler implements ICommandHandler {
|
|||||||
numRequests: 0,
|
numRequests: 0,
|
||||||
},
|
},
|
||||||
storageEngine: {
|
storageEngine: {
|
||||||
name: 'congodb',
|
name: 'tsmdb',
|
||||||
supportsCommittedReads: true,
|
supportsCommittedReads: true,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
},
|
},
|
||||||
@@ -283,7 +283,7 @@ export class AdminHandler implements ICommandHandler {
|
|||||||
return {
|
return {
|
||||||
ok: 1,
|
ok: 1,
|
||||||
version: '7.0.0',
|
version: '7.0.0',
|
||||||
gitVersion: 'congodb',
|
gitVersion: 'tsmdb',
|
||||||
modules: [],
|
modules: [],
|
||||||
allocator: 'system',
|
allocator: 'system',
|
||||||
javascriptEngine: 'none',
|
javascriptEngine: 'none',
|
||||||
@@ -294,7 +294,7 @@ export class AdminHandler implements ICommandHandler {
|
|||||||
compiled: 'disabled',
|
compiled: 'disabled',
|
||||||
},
|
},
|
||||||
buildEnvironment: {
|
buildEnvironment: {
|
||||||
distmod: 'congodb',
|
distmod: 'tsmdb',
|
||||||
distarch: process.arch,
|
distarch: process.arch,
|
||||||
cc: '',
|
cc: '',
|
||||||
ccflags: '',
|
ccflags: '',
|
||||||
@@ -307,7 +307,7 @@ export class AdminHandler implements ICommandHandler {
|
|||||||
bits: 64,
|
bits: 64,
|
||||||
debug: false,
|
debug: false,
|
||||||
maxBsonObjectSize: 16777216,
|
maxBsonObjectSize: 16777216,
|
||||||
storageEngines: ['congodb'],
|
storageEngines: ['tsmdb'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
||||||
import { AggregationEngine } from '../../engine/AggregationEngine.js';
|
import { AggregationEngine } from '../../engine/AggregationEngine.js';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
import { QueryEngine } from '../../engine/QueryEngine.js';
|
import { QueryEngine } from '../../engine/QueryEngine.js';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
||||||
import { QueryEngine } from '../../engine/QueryEngine.js';
|
import { QueryEngine } from '../../engine/QueryEngine.js';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
import { IndexEngine } from '../../engine/IndexEngine.js';
|
import { IndexEngine } from '../../engine/IndexEngine.js';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../../congodb.plugins.js';
|
import * as plugins from '../../tsmdb.plugins.js';
|
||||||
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
||||||
import { QueryEngine } from '../../engine/QueryEngine.js';
|
import { QueryEngine } from '../../engine/QueryEngine.js';
|
||||||
import { UpdateEngine } from '../../engine/UpdateEngine.js';
|
import { UpdateEngine } from '../../engine/UpdateEngine.js';
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Server module exports
|
// Server module exports
|
||||||
|
|
||||||
export { CongoServer } from './CongoServer.js';
|
export { TsmdbServer } from './TsmdbServer.js';
|
||||||
export type { ICongoServerOptions } from './CongoServer.js';
|
export type { ITsmdbServerOptions } from './TsmdbServer.js';
|
||||||
export { WireProtocol } from './WireProtocol.js';
|
export { WireProtocol } from './WireProtocol.js';
|
||||||
export { CommandRouter } from './CommandRouter.js';
|
export { CommandRouter } from './CommandRouter.js';
|
||||||
export type { ICommandHandler, IHandlerContext, ICursorState } from './CommandRouter.js';
|
export type { ICommandHandler, IHandlerContext, ICursorState } from './CommandRouter.js';
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from './IStorageAdapter.js';
|
import type { IStorageAdapter } from './IStorageAdapter.js';
|
||||||
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File-based storage adapter for CongoDB
|
* File-based storage adapter for TsmDB
|
||||||
* Stores data in JSON files on disk for persistence
|
* Stores data in JSON files on disk for persistence
|
||||||
*/
|
*/
|
||||||
export class FileStorageAdapter implements IStorageAdapter {
|
export class FileStorageAdapter implements IStorageAdapter {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import type * as plugins from '../congodb.plugins.js';
|
import type * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Storage adapter interface for CongoDB
|
* Storage adapter interface for TsmDB
|
||||||
* Implementations can provide different storage backends (memory, file, etc.)
|
* Implementations can provide different storage backends (memory, file, etc.)
|
||||||
*/
|
*/
|
||||||
export interface IStorageAdapter {
|
export interface IStorageAdapter {
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from './IStorageAdapter.js';
|
import type { IStorageAdapter } from './IStorageAdapter.js';
|
||||||
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In-memory storage adapter for CongoDB
|
* In-memory storage adapter for TsmDB
|
||||||
* Optionally supports persistence to a file
|
* Optionally supports persistence to a file
|
||||||
*/
|
*/
|
||||||
export class MemoryStorageAdapter implements IStorageAdapter {
|
export class MemoryStorageAdapter implements IStorageAdapter {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from '../congodb.plugins.js';
|
import * as plugins from '../tsmdb.plugins.js';
|
||||||
import type { IStorageAdapter } from './IStorageAdapter.js';
|
import type { IStorageAdapter } from './IStorageAdapter.js';
|
||||||
import type { IOpLogEntry, Document, IResumeToken, ChangeStreamOperationType } from '../types/interfaces.js';
|
import type { IOpLogEntry, Document, IResumeToken, ChangeStreamOperationType } from '../types/interfaces.js';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type * as plugins from '../congodb.plugins.js';
|
import type * as plugins from '../tsmdb.plugins.js';
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Document Types
|
// Document Types
|
||||||
@@ -14,7 +14,7 @@ export interface WithId<TSchema> {
|
|||||||
// Client Options
|
// Client Options
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface ICongoClientOptions {
|
export interface ITsmdbClientOptions {
|
||||||
/** Storage adapter type: 'memory' or 'file' */
|
/** Storage adapter type: 'memory' or 'file' */
|
||||||
storageType?: 'memory' | 'file';
|
storageType?: 'memory' | 'file';
|
||||||
/** Path for file-based storage */
|
/** Path for file-based storage */
|
||||||
@@ -30,7 +30,7 @@ export interface ICongoClientOptions {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface IParsedConnectionString {
|
export interface IParsedConnectionString {
|
||||||
protocol: 'congo';
|
protocol: 'tsmdb';
|
||||||
storageType: 'memory' | 'file';
|
storageType: 'memory' | 'file';
|
||||||
options: {
|
options: {
|
||||||
persist?: string;
|
persist?: string;
|
||||||
Reference in New Issue
Block a user