Skip to content

Commit

Permalink
chore: enable injected stores
Browse files Browse the repository at this point in the history
  • Loading branch information
mabels committed Jul 8, 2024
1 parent ae53adf commit 8a9231f
Show file tree
Hide file tree
Showing 24 changed files with 281 additions and 116 deletions.
8 changes: 7 additions & 1 deletion package-fireproof-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,11 @@
"url": "https://github.com/fireproof-storage/fireproof/issues"
},
"devDependencies": {},
"dependencies": {}
"dependencies": {
"@adviser/cement": "from-package-json",
"charwise": "from-package-json",
"prolly-trees": "from-package-json",
"ipfs-unixfs-exporter": "from-package-json",
"uuidv7": "from-package-json"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
},
"homepage": "https://github.com/fireproof-storage/fireproof#readme",
"dependencies": {
"@adviser/cement": "^0.1.19",
"@adviser/cement": "^0.1.20",
"@ipld/car": "^5.3.2",
"@ipld/dag-cbor": "^9.2.1",
"@ipld/dag-json": "^10.2.2",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions smoke/react/src/routes/Todo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ export default function TodoList() {
/>
<button
onClick={() => {
console.log(`saving todo-0: ${todo.text}`)
console.log(`saving todo-0: ${todo.text}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete (todo as any)._id;
console.log(`saving todo-1: ${todo.text}`)
console.log(`saving todo-1: ${todo.text}`);
// console.log("saving todo", todo, saveTodo.toString());
saveTodo()
.then(() => {
console.log(`saving todo-2: ${todo.text}`)
console.log(`saving todo-2: ${todo.text}`);
// console.log("saved todo", todo.text);
setTodo({ text: "", _id: undefined });
})
.catch((e) => console.error('Add-Todo Error:', e));
.catch((e) => console.error("Add-Todo Error:", e));
}}
>
Add Todo
Expand Down
34 changes: 17 additions & 17 deletions smoke/react/src/routes/todo-list.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import { expect, describe, it } from "vitest";
import { Database, fireproof } from "use-fireproof";

describe("<TodoList />", () => {
let fp: Database
let fp: Database;
afterEach(async () => {
console.log("ae-pre-destroy")
console.log("ae-pre-destroy");
await fp.destroy();
console.log("ae-post-destroy")
console.log("ae-post-destroy");
});
beforeEach(async () => {
console.log("be-pre-create")
console.log("be-pre-create");
fp = fireproof("TodoDB");
const all = await fp.allDocs();
for (const doc of all.rows) {
await fp.del(doc.key);
}
console.log("be-post-create")
console.log("be-post-create");
});
it.skip("it will render an text input and a button", async() => {
it.skip("it will render an text input and a button", async () => {
render(<TodoList />);
expect(await screen.findByPlaceholderText("new todo here")).not.toBeNull();
expect(await screen.findByText("Add Todo")).not.toBeNull();
Expand All @@ -30,7 +30,7 @@ describe("<TodoList />", () => {

it("it will add a new todo", async () => {
render(<TodoList />);
const input = await screen.findByPlaceholderText("new todo here") as HTMLInputElement;
const input = (await screen.findByPlaceholderText("new todo here")) as HTMLInputElement;
const button = await screen.findByText("Add Todo");

const values = Array(10)
Expand All @@ -47,40 +47,40 @@ describe("<TodoList />", () => {
});

it("it will mark a todo as completed", async () => {
console.log("pre-last")
console.log("pre-last");
render(<TodoList />);
console.log("pre-0")
console.log("pre-0");
// add todo
const input = await screen.findByPlaceholderText("new todo here");
const button = await screen.findByText("Add Todo");
const value = `ToComplete(${Math.random()})`;
await fireEvent.change(input, { target: { value } });
await fireEvent.click(button);
console.log("pre-1")
console.log("pre-1");

// open editor
const item = await screen.findByText(value);
console.log("pre-1.0")
console.log("pre-1.0");
expect(item).not.toBeNull();
console.log("pre-1.1")
console.log("pre-1.1");
const radio = item.parentNode?.querySelector("input[type=radio]") as HTMLInputElement;
console.log("pre-1.2")
console.log("pre-1.2");
await fireEvent.click(radio);
console.log("pre-2")
console.log("pre-2");

// check off todo
const textInput = (await screen.findByDisplayValue(value)) as HTMLInputElement;
const checkBox = textInput.parentNode?.querySelector("input[type=checkbox]") as HTMLInputElement;
expect(checkBox.checked).toBe(false);
await fireEvent.click(checkBox);
console.log("pre-3")
console.log("pre-3");

await waitFor(() => {
expect(checkBox.checked).toBe(true);
});
console.log("pre-4")
console.log("pre-4");
expect(item.attributeStyleMap.get("text-decoration")?.toString()).toBe("line-through");
console.log("post-last")
console.log("post-last");
// await new Promise((r) => setTimeout(r, 2000));
});
});
3 changes: 2 additions & 1 deletion src/blockstore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type {
DbMeta,
CommitOpts,
CryptoOpts,
StoreFactory,
StoreOpts,
StoreRuntime,
TransactionMeta,
Expand All @@ -26,7 +27,7 @@ export { ConnectREST, CarClockHead, Connectable, DbMetaEventBlock };

export { EncryptedBlockstore, BaseBlockstore, CompactionFetcher, type BlockFetcher, CarTransaction } from "./transaction.js";
export { Loader, Loadable } from "./loader.js";
export { DataStore, MetaStore } from "./store.js";
export { DataStore, DataSaveOpts, MetaStore } from "./store.js";
export { RemoteWAL, type WALState } from "./remote-wal.js";
export { parseCarFile } from "./loader-helpers.js";
export { ConnectionBase } from "./connection-base.js";
55 changes: 47 additions & 8 deletions src/blockstore/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ export abstract class Loadable {
abstract handleDbMetasFromStore(metas: DbMeta[]): Promise<void>;
}

interface Startable {
start(): Promise<void>;
}

class EnsureStart<T extends Startable> {
readonly oncePerStore = new ResolveOnce<T>();

reset() {
this.oncePerStore.reset();
}
once(fn: () => Promise<T>) {
return this.oncePerStore.once(async () => {
const ret = await fn();
await ret.start();
return ret;
});
}
}

export class Loader implements Loadable {
readonly name: string;
readonly ebOpts: BlockstoreRuntime;
Expand All @@ -91,19 +110,31 @@ export class Loader implements Loadable {

// readonly id = uuidv4();

readonly ensureCarStore = new EnsureStart<DataStore>();
async carStore(): Promise<DataStore> {
return this.ebOpts.store.makeDataStore(this);
return this.ensureCarStore.once(() => {
return this.ebOpts.store.makeDataStore(this);
});
}

readonly ensureFileStore = new EnsureStart<DataStore>();
async fileStore(): Promise<DataStore> {
return this.ebOpts.store.makeDataStore(this);
return this.ensureFileStore.once(() => {
return this.ebOpts.store.makeDataStore(this);
});
}
readonly ensureRemoteFileStore = new EnsureStart<RemoteWAL>();
async remoteWAL(): Promise<RemoteWAL> {
return this.ebOpts.store.makeRemoteWAL(this);
return this.ensureRemoteFileStore.once(() => {
return this.ebOpts.store.makeRemoteWAL(this);
});
}

readonly ensureMetaStore = new EnsureStart<MetaStore>();
async metaStore(): Promise<MetaStore> {
return this.ebOpts.store.makeMetaStore(this);
return this.ensureMetaStore.once(() => {
return this.ebOpts.store.makeMetaStore(this);
});
}

readonly onceReady = new ResolveOnce<void>();
Expand All @@ -118,7 +149,15 @@ export class Loader implements Loadable {

async close() {
const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
await Promise.all(toClose.map((store) => store.close()));
await Promise.all(
toClose.map((store) => {
store.close();
}),
);
this.ensureCarStore.reset();
this.ensureFileStore.reset();
this.ensureRemoteFileStore.reset();
this.ensureMetaStore.reset();
}

async destroy() {
Expand Down Expand Up @@ -331,9 +370,9 @@ export class Loader implements Loadable {
t: CarTransaction,
): Promise<{ cid: AnyLink; bytes: Uint8Array }> {
try {
return theKey && this.ebOpts.crypto
? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, cid, t)
: await encodeCarFile([cid], t);
return theKey && this.ebOpts.crypto
? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, cid, t)
: await encodeCarFile([cid], t);
} catch (e) {
console.error("error creating car file", e);
throw e;
Expand Down
8 changes: 5 additions & 3 deletions src/blockstore/remote-wal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export abstract class RemoteWAL {

readonly _ready = new ResolveOnce<void>();

async ready() {
private async ready() {
return this._ready.once(async () => {
const walState = await this._load().catch((e) => {
this.logger.Error().Any("error", e).Msg("error loading wal");
Expand All @@ -47,10 +47,10 @@ export abstract class RemoteWAL {

readonly logger: Logger;

constructor(loader: Loadable, url: URL) {
constructor(loader: Loadable, url: URL, logger: Logger) {
this.logger = logger;
this.loader = loader;
this.url = url;
this.logger = loader.logger;
}

async enqueue(dbMeta: DbMeta, opts: CommitOpts) {
Expand Down Expand Up @@ -165,6 +165,8 @@ export abstract class RemoteWAL {
await rmlp;
}

abstract start(): Promise<void>;

async load(): Promise<WALState | Falsy> {
await this.ready();
return await this._load();
Expand Down
37 changes: 23 additions & 14 deletions src/blockstore/store-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import { DataStore, MetaStore } from "./store.js";
import { StoreOpts, StoreRuntime, TestStore } from "./types.js";
import { ensureLogger } from "../utils.js";

function ensureIsIndex(url: URL, isIndex?: boolean): URL {
function ensureIsIndex(url: URL, isIndex?: string): URL {
if (isIndex) {
url.searchParams.set("index", "idx");
url.searchParams.set("index", isIndex);
return url;
} else {
url.searchParams.delete("index");
return url;
}
}

export function toURL(pathOrUrl: string | URL, isIndex?: boolean): URL {
export function toURL(pathOrUrl: string | URL, isIndex?: string): URL {
if (pathOrUrl instanceof URL) return ensureIsIndex(pathOrUrl, isIndex);
try {
const url = new URL(pathOrUrl);
Expand Down Expand Up @@ -164,22 +164,31 @@ export async function testStoreFactory(url: URL, ilogger?: Logger): Promise<Test
export function toStoreRuntime(name: string | undefined = undefined, opts: StoreOpts = {}): StoreRuntime {
return {
makeMetaStore: (loader: Loadable) => {
return cacheStore(toURL(opts.stores?.meta || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
meta: metaStoreFactory,
});
return (
opts.makeMetaStore?.(loader) ||
cacheStore(toURL(opts.stores?.meta || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
meta: metaStoreFactory,
})
);
},
makeDataStore: (loader: Loadable) => {
return cacheStore(toURL(opts.stores?.data || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
data: dataStoreFactory,
});
return (
opts.makeDataStore?.(loader) ||
cacheStore(toURL(opts.stores?.data || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
data: dataStoreFactory,
})
);
},
makeRemoteWAL: (loader: Loadable) => {
return cacheStore(toURL(opts.stores?.remoteWAL || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
remoteWAL: remoteWalFactory,
});
return (
opts.makeRemoteWAL?.(loader) ||
cacheStore(toURL(opts.stores?.remoteWAL || dataDir(name || loader.name, opts.stores?.base), opts.isIndex), loader, {
remoteWAL: remoteWalFactory,
})
);
},

encodeFile,
decodeFile,
encodeFile: opts.encodeFile || encodeFile,
decodeFile: opts.decodeFile || decodeFile,
};
}
Loading

0 comments on commit 8a9231f

Please sign in to comment.