Skip to content

Commit

Permalink
Fix #8 by cleaning indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
markwylde committed Jun 29, 2024
1 parent ac13972 commit ca2018b
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 14 deletions.
58 changes: 44 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,43 @@ async function createDoubleDb (dataDirectory) {

const db = new Level(dataDirectory);

async function addToIndexes (id, object, prefix = '') {
const promises = Object.keys(object).map(key => {
if (isObject(object[key])) {
addToIndexes(id, object[key], prefix + '.' + key);
return null;
}
async function addToIndexes(id, object, prefix = '') {
const promises = [];

if (Array.isArray(object[key])) {
for (const index in object[key]) {
db.put('indexes' + prefix + '.' + key + '=' + object[key][index] + '|' + id, id);
}
return null;
const addIndex = (key, value) => {
return db.put('indexes' + prefix + '.' + key + '=' + value + '|' + id, id);
};

for (const [key, value] of Object.entries(object)) {
if (isObject(value)) {
promises.push(addToIndexes(id, value, prefix + '.' + key));
} else if (Array.isArray(value)) {
value.forEach(item => promises.push(addIndex(key, item)));
} else {
promises.push(addIndex(key, value));
}
}

return Promise.all(promises);
}

async function removeIndexesForDocument(id, document, prefix = '') {
const parsedDocument = typeof document === 'string' ? JSON.parse(document) : document;
const promises = [];

db.put('indexes' + prefix + '.' + key + '=' + object[key] + '|' + id, id);
return null;
});
const removeIndex = (key, value) => {
return db.del('indexes' + prefix + '.' + key + '=' + value + '|' + id).catch(() => {});
};

for (const [key, value] of Object.entries(parsedDocument)) {
if (isObject(value)) {
promises.push(removeIndexesForDocument(id, value, prefix + '.' + key));
} else if (Array.isArray(value)) {
value.forEach(item => promises.push(removeIndex(key, item)));
} else {
promises.push(removeIndex(key, value));
}
}

return Promise.all(promises);
}
Expand Down Expand Up @@ -87,12 +107,16 @@ async function createDoubleDb (dataDirectory) {
throw new Error(`doubledb.replace: document with id ${id} does not exist`);
}

await removeIndexesForDocument(id, existingDocument);

const puttableRecord = {
...newDocument,
id
};
await db.put(id, JSON.stringify(puttableRecord));

await addToIndexes(id, puttableRecord);

return puttableRecord;
}

Expand All @@ -116,13 +140,17 @@ async function createDoubleDb (dataDirectory) {
throw new Error(`doubledb.patch: document with id ${id} does not exist`);
}

await removeIndexesForDocument(id, existingDocument);

const puttableRecord = {
...JSON.parse(existingDocument),
...newDocument,
id
};
await db.put(id, JSON.stringify(puttableRecord));

await addToIndexes(id, puttableRecord);

return puttableRecord;
}

Expand Down Expand Up @@ -266,6 +294,8 @@ async function createDoubleDb (dataDirectory) {
throw new Error(`doubledb.remove: document with id ${id} does not exist`);
}

await removeIndexesForDocument(id, existingDocument);

return db.del(id);
}

Expand Down
114 changes: 114 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,118 @@ test('query - found', async t => {
return () => db.close();
});

// Index resets

test('replace - updates indexes correctly', async t => {
t.plan(4);

await fs.rm('./testData', { recursive: true }).catch(() => {});
const db = await createDoubleDb('./testData');

// Insert initial document
const insertedRecord = await db.insert({
firstName: 'John',
lastName: 'Doe',
age: 30
});

// Replace the document
await db.replace(insertedRecord.id, {
firstName: 'Jane',
lastName: 'Smith',
occupation: 'Engineer'
});

// Check if old indexes are removed
const oldIndexes = await db.find('age', 30);
t.equal(oldIndexes, undefined, 'Old index should be removed');

// Check if new indexes are added
const newFirstNameIndex = await db.find('firstName', 'Jane');
t.deepEqual(newFirstNameIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Smith', occupation: 'Engineer' }, 'New firstName index should exist');

const newLastNameIndex = await db.find('lastName', 'Smith');
t.deepEqual(newLastNameIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Smith', occupation: 'Engineer' }, 'New lastName index should exist');

const newOccupationIndex = await db.find('occupation', 'Engineer');
t.deepEqual(newOccupationIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Smith', occupation: 'Engineer' }, 'New occupation index should exist');

await db.close();
});

test('patch - updates indexes correctly', async t => {
t.plan(5);

await fs.rm('./testData', { recursive: true }).catch(() => {});
const db = await createDoubleDb('./testData');

// Insert initial document
const insertedRecord = await db.insert({
firstName: 'John',
lastName: 'Doe',
age: 30
});

// Patch the document
await db.patch(insertedRecord.id, {
firstName: 'Jane',
age: 31,
occupation: 'Engineer'
});

// Check if updated indexes are correct
const updatedFirstNameIndex = await db.find('firstName', 'Jane');
t.deepEqual(updatedFirstNameIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Doe', age: 31, occupation: 'Engineer' }, 'Updated firstName index should exist');

const updatedAgeIndex = await db.find('age', 31);
t.deepEqual(updatedAgeIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Doe', age: 31, occupation: 'Engineer' }, 'Updated age index should exist');

// Check if new index is added
const newOccupationIndex = await db.find('occupation', 'Engineer');
t.deepEqual(newOccupationIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Doe', age: 31, occupation: 'Engineer' }, 'New occupation index should exist');

// Check if unchanged index still exists
const unchangedLastNameIndex = await db.find('lastName', 'Doe');
t.deepEqual(unchangedLastNameIndex, { id: insertedRecord.id, firstName: 'Jane', lastName: 'Doe', age: 31, occupation: 'Engineer' }, 'Unchanged lastName index should still exist');

// Check if old index is removed
const oldAgeIndex = await db.find('age', 30);
t.equal(oldAgeIndex, undefined, 'Old age index should be removed');

await db.close();
});

test('remove - cleans up indexes correctly', async t => {
t.plan(4);

await fs.rm('./testData', { recursive: true }).catch(() => {});
const db = await createDoubleDb('./testData');

// Insert initial document
const insertedRecord = await db.insert({
firstName: 'John',
lastName: 'Doe',
age: 30
});

// Remove the document
await db.remove(insertedRecord.id);

// Check if all indexes are removed
const firstNameIndex = await db.find('firstName', 'John');
t.equal(firstNameIndex, undefined, 'firstName index should be removed');

const lastNameIndex = await db.find('lastName', 'Doe');
t.equal(lastNameIndex, undefined, 'lastName index should be removed');

const ageIndex = await db.find('age', 30);
t.equal(ageIndex, undefined, 'age index should be removed');

// Check if the document is actually removed
const removedDocument = await db.read(insertedRecord.id);
t.equal(removedDocument, undefined, 'Document should be removed');

await db.close();
});

test.trigger();

0 comments on commit ca2018b

Please sign in to comment.