feat: release 3.0.0
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { IndexedDbCache } from "../src/databases/indexeddb/cache.ts";
|
||||
import type { Options } from "../src/storage/storage.ts";
|
||||
import type { WithId } from "../src/types.ts";
|
||||
|
||||
describe("IndexedDbCache", () => {
|
||||
let cache: IndexedDbCache;
|
||||
|
||||
beforeEach(() => {
|
||||
cache = new IndexedDbCache();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cache.flush();
|
||||
});
|
||||
|
||||
const sampleDocuments: WithId<{ name: string }>[] = [
|
||||
{ id: "doc1", name: "Document 1" },
|
||||
{ id: "doc2", name: "Document 2" },
|
||||
];
|
||||
|
||||
const sampleCriteria = { name: { $eq: "Document 1" } };
|
||||
const sampleOptions: Options = { sort: { name: 1 } };
|
||||
|
||||
it("hash", () => {
|
||||
const hashCode = cache.hash(sampleCriteria, sampleOptions);
|
||||
expect(typeof hashCode).toBe("number");
|
||||
});
|
||||
|
||||
it("set and get", () => {
|
||||
const hashCode = cache.hash(sampleCriteria, sampleOptions);
|
||||
cache.set(hashCode, sampleDocuments);
|
||||
const result = cache.get(hashCode);
|
||||
expect(result).toEqual(sampleDocuments);
|
||||
});
|
||||
|
||||
it("get undefined", () => {
|
||||
const hashCode = cache.hash(sampleCriteria, sampleOptions);
|
||||
const result = cache.get(hashCode);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("flush", () => {
|
||||
const hashCode = cache.hash(sampleCriteria, sampleOptions);
|
||||
cache.set(hashCode, sampleDocuments);
|
||||
cache.flush();
|
||||
const result = cache.get(hashCode);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
import { describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { hashCodeQuery } from "../src/hash.ts";
|
||||
import type { Options } from "../src/mod.ts";
|
||||
|
||||
describe("hashCodeQuery", () => {
|
||||
const filter = { name: { $eq: "Document 1" } };
|
||||
const options: Options = { sort: { name: 1 } };
|
||||
|
||||
it("return correct hash code", () => {
|
||||
const hashCode = hashCodeQuery(filter, options);
|
||||
expect(typeof hashCode).toBe("number");
|
||||
});
|
||||
});
|
||||
307
tests/index-manager.test.ts
Normal file
307
tests/index-manager.test.ts
Normal file
@@ -0,0 +1,307 @@
|
||||
import { describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { IndexManager, type IndexSpec } from "../src/index/manager.ts";
|
||||
|
||||
describe("IndexManager", () => {
|
||||
type User = {
|
||||
id: string;
|
||||
email: string;
|
||||
group: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
const specs: IndexSpec<User>[] = [
|
||||
{ field: "id", kind: "primary" },
|
||||
{ field: "email", kind: "unique" },
|
||||
{ field: "group", kind: "shared" },
|
||||
];
|
||||
|
||||
it("should insert and retrieve documents by primary, unique, and shared indexes", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user1: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
const user2: User = { id: "u2", email: "b@example.com", group: "staff", name: "Bob" };
|
||||
const user3: User = { id: "u3", email: "c@example.com", group: "admin", name: "Carol" };
|
||||
|
||||
// insert
|
||||
manager.insert(user1);
|
||||
manager.insert(user2);
|
||||
manager.insert(user3);
|
||||
|
||||
// primary lookup
|
||||
expect(manager.getByPrimary("u1")).toEqual(user1);
|
||||
expect(manager.getByPrimary("u2")).toEqual(user2);
|
||||
expect(manager.getByPrimary("u3")).toEqual(user3);
|
||||
|
||||
// unique lookup
|
||||
expect(manager.getByUnique("email", "a@example.com")).toEqual(user1);
|
||||
expect(manager.getByUnique("email", "b@example.com")).toEqual(user2);
|
||||
|
||||
// shared lookup
|
||||
const staff = manager.getByIndex("group", "staff");
|
||||
expect(staff).toHaveLength(2);
|
||||
expect(staff).toContainEqual(user1);
|
||||
expect(staff).toContainEqual(user2);
|
||||
|
||||
const admin = manager.getByIndex("group", "admin");
|
||||
expect(admin).toHaveLength(1);
|
||||
expect(admin[0]).toEqual(user3);
|
||||
|
||||
// unknown lookup
|
||||
expect(manager.getByPrimary("unknown")).toBeUndefined();
|
||||
expect(manager.getByUnique("email", "notfound@example.com")).toBeUndefined();
|
||||
expect(manager.getByIndex("group", "none")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should enforce unique constraints", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
manager.insert(user);
|
||||
|
||||
const dupEmail: User = { id: "u2", email: "a@example.com", group: "admin", name: "Bob" };
|
||||
expect(() => manager.insert(dupEmail)).toThrow(/Unique constraint violation/);
|
||||
});
|
||||
|
||||
it("should remove documents and clean up indexes", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
manager.insert(user);
|
||||
|
||||
// sanity
|
||||
expect(manager.getByPrimary("u1")).toEqual(user);
|
||||
expect(manager.getByUnique("email", "a@example.com")).toEqual(user);
|
||||
expect(manager.getByIndex("group", "staff")).toContainEqual(user);
|
||||
|
||||
// remove
|
||||
manager.remove(user);
|
||||
|
||||
expect(manager.getByPrimary("u1")).toBeUndefined();
|
||||
expect(manager.getByUnique("email", "a@example.com")).toBeUndefined();
|
||||
expect(manager.getByIndex("group", "staff")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should update existing documents", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
manager.insert(user);
|
||||
|
||||
// update email and group
|
||||
const updated: User = { ...user, email: "a_new@example.com", group: "admin" };
|
||||
manager.update(updated);
|
||||
|
||||
// old unique index cleared
|
||||
expect(manager.getByUnique("email", "a@example.com")).toBeUndefined();
|
||||
|
||||
// new unique index works
|
||||
expect(manager.getByUnique("email", "a_new@example.com")).toEqual(updated);
|
||||
|
||||
// old shared index cleared
|
||||
expect(manager.getByIndex("group", "staff")).toEqual([]);
|
||||
|
||||
// new shared index works
|
||||
expect(manager.getByIndex("group", "admin")).toContainEqual(updated);
|
||||
|
||||
// primary still points to updated document
|
||||
expect(manager.getByPrimary("u1")).toEqual(updated);
|
||||
});
|
||||
|
||||
it("should perform upsert if primary key does not exist", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
|
||||
// update on non-existent PK acts as insert
|
||||
manager.update(user);
|
||||
|
||||
expect(manager.getByPrimary("u1")).toEqual(user);
|
||||
expect(manager.getByUnique("email", "a@example.com")).toEqual(user);
|
||||
expect(manager.getByIndex("group", "staff")).toContainEqual(user);
|
||||
});
|
||||
|
||||
it("should lazily clean up stale shared index references", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user: User = { id: "u1", email: "a@example.com", group: "staff", name: "Alice" };
|
||||
manager.insert(user);
|
||||
|
||||
// manually delete primary without cleaning shared
|
||||
manager.primary.delete("u1");
|
||||
|
||||
// getByIndex should remove stale reference
|
||||
const result = manager.getByIndex("group", "staff");
|
||||
expect(result).toEqual([]);
|
||||
// after lazy cleanup, lookup should also be empty
|
||||
expect(manager.getPrimaryKeysByIndex("group", "staff")).toEqual(new Set());
|
||||
});
|
||||
|
||||
describe(".getByCondition", () => {
|
||||
type User = {
|
||||
id: string;
|
||||
email: string;
|
||||
group: string;
|
||||
name: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
const specs: IndexSpec<User>[] = [
|
||||
{ field: "id", kind: "primary" },
|
||||
{ field: "email", kind: "unique" },
|
||||
{ field: "group", kind: "shared" },
|
||||
];
|
||||
|
||||
it("should find documents by primary key", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user = { id: "u1", email: "a@example.com", group: "staff", name: "Alice", active: true };
|
||||
manager.insert(user);
|
||||
|
||||
const results = manager.getByCondition({ id: "u1" });
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0]).toEqual(user);
|
||||
});
|
||||
|
||||
it("should find documents by unique index", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user = { id: "u1", email: "a@example.com", group: "staff", name: "Alice", active: true };
|
||||
manager.insert(user);
|
||||
|
||||
const results = manager.getByCondition({ email: "a@example.com" });
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0]).toEqual(user);
|
||||
});
|
||||
|
||||
it("should find documents by shared index", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user1 = { id: "u1", email: "a@example.com", group: "staff", name: "Alice", active: true };
|
||||
const user2 = { id: "u2", email: "b@example.com", group: "staff", name: "Bob", active: false };
|
||||
const user3 = { id: "u3", email: "c@example.com", group: "admin", name: "Carol", active: true };
|
||||
|
||||
manager.insert(user1);
|
||||
manager.insert(user2);
|
||||
manager.insert(user3);
|
||||
|
||||
const staff = manager.getByCondition({ group: "staff" });
|
||||
expect(staff).toHaveLength(2);
|
||||
expect(staff).toContainEqual(user1);
|
||||
expect(staff).toContainEqual(user2);
|
||||
|
||||
const admin = manager.getByCondition({ group: "admin" });
|
||||
expect(admin).toHaveLength(1);
|
||||
expect(admin[0]).toEqual(user3);
|
||||
});
|
||||
|
||||
it("should handle multiple fields with intersection", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user1 = { id: "u1", email: "a@example.com", group: "staff", name: "Alice", active: true };
|
||||
const user2 = { id: "u2", email: "b@example.com", group: "staff", name: "Bob", active: false };
|
||||
manager.insert(user1);
|
||||
manager.insert(user2);
|
||||
|
||||
// Lookup by shared + non-indexed field
|
||||
const results = manager.getByCondition({ group: "staff", active: true });
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0]).toEqual(user1);
|
||||
});
|
||||
|
||||
it("should return empty array if no match", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const user = { id: "u1", email: "a@example.com", group: "staff", name: "Alice", active: true };
|
||||
manager.insert(user);
|
||||
|
||||
const results = manager.getByCondition({ group: "admin" });
|
||||
expect(results).toEqual([]);
|
||||
|
||||
const results2 = manager.getByCondition({ email: "nonexistent@example.com" });
|
||||
expect(results2).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("IndexManager Performance", () => {
|
||||
type User = {
|
||||
id: string;
|
||||
email: string;
|
||||
group: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
const NUM_RECORDS = 100_000;
|
||||
|
||||
const specs: IndexSpec<User>[] = [
|
||||
{ field: "id", kind: "primary" },
|
||||
{ field: "email", kind: "unique" },
|
||||
{ field: "group", kind: "shared" },
|
||||
];
|
||||
|
||||
it("should insert and query thousands of records efficiently", () => {
|
||||
const manager = new IndexManager<User>(specs);
|
||||
|
||||
const groups = ["staff", "admin", "guest", "manager"];
|
||||
|
||||
console.time("Insert 100k records");
|
||||
for (let i = 0; i < NUM_RECORDS; i++) {
|
||||
const user: User = {
|
||||
id: `user_${i}`,
|
||||
email: `user_${i}@example.com`,
|
||||
group: groups[i % groups.length],
|
||||
name: `User ${i}`,
|
||||
};
|
||||
manager.insert(user);
|
||||
}
|
||||
console.timeEnd("Insert 100k records");
|
||||
|
||||
// Check total number of records
|
||||
expect(manager.getByPrimary("user_0")?.name).toEqual("User 0");
|
||||
expect(manager.getByPrimary(`user_${NUM_RECORDS - 1}`)?.name).toEqual(`User ${NUM_RECORDS - 1}`);
|
||||
|
||||
// Unique lookup
|
||||
console.time("Unique lookup 10k");
|
||||
for (let i = 0; i < 10_000; i++) {
|
||||
const user = manager.getByUnique("email", `user_${i}@example.com`);
|
||||
expect(user?.id).toEqual(`user_${i}`);
|
||||
}
|
||||
console.timeEnd("Unique lookup 10k");
|
||||
|
||||
// Shared lookup
|
||||
console.time("Shared lookup");
|
||||
for (const group of groups) {
|
||||
const users = manager.getByIndex("group", group);
|
||||
expect(users.length).toBeGreaterThan(0);
|
||||
}
|
||||
console.timeEnd("Shared lookup");
|
||||
|
||||
// Update some users
|
||||
console.time("Update 10k records");
|
||||
for (let i = 0; i < 10_000; i++) {
|
||||
const user = manager.getByPrimary(`user_${i}`);
|
||||
if (!user) {
|
||||
continue;
|
||||
}
|
||||
const updated = { ...user, group: groups[(i + 1) % groups.length] };
|
||||
manager.update(updated);
|
||||
}
|
||||
console.timeEnd("Update 10k records");
|
||||
|
||||
// Remove some users
|
||||
console.time("Remove 10k records");
|
||||
for (let i = 0; i < 10_000; i++) {
|
||||
const user = manager.getByPrimary(`user_${i}`);
|
||||
if (user) {
|
||||
manager.remove(user);
|
||||
}
|
||||
}
|
||||
console.timeEnd("Remove 10k records");
|
||||
|
||||
// Spot check
|
||||
expect(manager.getByPrimary("user_0")).toBeUndefined();
|
||||
expect(manager.getByPrimary(`user_${10_001}`)).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
116
tests/indexeddb-storage.test.ts
Normal file
116
tests/indexeddb-storage.test.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { afterAll, afterEach, beforeAll, describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import "fake-indexeddb/auto";
|
||||
|
||||
import z from "zod";
|
||||
|
||||
import { IndexedDB } from "../src/databases/indexeddb/database.ts";
|
||||
import type { DBLogger } from "../src/logger.ts";
|
||||
|
||||
const log: DBLogger = () => {};
|
||||
|
||||
describe("IndexedDB Storage Integration", { sanitizeOps: false, sanitizeResources: false }, () => {
|
||||
let db: IndexedDB<{ name: string; registrars: any[]; log?: DBLogger }>;
|
||||
|
||||
let collection: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = new IndexedDB({
|
||||
name: "test-db",
|
||||
registrars: [
|
||||
{
|
||||
name: "users",
|
||||
schema: {
|
||||
id: z.string(),
|
||||
name: z.string().optional(),
|
||||
age: z.number().optional(),
|
||||
},
|
||||
indexes: [
|
||||
{ field: "id", kind: "primary" },
|
||||
{ field: "name", kind: "unique" },
|
||||
],
|
||||
},
|
||||
],
|
||||
log,
|
||||
});
|
||||
|
||||
collection = db.collection("users");
|
||||
|
||||
await collection.storage.resolve();
|
||||
await collection.flush();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.flush();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
it("should insert and find documents", async () => {
|
||||
await collection.storage.insert([
|
||||
{ id: "1", name: "Alice", age: 30 },
|
||||
{ id: "2", name: "Bob", age: 25 },
|
||||
]);
|
||||
|
||||
const all = await collection.storage.find({});
|
||||
expect(all).toHaveLength(2);
|
||||
|
||||
const alice = await collection.storage.find({ name: "Alice" });
|
||||
expect(alice).toHaveLength(1);
|
||||
expect(alice[0].age).toBe(30);
|
||||
});
|
||||
|
||||
it("should get documents by index", async () => {
|
||||
await collection.storage.insert([{ id: "1", name: "Alice" }]);
|
||||
const byIndex = await collection.storage.getByIndex("id", "1");
|
||||
expect(byIndex).toHaveLength(1);
|
||||
expect(byIndex[0].name).toBe("Alice");
|
||||
});
|
||||
|
||||
it("should update documents", async () => {
|
||||
await collection.storage.insert([{ id: "1", name: "Alice", age: 30 }]);
|
||||
|
||||
const result = await collection.storage.update({ id: "1" }, { $set: { age: 31 } });
|
||||
expect(result.matchedCount).toBe(1);
|
||||
expect(result.modifiedCount).toBe(1);
|
||||
|
||||
const updated = await collection.storage.find({ id: "1" });
|
||||
expect(updated[0].age).toBe(31);
|
||||
});
|
||||
|
||||
it("should remove documents", async () => {
|
||||
await collection.storage.insert([
|
||||
{ id: "1", name: "Alice" },
|
||||
{ id: "2", name: "Bob" },
|
||||
]);
|
||||
|
||||
const removedCount = await collection.storage.remove({ name: "Bob" });
|
||||
expect(removedCount).toBe(1);
|
||||
|
||||
const remaining = await collection.storage.find({});
|
||||
expect(remaining).toHaveLength(1);
|
||||
expect(remaining[0].name).toBe("Alice");
|
||||
});
|
||||
|
||||
it("should count documents", async () => {
|
||||
await collection.storage.insert([
|
||||
{ id: "1", age: 30 },
|
||||
{ id: "2", age: 25 },
|
||||
{ id: "3", age: 30 },
|
||||
]);
|
||||
|
||||
const count = await collection.storage.count({ age: 30 });
|
||||
expect(count).toBe(2);
|
||||
});
|
||||
|
||||
it("should flush the collection", async () => {
|
||||
await collection.storage.insert([{ id: "1", name: "Alice" }]);
|
||||
await collection.flush();
|
||||
|
||||
const all = await collection.storage.find({});
|
||||
expect(all).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
import "fake-indexeddb/auto";
|
||||
|
||||
import { describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { Collection } from "../src/collection.ts";
|
||||
import { MemoryStorage } from "../src/databases/memory/storage.ts";
|
||||
import { DuplicateDocumentError } from "../src/storage/errors.ts";
|
||||
import { getUsers } from "./users.mock.ts";
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Unit Tests
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
describe("Storage Insert", () => {
|
||||
it("should successfully insert a new document", async () => {
|
||||
const collection = new Collection("users", new MemoryStorage("users"));
|
||||
const users = getUsers();
|
||||
await collection.insertMany(users);
|
||||
expect(await collection.storage.findById(users[0].id)).toEqual(users[0]);
|
||||
expect(await collection.storage.findById(users[1].id)).toEqual(users[1]);
|
||||
collection.storage.destroy();
|
||||
});
|
||||
|
||||
it("should throw an error if the document already exists", async () => {
|
||||
const collection = new Collection("users", new MemoryStorage("users"));
|
||||
const users = getUsers();
|
||||
try {
|
||||
await collection.insertOne(users[0]);
|
||||
} catch (err) {
|
||||
expect(err instanceof DuplicateDocumentError).toEqual(true);
|
||||
expect(err).toEqual(new DuplicateDocumentError(users[0], collection.storage));
|
||||
}
|
||||
collection.storage.destroy();
|
||||
});
|
||||
});
|
||||
93
tests/memory-storage.test.ts
Normal file
93
tests/memory-storage.test.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { MemoryStorage } from "../src/databases/memory/storage.ts";
|
||||
|
||||
interface TestDoc {
|
||||
id: string;
|
||||
name?: string;
|
||||
age?: number;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
describe("MemoryStorage", () => {
|
||||
it("should insert new records", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
const documents: TestDoc[] = [{ id: "abc", name: "Alice", age: 30 }];
|
||||
|
||||
await storage.insert(documents);
|
||||
|
||||
expect(storage.documents).toHaveLength(1);
|
||||
expect(storage.documents[0]).toEqual(documents[0]);
|
||||
});
|
||||
|
||||
it("should retrieve records by index", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
await storage.insert([
|
||||
{ id: "abc", name: "Alice" },
|
||||
{ id: "def", name: "Bob" },
|
||||
]);
|
||||
|
||||
const result = await storage.getByIndex("id", "abc");
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].name).toBe("Alice");
|
||||
});
|
||||
|
||||
it("should find documents by criteria", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
await storage.insert([
|
||||
{ id: "1", name: "Alice", age: 30 },
|
||||
{ id: "2", name: "Bob", age: 25 },
|
||||
{ id: "3", name: "Charlie", age: 30 },
|
||||
]);
|
||||
|
||||
const results = await storage.find({ age: 30 });
|
||||
expect(results).toHaveLength(2);
|
||||
expect(results.map((r) => r.name).sort()).toEqual(["Alice", "Charlie"]);
|
||||
});
|
||||
|
||||
it("should update documents matching a condition", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
await storage.insert([{ id: "1", name: "Alice", age: 30 }]);
|
||||
|
||||
const updateResult = await storage.update({ id: "1" }, { $set: { age: 31 } });
|
||||
expect(updateResult.matchedCount).toBe(1);
|
||||
expect(updateResult.modifiedCount).toBe(1);
|
||||
|
||||
const updated = await storage.find({ id: "1" });
|
||||
expect(updated[0].age).toBe(31);
|
||||
});
|
||||
|
||||
it("should remove documents by condition", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
await storage.insert([
|
||||
{ id: "1", name: "Alice" },
|
||||
{ id: "2", name: "Bob" },
|
||||
]);
|
||||
|
||||
const removedCount = await storage.remove({ name: "Bob" });
|
||||
expect(removedCount).toBe(1);
|
||||
|
||||
const remaining = await storage.find({});
|
||||
expect(remaining).toHaveLength(1);
|
||||
expect(remaining[0].name).toBe("Alice");
|
||||
});
|
||||
|
||||
it("should count documents matching a condition", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
await storage.insert([
|
||||
{ id: "1", name: "Alice", age: 30 },
|
||||
{ id: "2", name: "Bob", age: 25 },
|
||||
{ id: "3", name: "Charlie", age: 30 },
|
||||
]);
|
||||
|
||||
const count = await storage.count({ age: 30 });
|
||||
expect(count).toBe(2);
|
||||
});
|
||||
|
||||
it("should return itself from resolve", async () => {
|
||||
const storage = new MemoryStorage<TestDoc>("test", [{ field: "id", kind: "primary" }]);
|
||||
const resolved = await storage.resolve();
|
||||
expect(resolved).toBe(storage);
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import { describe, it } from "@std/testing/bdd";
|
||||
import { expect } from "expect";
|
||||
|
||||
import { Collection } from "../src/collection.ts";
|
||||
import { MemoryStorage } from "../src/databases/memory/storage.ts";
|
||||
import { RemoveResult } from "../src/storage/operators/remove.ts";
|
||||
import { getUsers } from "./users.mock.ts";
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Unit Tests
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
describe("Storage Remove", () => {
|
||||
it("should successfully delete document", async () => {
|
||||
const collection = new Collection("users", new MemoryStorage("users"));
|
||||
const users = getUsers();
|
||||
await collection.insertMany(users);
|
||||
expect(await collection.remove({ id: "user-1" })).toEqual(new RemoveResult(1));
|
||||
collection.storage.destroy();
|
||||
});
|
||||
});
|
||||
1446
tests/update.test.ts
1446
tests/update.test.ts
File diff suppressed because it is too large
Load Diff
@@ -1,43 +0,0 @@
|
||||
const users: UserDocument[] = [
|
||||
{
|
||||
id: "user-1",
|
||||
name: "John Doe",
|
||||
email: "john.doe@test.none",
|
||||
friends: [
|
||||
{
|
||||
id: "user-2",
|
||||
alias: "Jane",
|
||||
},
|
||||
],
|
||||
interests: ["movies", "tv", "sports"],
|
||||
},
|
||||
{
|
||||
id: "user-2",
|
||||
name: "Jane Doe",
|
||||
email: "jane.doe@test.none",
|
||||
friends: [
|
||||
{
|
||||
id: "user-1",
|
||||
alias: "John",
|
||||
},
|
||||
],
|
||||
interests: ["movies", "fitness", "dance"],
|
||||
},
|
||||
];
|
||||
|
||||
export function getUsers(): UserDocument[] {
|
||||
return JSON.parse(JSON.stringify(users));
|
||||
}
|
||||
|
||||
export type UserDocument = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
friends: Friend[];
|
||||
interests: string[];
|
||||
};
|
||||
|
||||
type Friend = {
|
||||
id: string;
|
||||
alias: string;
|
||||
};
|
||||
Reference in New Issue
Block a user