File size: 2,274 Bytes
253e783
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import type { DatabaseSync } from "node:sqlite";
import type { Selectable } from "kysely";
import {
  executeSqliteQuerySync,
  executeSqliteQueryTakeFirstSync,
  getNodeSqliteKysely,
} from "../infra/kysely-sync.js";
import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js";
import { createOpenClawStateSchemaEnsurer } from "../state/openclaw-state-feature-schema.js";

export type ProjectRegistryIdentity = {
  id: string;
  repoRoot: string;
  originUrl?: string;
  source: "workspace" | "registered" | "cloned";
};

type ProjectsDatabase = Pick<OpenClawStateKyselyDatabase, "projects">;
type ProjectRow = Selectable<ProjectsDatabase["projects"]>;

export const ensureProjectRegistrySchema = createOpenClawStateSchemaEnsurer({
  table: "projects",
  operationLabel: "projects.registry.schema.ensure",
});

export function resolveRecordedProjectRootInDatabase(
  database: DatabaseSync,
  repoRoot: string,
): string | undefined {
  const db = getNodeSqliteKysely<ProjectsDatabase>(database);
  return executeSqliteQueryTakeFirstSync(
    database,
    db.selectFrom("projects").select("repo_root").where("repo_root", "=", repoRoot),
  )?.repo_root;
}

function matchesProjectRecord(row: ProjectRow, project: ProjectRegistryIdentity): boolean {
  return (
    row.id === project.id &&
    row.repo_root === project.repoRoot &&
    row.source === project.source &&
    (row.origin_url ?? undefined) === project.originUrl
  );
}

export function readMatchingProjectRow(
  database: DatabaseSync,
  project: ProjectRegistryIdentity,
): ProjectRow | undefined {
  const db = getNodeSqliteKysely<ProjectsDatabase>(database);
  const row = executeSqliteQueryTakeFirstSync(
    database,
    db.selectFrom("projects").selectAll().where("id", "=", project.id),
  );
  return row && matchesProjectRecord(row, project) ? row : undefined;
}

export function removeProjectRegistryInDatabase(
  database: DatabaseSync,
  project: ProjectRegistryIdentity,
): boolean {
  if (!readMatchingProjectRow(database, project)) {
    return false;
  }
  const db = getNodeSqliteKysely<ProjectsDatabase>(database);
  return (
    executeSqliteQuerySync(database, db.deleteFrom("projects").where("id", "=", project.id))
      .numAffectedRows === 1n
  );
}