Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete by query #64

Merged
merged 1 commit into from
Jan 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { bulkInsert, insert } from "./src/operations/insert.ts";
import { get } from "./src/operations/get.ts";
import { update } from "./src/operations/update.ts";
import { drop } from "./src/operations/drop.ts";
import { del } from "./src/operations/delete.ts";
import { deleteByKey, deleteByQuery } from "./src/operations/delete.ts";
import { select } from "./src/operations/select.ts";
import {
deleteTenant,
Expand Down Expand Up @@ -119,8 +119,27 @@ export function start(directory: string) {
}

case "delete": {
del(directory, tenant, table, key);
break;
let res: Response | undefined;
if (key) {
return new Response(
JSON.stringify(deleteByKey(directory, tenant, table, key)),
{ status: 200 },
);
}

if (body.where) {
return new Response(
JSON.stringify(
deleteByQuery(directory, tenant, table, body.where),
),
{ status: 200 },
);
}

if (!res) {
throw "You must include either a key or a query";
}
return res;
}

case "get": {
Expand Down
27 changes: 23 additions & 4 deletions mod_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,14 +685,33 @@ Deno.test({
basicFetchOptions,
);

assertEquals(await req.text(), "success");
assertEquals(await req.json(), yogiKey);

req = await fetch(
`http://localhost:8777/delete/tableWithSchema/${olekKey}`,
basicFetchOptions,
);

assertEquals(await req.text(), "success");
assertEquals(await req.json(), olekKey);
},
sanitizeResources: false,
sanitizeOps: false,
});

Deno.test({
name: "Able to delete documents by key",
async fn() {
const req = await fetch(
`http://localhost:8777/delete/table`,
{
...basicFetchOptions,
body: JSON.stringify({
where: "starts_with($name, 'Yogi')",
}),
},
);

assertEquals((await req.json()).sort(), yogiKeys.sort());
},
sanitizeResources: false,
sanitizeOps: false,
Expand All @@ -706,7 +725,7 @@ Deno.test({
basicFetchOptions,
);

assertEquals(await req.json(), { schema: null, size: 441 });
assertEquals(await req.json(), { schema: null, size: 0 });

req = await fetch(
`http://localhost:8777/meta/tableWithSchema`,
Expand Down Expand Up @@ -751,7 +770,7 @@ Deno.test({
},
},
},
size: 1733,
size: 848,
});
},
sanitizeResources: false,
Expand Down
61 changes: 59 additions & 2 deletions src/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {
writeMeta,
} from "../util/fileOperations.ts";
import { unindexDocument } from "../util/indexDocument.ts";
import { Chunk } from "../util/types.ts";
import { select } from "./select.ts";

/**
* Delete a document by key from a table.
* Named this way to avoid naming conflict with javascript built-in.
*/
export function del(
export function deleteByKey(
directory: string,
tenant: string,
table: string,
Expand Down Expand Up @@ -56,3 +57,59 @@ export function del(

return key;
}

/**
* Delete documents by query from a table.
*/
export function deleteByQuery(
directory: string,
tenant: string,
table: string,
where: string,
) {
// Get documents using a basic select, ideally we would seperate this but eh
const documents = select(directory, tenant, table, {
where,
maxResults: -1,
expandKeys: false,
});

const meta = readMeta(directory, tenant);
const schema = meta.table_index[table].schema;
const chunks: Record<string, Chunk> = {};

for (const document of documents) {
const key = document.key as string;
const chunkName = meta.key_index[key][1];

// Delete key from key_index
delete meta.key_index[key];

if (!(chunkName in chunks)) {
chunks[chunkName] = readChunk(directory, tenant, chunkName);
}

// Unindex document
if (schema) {
unindexDocument(chunks[chunkName][key], schema, meta, table);
}

delete chunks[chunkName][key];
}

for (const [chunkName, chunk] of Object.entries(chunks)) {
// Delete chunk if empty, otherwise just update it
if (Object.keys(chunk).length === 0) {
deleteChunk(directory, tenant, chunkName);

const index = meta.table_index[table].chunks.indexOf(chunkName);
meta.table_index[table].chunks.splice(index, 1);
} else {
writeChunk(directory, tenant, chunkName, chunk);
}
}

writeMeta(directory, tenant, meta);

return documents.map((doc) => doc.key);
}