( root: string, folder: NoteFolder, subpath: string, title?: string )
| 251 | * vault root rather than inventing an `inbox/` directory. |
| 252 | */ |
| 253 | export async function createDatabase( |
| 254 | root: string, |
| 255 | folder: NoteFolder, |
| 256 | subpath: string, |
| 257 | title?: string |
| 258 | ): Promise<DatabaseDoc> { |
| 259 | const safeTitle = (title ?? 'Untitled Database').trim() || 'Untitled Database' |
| 260 | const baseName = safeTitle.replace(/[\\/:*?"<>|]/g, '-') |
| 261 | const topAbs = await folderRoot(root, folder) |
| 262 | const cleanSub = toPosix(subpath).replace(/^\/+|\/+$/g, '') |
| 263 | const dirAbs = cleanSub ? path.join(topAbs, cleanSub) : topAbs |
| 264 | const dirRel = toPosix(path.relative(root, dirAbs)) |
| 265 | const makeFormDir = (name: string): string => |
| 266 | dirRel ? `${dirRel}/${name}${FORM_DIR_SUFFIX}` : `${name}${FORM_DIR_SUFFIX}` |
| 267 | // Resolve a non-colliding `<Name>.base` folder under the directory. |
| 268 | let formDirRel = makeFormDir(baseName) |
| 269 | let n = 2 |
| 270 | for (;;) { |
| 271 | try { |
| 272 | await fs.access(databaseDataPath(root, formDirRel)) |
| 273 | formDirRel = makeFormDir(`${baseName} ${n++}`) |
| 274 | } catch { |
| 275 | break |
| 276 | } |
| 277 | } |
| 278 | const rel = csvPathForFormDir(formDirRel) |
| 279 | |
| 280 | const idField: DbField = { id: randomUUID(), name: 'id', type: 'text', hidden: true } |
| 281 | const nameField: DbField = { id: randomUUID(), name: 'Name', type: 'text' } |
| 282 | const fields = [idField, nameField] |
| 283 | const { views, activeViewId } = buildDefaultViews(fields) |
| 284 | const sidecar: DatabaseSidecar = { |
| 285 | version: 1, |
| 286 | idFieldId: idField.id, |
| 287 | fields, |
| 288 | views, |
| 289 | activeViewId |
| 290 | } |
| 291 | // Create the folder, then the two data files. |
| 292 | await fs.mkdir(databaseDataPath(root, formDirRel), { recursive: true }) |
| 293 | await persistSidecar(root, rel, sidecar) |
| 294 | await writeFileAtomic(databaseDataPath(root, rel), serializeRows([], fields)) |
| 295 | return hydrate(rel, sidecar, []) |
| 296 | } |
| 297 | |
| 298 | /** |
| 299 | * Create a "page" note for a database record inside the database folder |
no test coverage detected