feat(FN-4313): complete Step 1 — add central default project setting
Fusion-Task-Id: FN-4313 Fusion-Task-Lineage: 36b8aad3-20f4-475b-9b0f-63e5458d1b91
This commit is contained in:
@@ -2378,6 +2378,58 @@ describe("CentralCore", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("default project setting", () => {
|
||||
beforeEach(async () => {
|
||||
await central.init();
|
||||
});
|
||||
|
||||
it("should be undefined by default", async () => {
|
||||
await expect(central.getDefaultProjectId()).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should set/get and clear default project id", async () => {
|
||||
const projectPath = join(tempDir, "default-project");
|
||||
mkdirSync(projectPath);
|
||||
projectPaths.push(projectPath);
|
||||
|
||||
const project = await central.registerProject({
|
||||
name: "Default Project",
|
||||
path: projectPath,
|
||||
});
|
||||
|
||||
await central.setDefaultProjectId(project.id);
|
||||
await expect(central.getDefaultProjectId()).resolves.toBe(project.id);
|
||||
|
||||
await central.setDefaultProjectId(null);
|
||||
await expect(central.getDefaultProjectId()).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should reject unknown project id", async () => {
|
||||
await expect(central.setDefaultProjectId("missing-project-id")).rejects.toThrow(
|
||||
"Cannot set default project: project not found: missing-project-id",
|
||||
);
|
||||
});
|
||||
|
||||
it("should persist setting across reopen", async () => {
|
||||
const projectPath = join(tempDir, "persisted-default-project");
|
||||
mkdirSync(projectPath);
|
||||
projectPaths.push(projectPath);
|
||||
|
||||
const project = await central.registerProject({
|
||||
name: "Persisted Default Project",
|
||||
path: projectPath,
|
||||
});
|
||||
|
||||
await central.setDefaultProjectId(project.id);
|
||||
await central.close();
|
||||
|
||||
central = new CentralCore(tempDir);
|
||||
await central.init();
|
||||
|
||||
await expect(central.getDefaultProjectId()).resolves.toBe(project.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe("global concurrency", () => {
|
||||
beforeEach(async () => {
|
||||
await central.init();
|
||||
|
||||
@@ -2424,6 +2424,31 @@ export class CentralCore extends EventEmitter<CentralCoreEvents> {
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
async getDefaultProjectId(): Promise<string | undefined> {
|
||||
this.ensureInitialized();
|
||||
|
||||
const row = this.db!.prepare("SELECT defaultProjectId FROM centralSettings WHERE id = 1").get() as
|
||||
| { defaultProjectId: string | null }
|
||||
| undefined;
|
||||
|
||||
return row?.defaultProjectId ?? undefined;
|
||||
}
|
||||
|
||||
async setDefaultProjectId(projectId: string | null): Promise<void> {
|
||||
this.ensureInitialized();
|
||||
|
||||
if (projectId !== null) {
|
||||
const project = await this.getProject(projectId);
|
||||
if (!project) {
|
||||
throw new Error(`Cannot set default project: project not found: ${projectId}`);
|
||||
}
|
||||
}
|
||||
|
||||
this.db!
|
||||
.prepare("UPDATE centralSettings SET defaultProjectId = ?, updatedAt = ? WHERE id = 1")
|
||||
.run(projectId, new Date().toISOString());
|
||||
}
|
||||
|
||||
// ── Global Concurrency API ─────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ export { toJson, toJsonNullable, fromJson };
|
||||
|
||||
// ── Schema Definition ───────────────────────────────────────────────────
|
||||
|
||||
const CENTRAL_SCHEMA_VERSION = 10;
|
||||
const CENTRAL_SCHEMA_VERSION = 11;
|
||||
|
||||
const CENTRAL_SCHEMA_SQL = `
|
||||
-- Projects table (project registry)
|
||||
@@ -107,6 +107,15 @@ CREATE TABLE IF NOT EXISTS globalConcurrency (
|
||||
INSERT OR IGNORE INTO globalConcurrency (id, globalMaxConcurrent, currentlyActive, queuedCount)
|
||||
VALUES (1, 4, 0, 0);
|
||||
|
||||
-- Central settings (single row)
|
||||
CREATE TABLE IF NOT EXISTS centralSettings (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
defaultProjectId TEXT,
|
||||
updatedAt TEXT NOT NULL
|
||||
);
|
||||
INSERT OR IGNORE INTO centralSettings (id, defaultProjectId, updatedAt)
|
||||
VALUES (1, NULL, CURRENT_TIMESTAMP);
|
||||
|
||||
-- Nodes table (runtime hosts for project execution)
|
||||
CREATE TABLE IF NOT EXISTS nodes (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -433,6 +442,16 @@ CREATE TABLE IF NOT EXISTS meshWriteQueue (
|
||||
CREATE INDEX IF NOT EXISTS idxMeshWriteQueueReplay ON meshWriteQueue(targetNodeId, status, createdAt, id);
|
||||
`;
|
||||
|
||||
const CENTRAL_SCHEMA_V11_MIGRATION_SQL = `
|
||||
CREATE TABLE IF NOT EXISTS centralSettings (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
defaultProjectId TEXT,
|
||||
updatedAt TEXT NOT NULL
|
||||
);
|
||||
INSERT OR IGNORE INTO centralSettings (id, defaultProjectId, updatedAt)
|
||||
VALUES (1, NULL, CURRENT_TIMESTAMP);
|
||||
`;
|
||||
|
||||
// ── Central Database Class ────────────────────────────────────────────────
|
||||
|
||||
export class CentralDatabase {
|
||||
@@ -575,6 +594,11 @@ export class CentralDatabase {
|
||||
migrated = true;
|
||||
}
|
||||
|
||||
if (currentVersion < 11) {
|
||||
this.db.exec(CENTRAL_SCHEMA_V11_MIGRATION_SQL);
|
||||
migrated = true;
|
||||
}
|
||||
|
||||
if (migrated) {
|
||||
this.db
|
||||
.prepare("INSERT INTO __meta (key, value) VALUES ('schemaVersion', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value")
|
||||
|
||||
Reference in New Issue
Block a user