Execute oxfmt (#1166)
Ran pnpm oxfmt . This should get the web repo aligned so that we can better enforce oxfmt going forward.
This commit is contained in:
@@ -14,8 +14,13 @@ describe("SqlocalDraftRepository", () => {
|
||||
});
|
||||
|
||||
it("save then load returns the same text", async () => {
|
||||
await repo.save({ kind: "channel", channel: ChannelNumber.Primary }, "hello");
|
||||
expect(await repo.load({ kind: "channel", channel: ChannelNumber.Primary })).toBe("hello");
|
||||
await repo.save(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
"hello",
|
||||
);
|
||||
expect(
|
||||
await repo.load({ kind: "channel", channel: ChannelNumber.Primary }),
|
||||
).toBe("hello");
|
||||
});
|
||||
|
||||
it("save with empty text deletes the row", async () => {
|
||||
@@ -25,9 +30,14 @@ describe("SqlocalDraftRepository", () => {
|
||||
});
|
||||
|
||||
it("clear removes the row", async () => {
|
||||
await repo.save({ kind: "channel", channel: ChannelNumber.Channel1 }, "draft");
|
||||
await repo.save(
|
||||
{ kind: "channel", channel: ChannelNumber.Channel1 },
|
||||
"draft",
|
||||
);
|
||||
await repo.clear({ kind: "channel", channel: ChannelNumber.Channel1 });
|
||||
expect(await repo.load({ kind: "channel", channel: ChannelNumber.Channel1 })).toBe("");
|
||||
expect(
|
||||
await repo.load({ kind: "channel", channel: ChannelNumber.Channel1 }),
|
||||
).toBe("");
|
||||
});
|
||||
|
||||
it("upsert overwrites prior text without throwing", async () => {
|
||||
@@ -38,10 +48,20 @@ describe("SqlocalDraftRepository", () => {
|
||||
|
||||
it("scoped per device_id", async () => {
|
||||
const repoB = new SqlocalDraftRepository(db, { deviceId: 2 });
|
||||
await repo.save({ kind: "channel", channel: ChannelNumber.Primary }, "from-1");
|
||||
await repoB.save({ kind: "channel", channel: ChannelNumber.Primary }, "from-2");
|
||||
expect(await repo.load({ kind: "channel", channel: ChannelNumber.Primary })).toBe("from-1");
|
||||
expect(await repoB.load({ kind: "channel", channel: ChannelNumber.Primary })).toBe("from-2");
|
||||
await repo.save(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
"from-1",
|
||||
);
|
||||
await repoB.save(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
"from-2",
|
||||
);
|
||||
expect(
|
||||
await repo.load({ kind: "channel", channel: ChannelNumber.Primary }),
|
||||
).toBe("from-1");
|
||||
expect(
|
||||
await repoB.load({ kind: "channel", channel: ChannelNumber.Primary }),
|
||||
).toBe("from-2");
|
||||
});
|
||||
|
||||
it("loadAll returns all drafts for the device", async () => {
|
||||
|
||||
@@ -65,17 +65,24 @@ export class SqlocalDraftRepository implements DraftRepository {
|
||||
);
|
||||
}
|
||||
|
||||
async loadAll(): Promise<ReadonlyArray<{ key: ConversationKey; text: string }>> {
|
||||
async loadAll(): Promise<
|
||||
ReadonlyArray<{ key: ConversationKey; text: string }>
|
||||
> {
|
||||
const rows = await this.db
|
||||
.select({ conversationKey: drafts.conversationKey, text: drafts.text })
|
||||
.from(drafts)
|
||||
.where(eq(drafts.deviceId, this.deviceId));
|
||||
return rows.map((r) => ({ key: parseKey(r.conversationKey), text: r.text }));
|
||||
return rows.map((r) => ({
|
||||
key: parseKey(r.conversationKey),
|
||||
text: r.text,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function parseKey(s: string): ConversationKey {
|
||||
if (s.startsWith("channel:")) return { kind: "channel", channel: Number(s.slice(8)) };
|
||||
if (s.startsWith("direct:")) return { kind: "direct", peer: Number(s.slice(7)) };
|
||||
if (s.startsWith("channel:"))
|
||||
return { kind: "channel", channel: Number(s.slice(8)) };
|
||||
if (s.startsWith("direct:"))
|
||||
return { kind: "direct", peer: Number(s.slice(7)) };
|
||||
throw new Error(`Unknown conversation key format: ${s}`);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,20 @@ describe("SqlocalMessageRepository (sql.js test driver)", () => {
|
||||
|
||||
it("loadRecent returns the tail in chronological order", async () => {
|
||||
await repo.appendBatch([msg(1, 1000), msg(2, 2000), msg(3, 3000)]);
|
||||
const out = await repo.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 2);
|
||||
const out = await repo.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
2,
|
||||
);
|
||||
expect(out.map((m) => m.id)).toEqual([2, 3]);
|
||||
});
|
||||
|
||||
it("loadBefore paginates older messages", async () => {
|
||||
await repo.appendBatch([msg(1, 1000), msg(2, 2000), msg(3, 3000), msg(4, 4000)]);
|
||||
await repo.appendBatch([
|
||||
msg(1, 1000),
|
||||
msg(2, 2000),
|
||||
msg(3, 3000),
|
||||
msg(4, 4000),
|
||||
]);
|
||||
const out = await repo.loadBefore(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
new Date(3000),
|
||||
@@ -45,22 +53,39 @@ describe("SqlocalMessageRepository (sql.js test driver)", () => {
|
||||
it("updateState mutates the matching row", async () => {
|
||||
await repo.append(msg(42, 1000));
|
||||
await repo.updateState(42, MessageState.Failed);
|
||||
const [found] = await repo.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 1);
|
||||
const [found] = await repo.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
1,
|
||||
);
|
||||
expect(found?.state).toBe(MessageState.Failed);
|
||||
});
|
||||
|
||||
it("prune enforces maxPerBucket", async () => {
|
||||
await repo.appendBatch([msg(1, 1000), msg(2, 2000), msg(3, 3000), msg(4, 4000)]);
|
||||
await repo.appendBatch([
|
||||
msg(1, 1000),
|
||||
msg(2, 2000),
|
||||
msg(3, 3000),
|
||||
msg(4, 4000),
|
||||
]);
|
||||
await repo.prune({ maxPerBucket: 2 });
|
||||
const out = await repo.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 10);
|
||||
const out = await repo.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
10,
|
||||
);
|
||||
expect(out.map((m) => m.id)).toEqual([3, 4]);
|
||||
});
|
||||
|
||||
it("prune enforces olderThanMs", async () => {
|
||||
const now = Date.now();
|
||||
await repo.appendBatch([msg(1, now - 1000 * 60 * 60 * 24 * 10), msg(2, now)]);
|
||||
await repo.appendBatch([
|
||||
msg(1, now - 1000 * 60 * 60 * 24 * 10),
|
||||
msg(2, now),
|
||||
]);
|
||||
await repo.prune({ olderThanMs: 1000 * 60 * 60 * 24 });
|
||||
const out = await repo.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 10);
|
||||
const out = await repo.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
10,
|
||||
);
|
||||
expect(out.map((m) => m.id)).toEqual([2]);
|
||||
});
|
||||
|
||||
@@ -68,8 +93,14 @@ describe("SqlocalMessageRepository (sql.js test driver)", () => {
|
||||
const repoB = new SqlocalMessageRepository(db, { deviceId: 2 });
|
||||
await repo.append(msg(1, 1000, "from-1"));
|
||||
await repoB.append(msg(2, 2000, "from-2"));
|
||||
const a = await repo.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 10);
|
||||
const b = await repoB.loadRecent({ kind: "channel", channel: ChannelNumber.Primary }, 10);
|
||||
const a = await repo.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
10,
|
||||
);
|
||||
const b = await repoB.loadRecent(
|
||||
{ kind: "channel", channel: ChannelNumber.Primary },
|
||||
10,
|
||||
);
|
||||
expect(a.map((m) => m.text)).toEqual(["from-1"]);
|
||||
expect(b.map((m) => m.text)).toEqual(["from-2"]);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { ConversationKey, Message, MessageRepository, RetentionPolicy } from "@meshtastic/sdk";
|
||||
import type {
|
||||
ConversationKey,
|
||||
Message,
|
||||
MessageRepository,
|
||||
RetentionPolicy,
|
||||
} from "@meshtastic/sdk";
|
||||
import { conversationKeyString, MessageState } from "@meshtastic/sdk";
|
||||
import { and, desc, eq, lt, sql } from "drizzle-orm";
|
||||
import { type MultiTabCoordinator } from "../coordination/MultiTabCoordinator.ts";
|
||||
@@ -33,7 +38,11 @@ export class SqlocalMessageRepository implements MessageRepository {
|
||||
return rows.reverse().map(rowToMessage);
|
||||
}
|
||||
|
||||
async loadBefore(key: ConversationKey, cursor: Date, limit: number): Promise<Message[]> {
|
||||
async loadBefore(
|
||||
key: ConversationKey,
|
||||
cursor: Date,
|
||||
limit: number,
|
||||
): Promise<Message[]> {
|
||||
const rows = await this.db
|
||||
.select()
|
||||
.from(messages)
|
||||
@@ -66,7 +75,12 @@ export class SqlocalMessageRepository implements MessageRepository {
|
||||
const cutoff = Date.now() - policy.olderThanMs;
|
||||
await this.db
|
||||
.delete(messages)
|
||||
.where(and(eq(messages.deviceId, this.deviceId), lt(messages.rxTime, cutoff))!);
|
||||
.where(
|
||||
and(
|
||||
eq(messages.deviceId, this.deviceId),
|
||||
lt(messages.rxTime, cutoff),
|
||||
)!,
|
||||
);
|
||||
}
|
||||
if (policy.maxPerBucket !== undefined) {
|
||||
// Keep the newest N per (device, conversation_key). SQLite has no
|
||||
|
||||
Reference in New Issue
Block a user