Skip to content

Commit 46de256

Browse files
committed
add llms.txt and docs
1 parent d789819 commit 46de256

7 files changed

Lines changed: 859 additions & 0 deletions

File tree

docs/conditions.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Conditions
2+
3+
Build complex trigger conditions with type safety.
4+
5+
## Basic Comparisons
6+
7+
```typescript
8+
.when(c => c.NEW('status').eq('active')) // equals
9+
.when(c => c.NEW('price').gt(100)) // greater than
10+
.when(c => c.NEW('stock').gte(10)) // greater or equal
11+
.when(c => c.NEW('discount').lt(50)) // less than
12+
.when(c => c.NEW('quantity').lte(5)) // less or equal
13+
.when(c => c.NEW('email').ne('old@mail.com')) // not equal
14+
```
15+
16+
## Field Comparisons
17+
18+
```typescript
19+
// Compare OLD vs NEW
20+
.when(c => c.OLD('email').ne(c.NEW('email')))
21+
22+
// Check if changed
23+
.when(c => c.changed('status'))
24+
.when(c => c.changed('email', 'phone')) // Any of these changed
25+
```
26+
27+
## Null Checks
28+
29+
```typescript
30+
.when(c => c.NEW('deletedAt').isNull())
31+
.when(c => c.NEW('approvedBy').isNotNull())
32+
```
33+
34+
## Boolean Logic
35+
36+
```typescript
37+
// AND
38+
.when(c => c.and(
39+
c.NEW('status').eq('published'),
40+
c.NEW('visibility').eq('public')
41+
))
42+
43+
// OR
44+
.when(c => c.or(
45+
c.NEW('priority').eq('high'),
46+
c.NEW('deadline').lt(new Date())
47+
))
48+
49+
// NOT
50+
.when(c => c.not(c.NEW('archived').eq(true)))
51+
```
52+
53+
## Complex Conditions
54+
55+
```typescript
56+
// Nested logic
57+
.when(c => c.and(
58+
c.changed('status'),
59+
c.or(
60+
c.and(
61+
c.OLD('status').eq('draft'),
62+
c.NEW('status').eq('published')
63+
),
64+
c.and(
65+
c.OLD('status').eq('published'),
66+
c.NEW('status').eq('archived')
67+
)
68+
)
69+
))
70+
```
71+
72+
## Pattern Matching
73+
74+
```typescript
75+
// LIKE
76+
.when(c => c.NEW('email').like('%@company.com'))
77+
78+
// IN
79+
.when(c => c.NEW('status').in(['active', 'pending', 'processing']))
80+
81+
// BETWEEN
82+
.when(c => c.NEW('age').between(18, 65))
83+
```
84+
85+
## Real-World Examples
86+
87+
### Order Status Workflow
88+
89+
```typescript
90+
triggers
91+
.for('order')
92+
.after()
93+
.on('UPDATE')
94+
.when(c => c.and(
95+
c.changed('status'),
96+
c.OLD('status').eq('payment_pending'),
97+
c.NEW('status').eq('payment_confirmed'),
98+
c.NEW('amount').gt(0)
99+
))
100+
.notify('order_paid')
101+
.build();
102+
```
103+
104+
### User Account Changes
105+
106+
```typescript
107+
triggers
108+
.for('user')
109+
.after()
110+
.on('UPDATE')
111+
.when(c => c.or(
112+
c.changed('email'),
113+
c.changed('password'),
114+
c.changed('twoFactorEnabled')
115+
))
116+
.notify('security_change')
117+
.build();
118+
```
119+
120+
### Inventory Alerts
121+
122+
```typescript
123+
triggers
124+
.for('product')
125+
.after()
126+
.on('UPDATE')
127+
.when(c => c.and(
128+
c.NEW('stock').lt(10),
129+
c.OLD('stock').gte(10),
130+
c.NEW('active').eq(true)
131+
))
132+
.notify('low_stock_alert')
133+
.build();
134+
```
135+
136+
## Raw SQL Escape Hatch
137+
138+
```typescript
139+
// For complex conditions not supported by the builder
140+
.when('NEW.data::jsonb @> \'{"featured": true}\'::jsonb')
141+
```
142+
143+
## Next: [Real-time Events](./realtime-events.md)

