interaqt 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/.claude/agents/code-generation-handler.md +2 -0
- package/agent/.claude/agents/computation-generation-handler.md +1 -0
- package/agent/.claude/agents/implement-design-handler.md +4 -13
- package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
- package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
- package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
- package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
- package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
- package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
- package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
- package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
- package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
- package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
- package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
- package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
- package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
- package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
- package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
- package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
- package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
- package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
- package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
- package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
- package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
- package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
- package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
- package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
- package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
- package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
- package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
- package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
- package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
- package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
- package/agent/agentspace/knowledge/usage/README.md +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
# Common Anti-Patterns and Mistakes
|
|
2
|
+
|
|
3
|
+
This document consolidates common mistakes and anti-patterns to help developers avoid pitfalls when using the interaqt framework.
|
|
4
|
+
|
|
5
|
+
## 1. Import-Related Mistakes
|
|
6
|
+
|
|
7
|
+
### ❌ Importing Non-Existent Entities
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// ❌ WRONG: User is not exported from interaqt
|
|
11
|
+
import { User, Entity, Property } from 'interaqt';
|
|
12
|
+
|
|
13
|
+
// ✅ CORRECT: Define your own User entity
|
|
14
|
+
import { Entity, Property } from 'interaqt';
|
|
15
|
+
|
|
16
|
+
const User = Entity.create({
|
|
17
|
+
name: 'User',
|
|
18
|
+
properties: [
|
|
19
|
+
Property.create({ name: 'name', type: 'string' }),
|
|
20
|
+
Property.create({ name: 'email', type: 'string' })
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### ❌ Using Non-Existent Computation Types
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// ❌ WRONG: RelationBasedEvery doesn't exist
|
|
29
|
+
import { RelationBasedEvery } from 'interaqt';
|
|
30
|
+
|
|
31
|
+
// ✅ CORRECT: Use Every with relations
|
|
32
|
+
import { Every } from 'interaqt';
|
|
33
|
+
|
|
34
|
+
const allCompleted = Every.create({
|
|
35
|
+
record: UserTaskRelation,
|
|
36
|
+
callback: (relation) => relation.status === 'completed'
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### ❌ Wrong Entity Name
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
// ❌ WRONG: It's not InteractionEvent
|
|
44
|
+
import { InteractionEvent } from 'interaqt';
|
|
45
|
+
|
|
46
|
+
// ✅ CORRECT: The correct name is InteractionEventEntity
|
|
47
|
+
import { InteractionEventEntity } from 'interaqt';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 2. Property Definition Mistakes
|
|
51
|
+
|
|
52
|
+
### ❌ Using Non-Existent Property Options
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
// ❌ WRONG: identifier property doesn't exist
|
|
56
|
+
Property.create({
|
|
57
|
+
name: 'id',
|
|
58
|
+
type: 'string',
|
|
59
|
+
identifier: true // This doesn't exist!
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ✅ CORRECT: ID uniqueness is handled by storage layer
|
|
63
|
+
Property.create({
|
|
64
|
+
name: 'id',
|
|
65
|
+
type: 'string'
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### ❌ Using Non-Function defaultValue
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
// ❌ WRONG: defaultValue should always be a function
|
|
73
|
+
Property.create({
|
|
74
|
+
name: 'status',
|
|
75
|
+
type: 'string',
|
|
76
|
+
defaultValue: 'active' // Should be a function!
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ✅ CORRECT: Use function form
|
|
80
|
+
Property.create({
|
|
81
|
+
name: 'status',
|
|
82
|
+
type: 'string',
|
|
83
|
+
defaultValue: () => 'active'
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 3. Relation Definition Mistakes
|
|
88
|
+
|
|
89
|
+
### ❌ Specifying Relation Name
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
// ❌ WRONG: Don't specify name for relations
|
|
93
|
+
const UserPostRelation = Relation.create({
|
|
94
|
+
name: 'UserPost', // Don't do this!
|
|
95
|
+
source: User,
|
|
96
|
+
target: Post,
|
|
97
|
+
type: '1:n'
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ✅ CORRECT: Name is auto-generated
|
|
101
|
+
const UserPostRelation = Relation.create({
|
|
102
|
+
source: User,
|
|
103
|
+
target: Post,
|
|
104
|
+
type: '1:n'
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### ❌ Using Wrong Property Names
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// ❌ WRONG: It's not relationType
|
|
112
|
+
const UserPostRelation = Relation.create({
|
|
113
|
+
source: User,
|
|
114
|
+
target: Post,
|
|
115
|
+
relationType: '1:n' // Wrong property name!
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ✅ CORRECT: Use 'type'
|
|
119
|
+
const UserPostRelation = Relation.create({
|
|
120
|
+
source: User,
|
|
121
|
+
target: Post,
|
|
122
|
+
type: '1:n'
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### ❌ Wrong Relation Type Format
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// ❌ WRONG: Wrong format
|
|
130
|
+
Relation.create({
|
|
131
|
+
type: 'one:many' // Wrong!
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ✅ CORRECT: Use proper format
|
|
135
|
+
Relation.create({
|
|
136
|
+
type: '1:n' // or '1:1', 'n:1', 'n:n'
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 4. Interaction Definition Mistakes
|
|
141
|
+
|
|
142
|
+
### ❌ Adding User Property to Interaction
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// ❌ WRONG: user is not a property of Interaction
|
|
146
|
+
const SomeInteraction = Interaction.create({
|
|
147
|
+
name: 'SomeInteraction',
|
|
148
|
+
user: User, // This doesn't exist!
|
|
149
|
+
action: Action.create({ name: 'someAction' })
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ✅ CORRECT: User is passed at execution time
|
|
153
|
+
const SomeInteraction = Interaction.create({
|
|
154
|
+
name: 'SomeInteraction',
|
|
155
|
+
action: Action.create({ name: 'someAction' })
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// User context provided when calling
|
|
159
|
+
await controller.callInteraction('SomeInteraction', {
|
|
160
|
+
user: { id: 'user123', name: 'John' }, // Passed here
|
|
161
|
+
payload: { /* ... */ }
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### ❌ Thinking Action Contains Logic
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// ❌ WRONG: Action is just an identifier
|
|
169
|
+
const CreatePost = Action.create({
|
|
170
|
+
name: 'createPost',
|
|
171
|
+
execute: async () => { /* ... */ }, // No execute method!
|
|
172
|
+
handler: () => { /* ... */ } // No handler either!
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// ✅ CORRECT: Action is just a name/identifier
|
|
176
|
+
const CreatePost = Action.create({
|
|
177
|
+
name: 'createPost' // That's it!
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 5. Computation Mistakes
|
|
182
|
+
|
|
183
|
+
### ❌ Using Transform for Property Computation
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
// ❌ WRONG: Transform is for collection-to-collection transformation
|
|
187
|
+
Property.create({
|
|
188
|
+
name: 'displayName',
|
|
189
|
+
computation: Transform.create({
|
|
190
|
+
record: User, // Wrong usage!
|
|
191
|
+
callback: (user) => `${user.firstName} ${user.lastName}`
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// ✅ CORRECT: Use getValue for same-entity property computation
|
|
196
|
+
Property.create({
|
|
197
|
+
name: 'displayName',
|
|
198
|
+
type: 'string',
|
|
199
|
+
getValue: (record) => `${record.firstName} ${record.lastName}`
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### ❌ Circular References in Transform
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
// ❌ WRONG: Entity referencing itself in Transform
|
|
207
|
+
const User = Entity.create({
|
|
208
|
+
name: 'User',
|
|
209
|
+
computation: Transform.create({
|
|
210
|
+
record: User, // Circular reference!
|
|
211
|
+
callback: (user) => { /* ... */ }
|
|
212
|
+
})
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// ✅ CORRECT: Transform should reference different entities
|
|
216
|
+
const DerivedEntity = Entity.create({
|
|
217
|
+
name: 'DerivedEntity',
|
|
218
|
+
computation: Transform.create({
|
|
219
|
+
record: SourceEntity, // Different entity
|
|
220
|
+
callback: (source) => { /* ... */ }
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### ❌ Using String References in StateMachine
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
// ❌ WRONG: Using strings for state references
|
|
229
|
+
StateMachine.create({
|
|
230
|
+
states: [activeState, inactiveState],
|
|
231
|
+
transfers: [
|
|
232
|
+
StateTransfer.create({
|
|
233
|
+
current: 'active', // Should be object reference!
|
|
234
|
+
next: 'inactive', // Should be object reference!
|
|
235
|
+
trigger: SomeInteraction
|
|
236
|
+
})
|
|
237
|
+
],
|
|
238
|
+
defaultState: 'active' // Should be object reference!
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// ✅ CORRECT: Use object references
|
|
242
|
+
const activeState = StateNode.create({ name: 'active' });
|
|
243
|
+
const inactiveState = StateNode.create({ name: 'inactive' });
|
|
244
|
+
|
|
245
|
+
StateMachine.create({
|
|
246
|
+
states: [activeState, inactiveState],
|
|
247
|
+
transfers: [
|
|
248
|
+
StateTransfer.create({
|
|
249
|
+
current: activeState, // Object reference
|
|
250
|
+
next: inactiveState, // Object reference
|
|
251
|
+
trigger: SomeInteraction
|
|
252
|
+
})
|
|
253
|
+
],
|
|
254
|
+
defaultState: activeState // Object reference
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 6. Testing Mistakes
|
|
259
|
+
|
|
260
|
+
### ❌ Using try-catch for Error Testing
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// ❌ WRONG: interaqt doesn't throw exceptions
|
|
264
|
+
test('should fail validation', async () => {
|
|
265
|
+
try {
|
|
266
|
+
await controller.callInteraction('SomeInteraction', {...});
|
|
267
|
+
fail('Should have thrown error');
|
|
268
|
+
} catch (e) {
|
|
269
|
+
// This code will never execute!
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// ✅ CORRECT: Check error field in result
|
|
274
|
+
test('should fail validation', async () => {
|
|
275
|
+
const result = await controller.callInteraction('SomeInteraction', {...});
|
|
276
|
+
expect(result.error).toBeTruthy();
|
|
277
|
+
expect(result.error.message).toContain('validation failed');
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### ❌ Using storage.create() to Test Validation
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
// ❌ WRONG: storage.create bypasses ALL validation
|
|
285
|
+
test('should fail with invalid data', async () => {
|
|
286
|
+
const result = await system.storage.create('Style', {
|
|
287
|
+
label: '', // Empty label
|
|
288
|
+
slug: '' // Empty slug
|
|
289
|
+
});
|
|
290
|
+
// This will ALWAYS succeed! storage.create bypasses validation
|
|
291
|
+
expect(result).toBeTruthy(); // Wrong expectation!
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// ✅ CORRECT: Test validation through Interactions
|
|
295
|
+
test('should fail with invalid data', async () => {
|
|
296
|
+
const result = await controller.callInteraction('CreateStyle', {
|
|
297
|
+
user: testUser,
|
|
298
|
+
payload: {
|
|
299
|
+
label: '', // Empty label
|
|
300
|
+
slug: '' // Empty slug
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
expect(result.error).toBeDefined();
|
|
305
|
+
expect(result.error.type).toBe('validation failed');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// ✅ CORRECT: Use storage.create ONLY for test setup
|
|
309
|
+
beforeEach(async () => {
|
|
310
|
+
// Create test data that should already exist
|
|
311
|
+
testUser = await system.storage.create('User', {
|
|
312
|
+
name: 'Test User',
|
|
313
|
+
role: 'admin'
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
existingStyle = await system.storage.create('Style', {
|
|
317
|
+
label: 'Existing Style',
|
|
318
|
+
slug: 'existing-style'
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### ❌ Testing Entity/Relation Directly
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
// ❌ WRONG: Don't test entities separately
|
|
327
|
+
test('should create User entity', async () => {
|
|
328
|
+
const user = await system.storage.create('User', {
|
|
329
|
+
name: 'John',
|
|
330
|
+
email: 'john@example.com'
|
|
331
|
+
});
|
|
332
|
+
expect(user.name).toBe('John');
|
|
333
|
+
// This is testing storage, not business logic!
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// ✅ CORRECT: Test through Interactions
|
|
337
|
+
test('should create user through interaction', async () => {
|
|
338
|
+
const result = await controller.callInteraction('CreateUser', {
|
|
339
|
+
user: adminUser,
|
|
340
|
+
payload: {
|
|
341
|
+
name: 'John',
|
|
342
|
+
email: 'john@example.com'
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
expect(result.error).toBeUndefined();
|
|
347
|
+
|
|
348
|
+
// Verify side effects
|
|
349
|
+
const user = await system.storage.findOne('User',
|
|
350
|
+
MatchExp.atom({ key: 'email', value: ['=', 'john@example.com'] })
|
|
351
|
+
);
|
|
352
|
+
expect(user.name).toBe('John');
|
|
353
|
+
});
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## 7. Payload Entity Reference Issues
|
|
357
|
+
|
|
358
|
+
### ❌ Entity Resolution Problems
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
// ❌ PROBLEMATIC: Can cause "entity undefined not found"
|
|
362
|
+
PayloadItem.create({
|
|
363
|
+
name: 'version',
|
|
364
|
+
base: Version, // Can cause resolution issues with circular deps
|
|
365
|
+
isRef: false
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// ✅ WORKAROUND: Use generic object type when needed
|
|
369
|
+
PayloadItem.create({
|
|
370
|
+
name: 'version',
|
|
371
|
+
base: 'object', // Generic type avoids resolution issues
|
|
372
|
+
isRef: false
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## 8. Authentication Misunderstandings
|
|
377
|
+
|
|
378
|
+
### ❌ Creating Authentication Interactions
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
// ❌ WRONG: interaqt doesn't handle authentication
|
|
382
|
+
const UserLogin = Interaction.create({
|
|
383
|
+
name: 'UserLogin',
|
|
384
|
+
action: Action.create({ name: 'login' }),
|
|
385
|
+
payload: Payload.create({
|
|
386
|
+
items: [
|
|
387
|
+
PayloadItem.create({ name: 'username' }),
|
|
388
|
+
PayloadItem.create({ name: 'password' })
|
|
389
|
+
]
|
|
390
|
+
})
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// ✅ CORRECT: Authentication is external
|
|
394
|
+
// User identity should be provided by external system (JWT, Session, etc.)
|
|
395
|
+
// When calling interactions, user is already authenticated:
|
|
396
|
+
await controller.callInteraction('CreatePost', {
|
|
397
|
+
user: authenticatedUser, // Pre-authenticated by external system
|
|
398
|
+
payload: { /* ... */ }
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## 9. ID Generation Mistakes
|
|
403
|
+
|
|
404
|
+
### ❌ Manually Specifying IDs
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
// ❌ WRONG: Never manually specify ID when creating entities
|
|
408
|
+
const result = await controller.callInteraction('CreateArticle', {
|
|
409
|
+
user: currentUser,
|
|
410
|
+
payload: {
|
|
411
|
+
id: uuid(), // ❌ Don't do this!
|
|
412
|
+
title: 'My Article',
|
|
413
|
+
content: 'Content...'
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// ❌ WRONG: Don't specify ID in Transform computation
|
|
418
|
+
const Article = Entity.create({
|
|
419
|
+
name: 'Article',
|
|
420
|
+
computation: Transform.create({
|
|
421
|
+
record: InteractionEventEntity,
|
|
422
|
+
callback: function(event) {
|
|
423
|
+
if (event.interactionName === 'CreateArticle') {
|
|
424
|
+
return {
|
|
425
|
+
id: uuid(), // ❌ Never specify ID!
|
|
426
|
+
title: event.payload.title,
|
|
427
|
+
content: event.payload.content
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// ❌ WRONG: Don't specify ID in test data setup
|
|
435
|
+
beforeEach(async () => {
|
|
436
|
+
const user = await system.storage.create('User', {
|
|
437
|
+
id: 'user-123', // ❌ Don't specify ID!
|
|
438
|
+
name: 'Test User'
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### ✅ Correct Approaches for Tracking Created Data
|
|
444
|
+
|
|
445
|
+
#### Option 1: Use Return Value from storage.create
|
|
446
|
+
|
|
447
|
+
```javascript
|
|
448
|
+
// ✅ CORRECT: Use the returned entity which includes auto-generated ID
|
|
449
|
+
beforeEach(async () => {
|
|
450
|
+
// storage.create returns the created entity with auto-generated ID
|
|
451
|
+
testUser = await system.storage.create('User', {
|
|
452
|
+
name: 'Test User',
|
|
453
|
+
email: 'test@example.com'
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Use the returned entity's ID
|
|
457
|
+
testArticle = await system.storage.create('Article', {
|
|
458
|
+
title: 'Test Article',
|
|
459
|
+
author: { id: testUser.id } // Reference using auto-generated ID
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// Use in tests
|
|
464
|
+
test('should update article', async () => {
|
|
465
|
+
const result = await controller.callInteraction('UpdateArticle', {
|
|
466
|
+
user: testUser,
|
|
467
|
+
payload: {
|
|
468
|
+
articleId: testArticle.id, // Use the auto-generated ID
|
|
469
|
+
title: 'Updated Title'
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
#### Option 2: Use clientId Property for Tracking
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
// ✅ CORRECT: Define a clientId property for tracking
|
|
479
|
+
const Article = Entity.create({
|
|
480
|
+
name: 'Article',
|
|
481
|
+
properties: [
|
|
482
|
+
Property.create({ name: 'title', type: 'string' }),
|
|
483
|
+
Property.create({ name: 'content', type: 'string' }),
|
|
484
|
+
// Add clientId for tracking purposes
|
|
485
|
+
Property.create({
|
|
486
|
+
name: 'clientId',
|
|
487
|
+
type: 'string',
|
|
488
|
+
description: 'Client-provided ID for tracking created entities'
|
|
489
|
+
})
|
|
490
|
+
],
|
|
491
|
+
computation: Transform.create({
|
|
492
|
+
record: InteractionEventEntity,
|
|
493
|
+
callback: function(event) {
|
|
494
|
+
if (event.interactionName === 'CreateArticle') {
|
|
495
|
+
return {
|
|
496
|
+
// ID is auto-generated, not specified
|
|
497
|
+
title: event.payload.title,
|
|
498
|
+
content: event.payload.content,
|
|
499
|
+
clientId: event.payload.clientId // Use clientId for tracking
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Use in interaction
|
|
507
|
+
const result = await controller.callInteraction('CreateArticle', {
|
|
508
|
+
user: currentUser,
|
|
509
|
+
payload: {
|
|
510
|
+
title: 'My Article',
|
|
511
|
+
content: 'Content...',
|
|
512
|
+
clientId: 'my-tracking-id-123' // Provide clientId for tracking
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Find the created article using clientId
|
|
517
|
+
const createdArticle = await system.storage.findOne('Article',
|
|
518
|
+
MatchExp.atom({ key: 'clientId', value: ['=', 'my-tracking-id-123'] })
|
|
519
|
+
);
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### Option 3: Query by Unique Properties
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
// ✅ CORRECT: Find created entity by unique properties
|
|
526
|
+
const result = await controller.callInteraction('CreateUser', {
|
|
527
|
+
user: adminUser,
|
|
528
|
+
payload: {
|
|
529
|
+
email: 'unique@example.com', // Use unique email
|
|
530
|
+
name: 'John Doe'
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// Find the created user by unique email
|
|
535
|
+
const createdUser = await system.storage.findOne('User',
|
|
536
|
+
MatchExp.atom({ key: 'email', value: ['=', 'unique@example.com'] })
|
|
537
|
+
);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Why IDs Must Be Auto-Generated
|
|
541
|
+
|
|
542
|
+
1. **Framework Design**: InterAQT manages ID generation internally to ensure uniqueness and consistency
|
|
543
|
+
2. **Storage Layer Responsibility**: Different storage backends may have different ID generation strategies
|
|
544
|
+
3. **Data Integrity**: Manual IDs can cause conflicts and break relationships
|
|
545
|
+
4. **Reactive System**: The framework needs control over IDs for proper change tracking
|
|
546
|
+
|
|
547
|
+
## Key Takeaways
|
|
548
|
+
|
|
549
|
+
1. **interaqt provides tools, not pre-built business entities**
|
|
550
|
+
2. **All entities must be defined by you**
|
|
551
|
+
3. **User authentication is external to the framework**
|
|
552
|
+
4. **Action is just an identifier, not an operation**
|
|
553
|
+
5. **Transform is for collection transformations, not property computations**
|
|
554
|
+
6. **Always use object references in StateMachine, not strings**
|
|
555
|
+
7. **Check result.error for errors, don't use try-catch**
|
|
556
|
+
8. **storage.create() bypasses ALL validation - use only for test setup**
|
|
557
|
+
9. **ALL business logic testing must use callInteraction()**
|
|
558
|
+
10. **Never test Entity/Relation directly - test through Interactions**
|
|
559
|
+
11. **NEVER manually specify IDs - they are always auto-generated by the framework**
|
|
560
|
+
12. **Use storage.create return value or clientId property to track created entities**
|
|
561
|
+
13. **When in doubt, check the [API Exports Reference](./18-api-exports-reference.md)**
|
|
562
|
+
|
|
563
|
+
Remember: The framework is about **declaring what data is**, not **how to manipulate it**.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# interaqt Framework Learning Guide
|
|
2
|
+
|
|
3
|
+
⚠️ **Important: Please follow the learning order below. Skipping any step may lead to misunderstanding**
|
|
4
|
+
|
|
5
|
+
## 📚 Required Reading Order
|
|
6
|
+
|
|
7
|
+
### 1. 🧠 [Mindset Shift](./00-mindset-shift.md) **← Most Important!**
|
|
8
|
+
Before learning anything else, you **must** first understand the mindset shift from imperative to declarative thinking. This is the key to understanding interaqt.
|
|
9
|
+
|
|
10
|
+
### 2. 🎯 [Core Concepts](./01-core-concepts.md)
|
|
11
|
+
Understand the basic concepts and reactive mechanisms of the framework.
|
|
12
|
+
|
|
13
|
+
### 3. 🏗️ [Define Entities & Properties](./02-define-entities-properties.md)
|
|
14
|
+
Learn how to define data structures.
|
|
15
|
+
|
|
16
|
+
### 4. 🔗 [Entity Relations](./03-entity-relations.md)
|
|
17
|
+
Understand relationships between entities.
|
|
18
|
+
|
|
19
|
+
### 5. ⚡ [Reactive Computations](./04-reactive-computations.md)
|
|
20
|
+
Master declarative data computation.
|
|
21
|
+
|
|
22
|
+
### 6. 🎮 [Interactions](./05-interactions.md)
|
|
23
|
+
Learn how to define user interactions (Remember: Action is just an identifier!).
|
|
24
|
+
|
|
25
|
+
### 7. 🔐 [Attributive Permissions](./06-attributive-permissions.md)
|
|
26
|
+
Understand how to control access permissions.
|
|
27
|
+
|
|
28
|
+
### 8. 📦 [Payload Parameters](./07-payload-parameters.md)
|
|
29
|
+
Learn how to define and validate interaction parameters.
|
|
30
|
+
|
|
31
|
+
### 9. 📋 [Activities](./08-activities.md)
|
|
32
|
+
Design complex business processes.
|
|
33
|
+
|
|
34
|
+
### 10. 🎪 [Other Advanced Features](./09-filtered-entities.md)
|
|
35
|
+
Filtered entities, async computations, etc.
|
|
36
|
+
|
|
37
|
+
### 11. 📖 [API Reference](./14-api-reference.md)
|
|
38
|
+
Detailed API documentation.
|
|
39
|
+
|
|
40
|
+
## ⚠️ Common Misconceptions
|
|
41
|
+
|
|
42
|
+
### Misconception 1: Treating Action as Operation Function
|
|
43
|
+
```javascript
|
|
44
|
+
// ❌ Wrong: Thinking Action contains operational logic
|
|
45
|
+
const CreatePost = Action.create({
|
|
46
|
+
name: 'createPost',
|
|
47
|
+
handler: () => { /* operational logic */ } // Action has no handler!
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ✅ Correct: Action is just an identifier
|
|
51
|
+
const CreatePost = Action.create({
|
|
52
|
+
name: 'createPost' // That's it
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Misconception 2: Trying to Operate Data in Interactions
|
|
57
|
+
```javascript
|
|
58
|
+
// ❌ Wrong: Trying to write data operation logic somewhere
|
|
59
|
+
const CreatePost = Interaction.create({
|
|
60
|
+
name: 'CreatePost',
|
|
61
|
+
onExecute: async (payload) => { // Interaction has no onExecute!
|
|
62
|
+
// Trying to write creation logic here...
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// ✅ Correct: Declare data existence through reactive computations
|
|
67
|
+
const UserPostRelation = Relation.create({
|
|
68
|
+
computation: Transform.create({
|
|
69
|
+
record: InteractionEventEntity,
|
|
70
|
+
callback: (event) => {
|
|
71
|
+
if (event.interactionName === 'CreatePost') {
|
|
72
|
+
return { /* post data */ };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Misconception 3: Asking Wrong Questions
|
|
80
|
+
```javascript
|
|
81
|
+
// ❌ Wrong question:
|
|
82
|
+
// "When user creates a post, how should I update the user's post count?"
|
|
83
|
+
|
|
84
|
+
// ✅ Correct question:
|
|
85
|
+
// "What is the essence of user's post count?"
|
|
86
|
+
// Answer: Count of user-post relations
|
|
87
|
+
|
|
88
|
+
Property.create({
|
|
89
|
+
name: 'postCount',
|
|
90
|
+
computation: Count.create({
|
|
91
|
+
record: UserPostRelation
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 🔥 Core Points
|
|
97
|
+
|
|
98
|
+
1. **Only Interactions generate data**: All other data are computed results of Interactions
|
|
99
|
+
2. **Action is identifier**: Contains no operational logic
|
|
100
|
+
3. **Declare data essence**: Don't think "how to compute", think "what data is"
|
|
101
|
+
4. **Unidirectional data flow**: Interaction → Event → Transform/Count → Data
|
|
102
|
+
5. **Never operate data**: Only declare data existence conditions
|
|
103
|
+
|
|
104
|
+
## 🎯 Learning Goals
|
|
105
|
+
|
|
106
|
+
After completing these documents, you should be able to:
|
|
107
|
+
|
|
108
|
+
- ✅ Understand declarative vs imperative differences
|
|
109
|
+
- ✅ Correctly use Interaction and Action
|
|
110
|
+
- ✅ Declare data relationships with reactive computations
|
|
111
|
+
- ✅ Avoid writing operational logic in wrong places
|
|
112
|
+
- ✅ Establish correct mental model of data flow
|
|
113
|
+
|
|
114
|
+
Remember: **Stop thinking "how to do", start thinking "what is"**!
|
|
115
|
+
|
|
116
|
+
## 📚 Complete Learning Path
|
|
117
|
+
|
|
118
|
+
### Core Concepts
|
|
119
|
+
1. [Mindset Shift](./00-mindset-shift.md) - Understanding declarative thinking
|
|
120
|
+
2. [Core Concepts](./01-core-concepts.md) - Framework fundamentals
|
|
121
|
+
3. [Define Entities & Properties](./02-define-entities-properties.md) - Data structure definition
|
|
122
|
+
4. [Entity Relations](./03-entity-relations.md) - Relationships between entities
|
|
123
|
+
|
|
124
|
+
### Reactive System
|
|
125
|
+
5. [Reactive Computations](./04-reactive-computations.md) - Declarative data computation
|
|
126
|
+
6. [Interactions](./05-interactions.md) - User interaction definition
|
|
127
|
+
7. [Attributive Permissions](./06-attributive-permissions.md) - Access control
|
|
128
|
+
8. [Payload Parameters](./07-payload-parameters.md) - Interaction parameter validation
|
|
129
|
+
9. [Activities](./08-activities.md) - Complex business processes
|
|
130
|
+
|
|
131
|
+
### Advanced Features
|
|
132
|
+
10. [Filtered Entities](./09-filtered-entities.md) - Entity filtering and views
|
|
133
|
+
11. [Async Computations](./10-async-computations.md) - Asynchronous operations
|
|
134
|
+
12. [Global Dictionaries](./11-global-dictionaries.md) - Global state management
|
|
135
|
+
13. [Data Querying](./12-data-querying.md) - Advanced query patterns
|
|
136
|
+
|
|
137
|
+
### Reference
|
|
138
|
+
14. [Testing](./13-testing.md) - Testing strategies
|
|
139
|
+
15. [API Reference](./14-api-reference.md) - Complete API documentation
|
|
140
|
+
16. [CRUD Patterns](./15-entity-crud-patterns.md) - Common patterns
|
|
141
|
+
17. [Frontend Integration](./16-frontend-page-design-guide.md) - UI integration
|
|
142
|
+
18. [Performance Optimization](./17-performance-optimization.md) - Performance tips
|
|
143
|
+
19. [API Exports Reference](./18-api-exports-reference.md) - Complete list of available imports
|
|
144
|
+
20. [Common Anti-Patterns](./19-common-anti-patterns.md) - Mistakes to avoid
|
|
145
|
+
|
|
146
|
+
## 📞 Need Help?
|
|
147
|
+
|
|
148
|
+
If you find yourself still thinking about "how to operate data", please re-read [Mindset Shift](./00-mindset-shift.md). This mindset shift is a prerequisite for using interaqt.
|