zumito-db
Version:
Multi-driver database abstraction layer with decorator-based models
143 lines (142 loc) • 4.85 kB
JavaScript
import { mkdirSync } from 'fs';
export class TingoDriver {
db;
raw;
async connect(config) {
mkdirSync(config.path || './db/tingodb', { recursive: true });
try {
// @ts-ignore - optional peer dependency
const tingoModule = await import('tingodb');
const factory = tingoModule.default || tingoModule;
const tingodb = typeof factory === 'function' ? factory() : new factory.Db(config.path || './db/tingodb', {});
const Db = tingodb.Db || factory.Db;
this.db = new Db(config.path || './db/tingodb', {});
this.raw = this.db;
}
catch {
const { createRequire } = await import('module');
const req = createRequire(import.meta.url);
// @ts-ignore - optional peer dependency
const tingodb = req('tingodb')();
this.db = new tingodb.Db(config.path || './db/tingodb', {});
this.raw = this.db;
}
}
async disconnect() { }
async find(collection, query) {
return new Promise((resolve, reject) => {
const filter = this.buildFilter(query);
const cursor = this.db.collection(collection).find(filter);
if (query.select) {
const projection = {};
for (const f of query.select)
projection[f] = 1;
cursor.project(projection);
}
if (query.sort) {
const sort = {};
for (const s of query.sort)
sort[s.field] = s.dir === 'asc' ? 1 : -1;
cursor.sort(sort);
}
if (query.offset)
cursor.skip(query.offset);
if (query.limit)
cursor.limit(query.limit);
cursor.toArray((err, docs) => {
if (err)
reject(err);
else
resolve(docs || []);
});
});
}
async findOne(collection, query) {
return new Promise((resolve, reject) => {
this.db.collection(collection).findOne(this.buildFilter(query), (err, doc) => {
if (err)
reject(err);
else
resolve(doc || null);
});
});
}
async insert(collection, data) {
return new Promise((resolve, reject) => {
this.db.collection(collection).insert(data, (err, docs) => {
if (err)
reject(err);
else
resolve(docs[0]);
});
});
}
async update(collection, query, data) {
return new Promise((resolve, reject) => {
this.db.collection(collection).update(this.buildFilter(query), { $set: data }, { multi: true }, (err, count) => {
if (err)
reject(err);
else
resolve(count);
});
});
}
async delete(collection, query) {
return new Promise((resolve, reject) => {
this.db.collection(collection).remove(this.buildFilter(query), (err, count) => {
if (err)
reject(err);
else
resolve(count);
});
});
}
async count(collection, query) {
return new Promise((resolve, reject) => {
this.db.collection(collection).count(this.buildFilter(query), (err, count) => {
if (err)
reject(err);
else
resolve(count);
});
});
}
async ensureSchema(_metadata) { }
async dropCollection(name) {
return new Promise((resolve, reject) => {
this.db.dropCollection(name, (err) => {
if (err)
reject(err);
else
resolve();
});
});
}
async listCollections() {
return new Promise((resolve, reject) => {
this.db.collections((err, names) => {
if (err)
reject(err);
else
resolve(names || []);
});
});
}
buildFilter(query) {
if (!query.where || query.where.length === 0)
return {};
const filter = {};
for (const clause of query.where) {
if (clause.operator === 'eq') {
filter[clause.field] = clause.value;
}
else if (clause.operator === 'like') {
filter[clause.field] = { $regex: clause.value };
}
else {
filter[clause.field] = { ['$' + clause.operator]: clause.value };
}
}
return filter;
}
}