docs/index.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# pg-typesafe-triggers
2+
3+
Type-safe PostgreSQL triggers for Prisma without writing SQL.
4+
5+
## What it does
6+
7+
Automatically creates PostgreSQL trigger functions from TypeScript code. Full type safety using your Prisma schema types.
8+
9+
## Quick Example
10+
11+
```typescript
12+
// Instead of writing SQL...
13+
triggers
14+
.for('order')
15+
.after()
16+
.on('UPDATE')
17+
.when(c => c.NEW('status').eq('shipped'))
18+
.notify('order_shipped')
19+
.build();
20+
21+
// Automatically generates and manages the PostgreSQL trigger
22+
```
23+
24+
## Use Cases
25+
26+
- [Individual Triggers](./individual-triggers.md) - Fine control over single triggers
27+
- [Registry Pattern](./registry-pattern.md) - Manage multiple triggers at once
28+
- [Conditions](./conditions.md) - Complex trigger logic
29+
- [Real-time Events](./realtime-events.md) - Subscribe to database changes
30+
- [Common Patterns](./patterns.md) - Audit logs, workflows, sync
31+
32+
## Installation
33+
34+
```bash
35+
npm install pg-typesafe-triggers
36+
```
37+
38+
## Basic Setup
39+
40+
```typescript
41+
import { createTriggers } from 'pg-typesafe-triggers';
42+
import { PrismaClient } from '@prisma/client';
43+
44+
const prisma = new PrismaClient();
45+
const triggers = createTriggers<typeof prisma>(DATABASE_URL);
46+
```
47+
48+
## Next Steps
49+
50+
Choose your approach:
51+
- [Individual Triggers](./individual-triggers.md) for specific use cases
52+
- [Registry Pattern](./registry-pattern.md) for managing many triggers

docs/individual-triggers.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Individual Triggers
2+
3+
Create and manage single triggers with fine-grained control.
4+
5+
## Basic Trigger
6+
7+
```typescript
8+
const trigger = triggers
9+
.for('user')
10+
.after()
11+
.on('INSERT')
12+
.notify('new_user')
13+
.build();
14+
15+
await trigger.setup();
16+
```
17+
18+
## Trigger Options
19+
20+
### Timing
21+
22+
```typescript
23+
.before() // Run before the operation
24+
.after() // Run after the operation
25+
```
26+
27+
### Events
28+
29+
```typescript
30+
.on('INSERT')
31+
.on('UPDATE')
32+
.on('DELETE')
33+
.on('INSERT', 'UPDATE') // Multiple events
34+
```
35+
36+
### Column Watching
37+
38+
```typescript
39+
.watchColumns('email', 'status') // Only trigger on specific column changes
40+
```
41+
42+
### Custom Names
43+
44+
```typescript
45+
.withName('user_email_change_trigger')
46+
```
47+
48+
## Complete Example
49+
50+
```typescript
51+
const emailChangeTrigger = triggers
52+
.for('user')
53+
.withName('track_email_changes')
54+
.after()
55+
.on('UPDATE')
56+
.watchColumns('email')
57+
.when(c => c.OLD('email').ne(c.NEW('email')))
58+
.notify('user_email_changed')
59+
.build();
60+
61+
// Deploy
62+
await emailChangeTrigger.setup();
63+
await emailChangeTrigger.listen();
64+
65+
// Handle events
66+
emailChangeTrigger.subscribe((event) => {
67+
console.log(`Email changed from ${event.old.email} to ${event.data.email}`);
68+
});
69+
```
70+
71+
## Lifecycle Methods
72+
73+
```typescript
74+
await trigger.setup(); // Create in database
75+
await trigger.listen(); // Start listening for events
76+
await trigger.stop(); // Stop listening
77+
await trigger.drop(); // Remove from database
78+
```
79+
80+
## When to Use
81+
82+
- Single, specific business logic
83+
- Testing individual triggers
84+
- Gradual migration from SQL triggers
85+
- Simple notification needs
86+
87+
## Next: [Registry Pattern](./registry-pattern.md)

0 commit comments

Comments
 (0)