{"record":{"id":"12af8699dbb92a45","repo":"toeverything/AFFiNE","slug":"table-tablename-there-should-be-at-least-on","errorCode":null,"errorMessage":"[Table(${tableName})]: There should be at least one field marked as primary key.","messagePattern":"\\[Table\\((.+?)\\)\\]: There should be at least one field marked as primary key\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/common/infra/src/orm/core/validators/schema.ts","lineNumber":7,"sourceCode":"import type { TableSchemaValidator } from './types';\n\nexport const tableSchemaValidators: Record<string, TableSchemaValidator> = {\n  PrimaryKeyShouldExist: {\n    validate(tableName, table) {\n      if (!Object.values(table).some(field => field.schema.isPrimaryKey)) {\n        throw new Error(\n          `[Table(${tableName})]: There should be at least one field marked as primary key.`\n        );\n      }\n    },\n  },\n  OnlyOnePrimaryKey: {\n    validate(tableName, table) {\n      const primaryFields = [];\n\n      for (const name in table) {\n        if (table[name].schema.isPrimaryKey) {\n          primaryFields.push(name);\n        }\n      }\n\n      if (primaryFields.length > 1) {\n        throw new Error(\n          `[Table(${tableName})]: There should be only one field marked as primary key. Found [${primaryFields.join(', ')}].`","sourceCodeStart":1,"sourceCodeEnd":25,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/common/infra/src/orm/core/validators/schema.ts#L1-L25","documentation":"Schema validator PrimaryKeyShouldExist runs when a table definition is registered and throws if not a single field has isPrimaryKey set. Every AFFiNE ORM table must declare exactly one primary key so rows can be addressed for get/update/delete. This fails at definition time, before any data operation.","triggerScenarios":"Calling t.table('name', {...}) where no field uses .primaryKey(); defining the table with only plain t.string()/t.number() fields; forgetting .primaryKey() when copying an existing table definition.","commonSituations":"Creating a new table quickly during prototyping and skipping the key; refactoring a table and accidentally dropping the .primaryKey() chain; generating table definitions from a template that lacks the marker.","solutions":["Add .primaryKey() to the field that uniquely identifies rows (usually an id column).","If no natural unique column exists, add an id: t.string().primaryKey() and populate it (e.g. with nanoid/uuid) on create.","Re-run; this throws eagerly at table registration, so the stack points straight at the offending definition."],"exampleFix":"// before\nexport const Setting = t.table('setting', {\n  key: t.string(),\n  value: t.string(),\n});\n\n// after\nexport const Setting = t.table('setting', {\n  key: t.string().primaryKey(),\n  value: t.string(),\n});","handlingStrategy":"validation","validationCode":"function assertSinglePrimaryKey(tableName: string, fields: Record<string, { isPrimaryKey?: boolean }>) {\n  const pks = Object.entries(fields).filter(([, f]) => f.isPrimaryKey);\n  if (pks.length === 0) throw new Error(`${tableName}: missing primary key`);\n  if (pks.length > 1) throw new Error(`${tableName}: multiple primary keys ${pks.map(([n]) => n)}`);\n}","typeGuard":null,"tryCatchPattern":"try { registerTable(MyTable); } catch (e) { if (e instanceof Error && e.message.includes('primary key')) { /* fix definition; fails fast at startup */ } throw e; }","preventionTips":["Start new table definitions from a template containing id: t.string().primaryKey().default(nanoid)","Register tables in a unit test so definition errors fail CI, not production","Code-review any schema diff for PK presence"],"tags":["orm","schema","primary-key","affine"],"backgroundTag":"missing-primary-key","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}