mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-09 14:59:27 +08:00
docs(README): enhance foreign key documentation with usage examples
- Added sections on basic usage of foreign keys, self-referencing foreign keys, and circular foreign key references. - Provided TypeScript code examples to illustrate best practices and avoid common pitfalls. - Explained the rationale behind using soft references in SQLite for improved data integrity and simplified operations.
This commit is contained in:
parent
9c47937714
commit
44b85fa661
@ -88,6 +88,8 @@ Drizzle handles JSON serialization/deserialization automatically.
|
|||||||
|
|
||||||
## Foreign Keys
|
## Foreign Keys
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// SET NULL: preserve record when referenced record is deleted
|
// SET NULL: preserve record when referenced record is deleted
|
||||||
groupId: text().references(() => groupTable.id, { onDelete: 'set null' })
|
groupId: text().references(() => groupTable.id, { onDelete: 'set null' })
|
||||||
@ -96,6 +98,69 @@ groupId: text().references(() => groupTable.id, { onDelete: 'set null' })
|
|||||||
topicId: text().references(() => topicTable.id, { onDelete: 'cascade' })
|
topicId: text().references(() => topicTable.id, { onDelete: 'cascade' })
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Self-Referencing Foreign Keys
|
||||||
|
|
||||||
|
For self-referencing foreign keys (e.g., tree structures with parentId), **always use the `foreignKey` operator** in the table's third parameter:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { foreignKey, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||||
|
|
||||||
|
export const messageTable = sqliteTable(
|
||||||
|
'message',
|
||||||
|
{
|
||||||
|
id: uuidPrimaryKeyOrdered(),
|
||||||
|
parentId: text(), // Do NOT use .references() here
|
||||||
|
// ...other fields
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
// Use foreignKey operator for self-referencing
|
||||||
|
foreignKey({ columns: [t.parentId], foreignColumns: [t.id] }).onDelete('set null')
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this approach:**
|
||||||
|
- Avoids TypeScript circular reference issues (no need for `AnySQLiteColumn` type annotation)
|
||||||
|
- More explicit and readable
|
||||||
|
- Allows chaining `.onDelete()` / `.onUpdate()` actions
|
||||||
|
|
||||||
|
### Circular Foreign Key References
|
||||||
|
|
||||||
|
**Avoid circular foreign key references between tables.** For example:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ❌ BAD: Circular FK between tables
|
||||||
|
// tableA.currentItemId -> tableB.id
|
||||||
|
// tableB.ownerId -> tableA.id
|
||||||
|
```
|
||||||
|
|
||||||
|
If you encounter a scenario that seems to require circular references:
|
||||||
|
|
||||||
|
1. **Identify which relationship is "weaker"** - typically the one that can be null or is less critical for data integrity
|
||||||
|
2. **Remove the FK constraint from the weaker side** - let the application layer handle validation and consistency (this is known as "soft references" pattern)
|
||||||
|
3. **Document the application-layer constraint** in code comments
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ GOOD: Break the cycle by handling one side at application layer
|
||||||
|
export const topicTable = sqliteTable('topic', {
|
||||||
|
id: uuidPrimaryKey(),
|
||||||
|
// Application-managed reference (no FK constraint)
|
||||||
|
// Validated by TopicService.setCurrentMessage()
|
||||||
|
currentMessageId: text(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const messageTable = sqliteTable('message', {
|
||||||
|
id: uuidPrimaryKeyOrdered(),
|
||||||
|
// Database-enforced FK
|
||||||
|
topicId: text().references(() => topicTable.id, { onDelete: 'cascade' }),
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why soft references for SQLite:**
|
||||||
|
- SQLite does not support `DEFERRABLE` constraints (unlike PostgreSQL/Oracle)
|
||||||
|
- Application-layer validation provides equivalent data integrity
|
||||||
|
- Simplifies insert/update operations without transaction ordering concerns
|
||||||
|
|
||||||
## Migrations
|
## Migrations
|
||||||
|
|
||||||
Generate migrations after schema changes:
|
Generate migrations after schema changes:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user