Files
2026-05-27 23:29:53 +01:00

187 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: enterprise-surrealdb
**Change ID**: enterprise-surrealdb
**Package**: `@suaveplan/surrealdb`
**Target path**: `universal/database/surrealdb`
**Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/db`, `@suaveplan/retry`
---
## 1. Scaffold
- [x] Create directory `universal/database/surrealdb/` with `src/`, `tests/`, `src/__benchmarks__/`, and all feature subdirectories per the layout in `proposal.md`.
- [x] Write `package.json` at version `0.1.0` with:
- `"type": "module"`, `"sideEffects": false`
- `exports` map: top-level `"."` barrel plus subpaths for `./connection/connection`, `./adapters/surreal-adapter`, `./schema/discovery`, `./init/init`, `./utils/version-detector`
- `dependencies`: `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/db workspace:^`, `@suaveplan/retry workspace:^`, `surrealdb catalog:database`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`
- `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `fast-check catalog:testing`, `mitata catalog:testing`, `@suaveplan/testing workspace:^`
- [x] Write `tsconfig.json` extending `@suaveplan/typescript-config/library.json`.
- [x] Write `vitest.config.ts` using `createTestConfig()` from `@suaveplan/testing/config` (pool: `forks`).
- [x] Add `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check`, `bench` scripts to `package.json`.
---
## 2. Types + errors
### 2a. Common types (`src/types/common.ts` + `src/types/common.md`)
- [x] Define all shared TS types: `SurrealVersion`, `MajorVersion`, `VersionInfo`, `ConnectionState`, `RecordId`, `RecordResult`, `QueryStatementResult`, `RawQueryResult`, `QueryResult`, `AuthCredentials`.
- [x] Write `src/types/common.md` (≥200 words, both simple + advanced examples, API reference).
### 2b. Error codes (`src/error-codes.ts`)
- [x] Import `CodeMetadata`, `ErrorCodes`, `SuaveplanError` from `@suaveplan/error`.
- [x] Define `SurrealErrorCode` union — eight codes: `SURREAL_CONNECT_FAILED`, `SURREAL_QUERY_FAILED`, `SURREAL_AUTH_FAILED`, `SURREAL_NOT_CONNECTED`, `SURREAL_TIMEOUT`, `SURREAL_VERSION_UNSUPPORTED`, `SURREAL_SCHEMA_LOAD_FAILED`, `SURREAL_INIT_FAILED`.
- [x] Define `SURREAL_ERROR_METADATA` with `httpStatus`, `severity`, `retryable`, `userMessageKey`, `category`, `description` for each code.
- [x] Export `registerSurrealErrorCodes()` — calls `ErrorCodes.registerMany(SURREAL_ERROR_METADATA)`. Idempotent.
- [x] Call `registerSurrealErrorCodes()` as an eager side-effect at module scope.
- [x] Export `SurrealError` extending `SuaveplanError` carrying `SurrealErrorCode` as its `.code` discriminant.
### 2c. Zod option schemas
- [x] Write `src/connection/connection/connection.types.ts` with `SurrealDBConfigSchema` and inferred `SurrealDBConfig`.
- [x] Write `src/init/init/init.types.ts` with `InitOptionsSchema`, `AdvancedInitOptionsSchema`, `SchemaFileSchema`.
- [x] Write `src/schema/discovery/discovery.types.ts` with `DiscoverOptionsSchema`.
---
## 3. Constants
- [x] Write `src/constants/index.ts`:
- `DEFAULT_SCHEMA_ORDER`: `readonly string[]` with sensible migration-first ordering.
- `DEFAULT_SURREAL_URL`, `DEFAULT_SURREAL_NAMESPACE`, `DEFAULT_SURREAL_DATABASE`.
- `SURREAL_SUPPORTED_MAJOR_VERSIONS: readonly MajorVersion[]` = `[1, 2, 3]`.
---
## 4. Version detector (`src/utils/version-detector.ts`)
- [x] Implement `detectVersion(db: Surreal): Promise<VersionInfo>`:
- Calls `db.version()`, parses the semver string with a regex.
- Returns typed `VersionInfo` for major versions 1–3.
- Throws `SurrealError` with code `SURREAL_VERSION_UNSUPPORTED` for unknown major versions.
- [x] Write `version-detector.test.ts`: known version strings for v1/v2/v3, prerelease string, unsupported major throws.
- [x] Write `version-detector.md` (≥200 words).
---
## 5. Connection (`src/connection/connection/`)
- [x] Implement `getDefaultConfig(): SurrealDBConfig` — reads `DB_URL`, `DB_NAMESPACE`, `DB_NAME`, `DB_USER`, `DB_PASS` from `process.env` where available; falls back to defaults.
- [x] Implement `createConnection(config?, options?)`:
- Merges partial config with defaults.
- Instantiates `new Surreal()`, calls `db.connect(url)`, then authenticates.
- Accepts optional `signal?: AbortSignal` — throws `SurrealError(SURREAL_TIMEOUT)` on abort before connect completes.
- Accepts optional `retry?: RetryStrategyOptions` — wraps the connect+auth sequence with `@suaveplan/retry`'s `withRetry`.
- OTel: span `surreal.connect`, counter `surreal.connect_total`.
- [x] Implement `connectWith`, `getSingleton`, `hasSingleton`, `closeSingleton` — delegate to `@suaveplan/db`'s singleton helpers where appropriate.
- [x] Write `connection.test.ts` (requires real SurrealDB; gate with `process.env.SURREALDB_URL` skip guard).
- [x] Write `connection.md` (≥200 words).
---
## 6. Adapter (`src/adapters/surreal-adapter/`)
- [x] Define `SurrealAdapter` interface in `surreal-adapter.types.ts` — mirrors the main-branch surface; adds `DatabaseAdapter` from `@suaveplan/db` as parent interface.
- [x] Implement `SurrealAdapter` class:
- Internal `_state: ConnectionState` with protected getter.
- `connect(config)` — calls `createConnection`, transitions state.
- `disconnect()` — calls `db.close()`, transitions to `disconnected`.
- `query<T>(sql, params?, options?)` — calls `db.query(sql, params)`, wraps errors as `SurrealError(SURREAL_QUERY_FAILED)`, records OTel span + histogram.
- `create`, `select`, `update`, `merge`, `delete` — delegate to driver, wrap errors.
- All methods accept optional `signal?: AbortSignal`.
- Fix: use `INSERT INTO` query instead of `db.create()` to avoid surrealdb.js v2 content-drop bug (see memory `feedback_surrealdb_create_content_drop`).
- [x] Write `surreal-adapter.test.ts` (integration, real SurrealDB; SURREALDB_URL skip guard).
- [x] Write `surreal-adapter.md` (≥200 words).
---
## 7. Schema discovery (`src/schema/discovery/`)
- [x] Implement `discoverSchemas(dir, options?)` — reads directory recursively for `.surql` files; returns `SchemaFile[]` sorted by `DEFAULT_SCHEMA_ORDER` then alphabetically.
- [x] Implement `filterSchemas(files, filter)` — apply caller-supplied predicate.
- [x] Implement `getSchemasToLoad(dir, filter?)` — `discoverSchemas` + optional `filterSchemas`.
- [x] Implement `readSchemaContent(file)` — reads file content; caches in `file.content`.
- [x] Write `discovery.test.ts` — in-memory fixture files (no real FS), happy path, empty dir, filter exclude/include.
- [x] Write `discovery.md` (≥200 words).
---
## 8. Init (`src/init/init/`)
- [x] Implement `initDatabase(db, options)`:
- Calls `getSchemasToLoad`, reads each file, executes via `db.query(content)`.
- Runs `options.hooks?.before` / `after` around each schema.
- Dry-run mode: skip execution, record in `result.skipped`.
- Returns `InitResult { applied, skipped, errors }`.
- OTel: span `surreal.init`, attribute `surreal.schema_count`.
- [x] Implement `initAndClose(options)` — opens a singleton, runs init, closes.
- [x] Implement `createInitializer(options)` — returns a closure `(db) => initDatabase(db, options)`.
- [x] Write `init.test.ts` (unit: mock schema files, real adapter not required; integration: SURREALDB_URL guard).
- [x] Write `init.md` (≥200 words).
---
## 9. Public barrel (`src/index.ts`)
- [x] Re-export all public symbols from connection, adapters, schema, init, utils, types, error-codes, constants.
- [x] Re-export `RecordId`, `StringRecordId`, `Surreal`, `Table`, `Patch`, `RecordIdValue` directly from `surrealdb` driver (not wrapped).
---
## 10. OTel instrumentation (cross-cutting)
- [x] Obtain tracer `surreal` and meter `surreal` once at module scope via lazy `trace.getTracer` / `metrics.getMeter`.
- [x] `createConnection` — span `surreal.connect` with attributes `surreal.url`, `surreal.namespace`, `surreal.database`; counter `surreal.connect_total`.
- [x] `SurrealAdapter.query` — span `surreal.query`; histogram `surreal.query_duration_ms`; counter `surreal.query_total` with attribute `surreal.table` where parseable.
- [x] `closeSingleton` / `disconnect` — span `surreal.disconnect`.
- [x] `initDatabase` — span `surreal.init`; attribute `surreal.schema_count`.
- [x] All spans record exception on error and end in `finally`.
---
## 11. Property-based tests (`tests/property.test.ts`)
Use `fast-check`. All test timeouts: `{ timeout: 30000 }`.
- [x] **`detectVersion` parser**: for arbitrary `major.minor.patch` strings (1–3), assert that `parseVersionString` returns the same major/minor/patch. Does not require live DB.
- [x] **`filterSchemas` complement**: generate N random schema files (2–10); assert include filter with predicate P plus exclude filter with predicate P covers the full set without overlap.
- [x] **`ConnectionState` state machine**: for a sequence of `connect` and `disconnect` calls on a mock adapter, assert the final state equals the result of applying transitions in order (always ends `connected` or `disconnected`).
---
## 12. Benchmarks (`src/__benchmarks__/surreal.bench.ts`)
Use `mitata`. Guard IO-bound benchmarks with `SKIP_DB_BENCHMARKS` env flag.
- [x] `detectVersion_parse_10k`: 10 000 pure semver parses.
- [x] `query_hot` (conditional on `!SKIP_DB_BENCHMARKS`): 1000 `SELECT 1` queries on a pre-connected adapter.
- [x] Document placeholder benchmark table in `README.md` under `## Benchmarks`.
---
## 13. Docs
- [x] `src/types/common.md`
- [x] `src/connection/connection/connection.md`
- [x] `src/adapters/surreal-adapter/surreal-adapter.md`
- [x] `src/schema/discovery/discovery.md`
- [x] `src/init/init/init.md`
- [x] `src/utils/version-detector.md`
- [x] Root `universal/database/surrealdb/README.md` — purpose, installation, quick-start, dep table, API symbol list, benchmarks table.
---
## 14. Verify and publish
- [x] Run `bunx turbo lint --filter=@suaveplan/surrealdb` — zero errors.
- [x] Run `bunx turbo typecheck --filter=@suaveplan/surrealdb` — zero errors.
- [x] Run `bunx turbo test --filter=@suaveplan/surrealdb` — all tests pass.
- [x] Run `bunx turbo test:coverage --filter=@suaveplan/surrealdb` — 100% on all touched modules.
- [x] Run `bun run docs:check --filter=@suaveplan/surrealdb` — zero errors.
- [x] Confirm no `TODO`, `FIXME`, `@deprecated`, untyped `any`, `ts-ignore`, or `.skip` in `src/` or `tests/`.
- [x] Confirm `"sideEffects": false` in `package.json`.
- [x] Run `bun scripts/publish.ts --package @suaveplan/surrealdb`.
- [x] Update `CLAUDE.md` package listing to include `@suaveplan/surrealdb`.
- [x] Archive: move `openspec/changes/enterprise-surrealdb/` to `openspec/archive/2026-04-24-enterprise-surrealdb/` and fold spec delta into `openspec/specs/database/spec.md`.