docudb
Version:
Document-based NoSQL database for NodeJS
240 lines • 10.6 kB
JavaScript
import { Database, Schema, Query } from '../index.js';
import { expect } from 'chai';
import { cleanTestDataDir } from './utils.js';
describe('DocuDB - Compression and Edge Cases', () => {
let db;
let productos;
const testDbName = 'testCompression';
describe('Data Compression', () => {
beforeEach(async () => {
await cleanTestDataDir(testDbName);
db = new Database({
name: testDbName,
compression: true, // Enable compression
chunkSize: 512 // Small size to force multiple chunks
});
await db.initialize();
const productoSchema = new Schema({
name: { type: 'string', required: true },
description: { type: 'string', default: '' },
price: { type: 'number', required: true },
details: { type: 'object', default: {} }
});
productos = db.collection('productos', { schema: productoSchema });
});
afterEach(async () => {
await cleanTestDataDir(testDbName);
});
it('should compress large documents correctly', async () => {
// Create a document with large data
const longDescription = 'a'.repeat(1000); // 1KB of text
const largeDetails = {};
// Generate large object
for (let i = 0; i < 100; i++) {
largeDetails[`property${i}`] = `value${i}`.repeat(10);
}
const product = await productos.insertOne({
name: 'Large Product',
description: longDescription,
price: 999.99,
details: largeDetails
});
expect(product).to.have.property('_id');
// Retrieve the document
const retrieved = await productos.findById(product._id);
expect(retrieved).to.exist;
if (retrieved != null) {
expect(retrieved.description).to.equal(longDescription);
expect(Object.keys(retrieved.details)).to.have.lengthOf(100);
}
});
it('should compress and decompress multiple documents correctly', async () => {
// Insert multiple documents with medium-sized data
const docs = [];
for (let i = 0; i < 50; i++) {
docs.push({
name: `Product ${i}`,
description: `Product description ${i}`.repeat(20),
price: i * 10.5,
details: {
color: 'red',
weight: `${i * 100}g`,
dimensions: `${i}x${i + 1}x${i + 2}`
}
});
}
const inserted = await productos.insertMany(docs);
expect(inserted).to.have.lengthOf(50);
// Retrieve all documents
const retrieved = await productos.find({});
expect(retrieved).to.have.lengthOf(50);
// Verify data integrity
for (let i = 0; i < 50; i++) {
const doc = retrieved.find(d => d.name === `Product ${i}`);
expect(doc).to.exist;
if (doc != null) {
expect(doc.price).to.equal(i * 10.5);
expect(doc.details.weight).to.equal(`${i * 100}g`);
}
}
});
it('should handle compression in updates correctly', async () => {
// Insert initial document
const product = await productos.insertOne({
name: 'Updatable Product',
description: 'Initial description',
price: 100
});
// Update with large data
const longDescription = 'New extended description '.repeat(100);
const largeDetails = {};
for (let i = 0; i < 50; i++) {
largeDetails[`attribute${i}`] = `value${i}`.repeat(5);
}
const updated = await productos.updateById(product._id, {
$set: {
description: longDescription,
details: largeDetails
}
});
expect(updated?.description).to.equal(longDescription);
// Retrieve and verify
const retrieved = await productos.findById(product._id);
expect(retrieved).to.exist;
if (retrieved != null) {
expect(retrieved.description).to.equal(longDescription);
expect(Object.keys(retrieved.details)).to.have.lengthOf(50);
}
});
});
describe('Edge Cases', () => {
beforeEach(async () => {
await cleanTestDataDir(testDbName);
db = new Database({
name: testDbName,
compression: false
});
await db.initialize();
const productoSchema = new Schema({
name: { type: 'string', required: true },
price: { type: 'number', default: 0 },
stock: { type: 'number', default: 0 },
tags: { type: 'array', default: [] },
metadata: { type: 'object' }
}, { strict: false });
productos = db.collection('productos', { schema: productoSchema });
});
afterEach(async () => {
await cleanTestDataDir(testDbName);
});
it('should handle empty documents correctly', async () => {
// Only with required field
const minimalProduct = await productos.insertOne({
name: 'Minimal Product'
});
expect(minimalProduct).to.have.property('_id');
expect(minimalProduct.price).to.equal(0); // Default value
expect(minimalProduct.tags).to.be.an('array').that.is.empty;
// Retrieve
const retrieved = await productos.findById(minimalProduct._id);
expect(retrieved).to.exist;
if (retrieved != null) {
expect(retrieved.name).to.equal('Minimal Product');
}
});
it('should handle empty arrays and objects', async () => {
const product = await productos.insertOne({
name: 'Array Product',
price: 50,
tags: [],
metadata: {}
});
expect(product.tags).to.be.an('array').that.is.empty;
expect(product.metadata).to.be.an('object').that.is.empty;
// Update with arrays and objects
const updated = await productos.updateById(product._id, {
$set: {
tags: ['tag1', 'tag2'],
metadata: { color: 'red' }
}
});
expect(updated).to.exist;
if (updated != null) {
expect(updated.tags).to.have.lengthOf(2);
expect(updated.metadata.color).to.equal('red');
}
});
it('should handle queries with complex filters', async () => {
// Insert varied data
await productos.insertMany([
{ name: 'A', price: 10, stock: 5, tags: ['small', 'cheap'] },
{ name: 'B', price: 20, stock: 0, tags: ['medium', 'cheap'] },
{ name: 'C', price: 30, stock: 15, tags: ['small', 'premium'] },
{ name: 'D', price: 100, stock: 10, tags: ['large', 'premium'] },
{ name: 'E', price: 50, stock: 0, tags: ['medium', 'premium'] },
{ name: 'F', price: 25, stock: 2, tags: ['medium', 'premium'] },
{ name: 'G', price: 95, stock: 8, tags: ['small', 'cheap'] }
]);
// Complex query with multiple conditions
const query = new Query({
$and: [
{
$or: [{ price: { $lt: 30 } }, { price: { $gt: 90 } }]
},
{
$or: [{ stock: { $gt: 0 } }, { tags: { $in: ['premium'] } }]
},
{ tags: { $nin: ['large'] } }
]
});
const results = await productos.find(query);
expect(results).to.have.lengthOf(3);
expect(results.map(p => p.name)).to.have.members(['A', 'F', 'G']);
});
it('should handle massive document deletion', async () => {
// Insert many documents
const docs = [];
for (let i = 0; i < 100; i++) {
docs.push({
name: `Product ${i}`,
price: (i % 10) * 10,
stock: i % 5,
tags: i % 2 === 0 ? ['even'] : ['odd']
});
}
await productos.insertMany(docs);
// Verify total
const initialTotal = await productos.count();
expect(initialTotal).to.equal(100);
// Delete documents with price > 50
const deleted = await productos.deleteMany({ price: { $gt: 50 } });
expect(deleted).to.be.at.least(40); // At least 40 documents deleted
// Verify remaining
const remaining = await productos.count();
expect(remaining).to.equal(initialTotal - deleted);
// Verify correct ones were deleted
const results = await productos.find({ price: { $gt: 50 } });
expect(results).to.have.lengthOf(0);
});
it('should handle extreme values correctly', async () => {
// Extreme values
const extremeProduct = await productos.insertOne({
name: 'Extreme Product',
price: Number.MAX_SAFE_INTEGER,
stock: -0,
tags: Array(1000).fill('tag'), // Large array
metadata: { nested: { deeply: { value: Number.MIN_SAFE_INTEGER } } }
});
// Retrieve and verify
const retrieved = await productos.findById(extremeProduct._id);
expect(retrieved).to.exist;
if (retrieved != null) {
expect(retrieved.price).to.equal(Number.MAX_SAFE_INTEGER);
expect(retrieved.stock).to.equal(0); // -0 converts to 0
expect(retrieved.tags).to.have.lengthOf(1000);
expect(retrieved.metadata.nested.deeply.value).to.equal(Number.MIN_SAFE_INTEGER);
}
});
});
});
//# sourceMappingURL=compression_edge_cases.test.js.map