(csvPath: string)
| 790 | } |
| 791 | |
| 792 | async function openDatabase(csvPath: string): Promise<DatabaseDoc> { |
| 793 | const rel = dbToPosix(csvPath) |
| 794 | const csvText = await readFileTextOrNull(rel) |
| 795 | if (csvText === null) throw new Error(`Database not found: ${rel}`) |
| 796 | |
| 797 | const existing = await dbReadSidecar(rel) |
| 798 | if (existing) { |
| 799 | const rows = parseRows(csvText, existing.fields, existing.idFieldId, dbGenId) |
| 800 | const pageHasContent = await dbReadPageFlags(existing.pages) |
| 801 | return dbHydrate(rel, existing, rows, pageHasContent) |
| 802 | } |
| 803 | |
| 804 | // Adopt a plain CSV: infer the schema + materialize (matches desktop readDatabase). |
| 805 | const grid = parseCsv(csvText) |
| 806 | const headers = grid[0] ?? [] |
| 807 | const { fields, idFieldId } = inferFields(headers, grid.slice(1, 1 + SCHEMA_SAMPLE_ROWS), dbGenId) |
| 808 | const { views, activeViewId } = buildDefaultViews(fields, dbGenId) |
| 809 | const sidecar: DatabaseSidecar = { version: 1, idFieldId, fields, views, activeViewId } |
| 810 | const rows = parseRows(csvText, fields, idFieldId, dbGenId) |
| 811 | await dbPersistSidecar(rel, sidecar) |
| 812 | await writeNote(rel, serializeRows(rows, fields)) // canonicalize + persist ids |
| 813 | return dbHydrate(rel, sidecar, rows) |
| 814 | } |
| 815 | |
| 816 | async function writeDatabaseRows(csvPath: string, rows: DbRow[]): Promise<DatabaseDoc> { |
| 817 | const rel = dbToPosix(csvPath) |
no test coverage detected