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,407 @@
|
|
|
1
|
+
# How to Define Entities and Properties
|
|
2
|
+
|
|
3
|
+
## Creating Basic Entities
|
|
4
|
+
|
|
5
|
+
Entities are the fundamental data units in the system. Use the `Entity.create()` method to create entities:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { Entity, Property } from 'interaqt';
|
|
9
|
+
|
|
10
|
+
const User = Entity.create({
|
|
11
|
+
name: 'User',
|
|
12
|
+
properties: [
|
|
13
|
+
Property.create({ name: 'name', type: 'string' }),
|
|
14
|
+
Property.create({ name: 'email', type: 'string' }),
|
|
15
|
+
Property.create({ name: 'age', type: 'number' })
|
|
16
|
+
]
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Entity Naming Conventions
|
|
21
|
+
|
|
22
|
+
- Use PascalCase (capitalized camelCase)
|
|
23
|
+
- Names should be singular (User not Users)
|
|
24
|
+
- Names should be descriptive and clearly express the entity's meaning
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
// ✅ Good naming
|
|
28
|
+
const User = Entity.create({ name: 'User' });
|
|
29
|
+
const BlogPost = Entity.create({ name: 'BlogPost' });
|
|
30
|
+
const OrderItem = Entity.create({ name: 'OrderItem' });
|
|
31
|
+
|
|
32
|
+
// ❌ Avoid these naming patterns
|
|
33
|
+
const users = Entity.create({ name: 'users' });
|
|
34
|
+
const data = Entity.create({ name: 'data' });
|
|
35
|
+
const obj = Entity.create({ name: 'obj' });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Defining Property Types
|
|
39
|
+
|
|
40
|
+
### Basic Types
|
|
41
|
+
|
|
42
|
+
The framework supports multiple basic data types:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
const Product = Entity.create({
|
|
46
|
+
name: 'Product',
|
|
47
|
+
properties: [
|
|
48
|
+
Property.create({ name: 'title', type: 'string' }),
|
|
49
|
+
Property.create({ name: 'price', type: 'number' }),
|
|
50
|
+
Property.create({ name: 'isActive', type: 'boolean' }),
|
|
51
|
+
Property.create({ name: 'createdAt', type: 'string' }) // Can store ISO date strings
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### JSON Type
|
|
57
|
+
|
|
58
|
+
For complex data structures, you can use JSON type:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
const User = Entity.create({
|
|
62
|
+
name: 'User',
|
|
63
|
+
properties: [
|
|
64
|
+
Property.create({ name: 'name', type: 'string' }),
|
|
65
|
+
Property.create({
|
|
66
|
+
name: 'profile',
|
|
67
|
+
type: 'object', // JSON object
|
|
68
|
+
collection: false
|
|
69
|
+
}),
|
|
70
|
+
Property.create({
|
|
71
|
+
name: 'tags',
|
|
72
|
+
type: 'string',
|
|
73
|
+
collection: true // Array of strings
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Usage example
|
|
79
|
+
const userData = {
|
|
80
|
+
name: 'John Doe',
|
|
81
|
+
profile: {
|
|
82
|
+
bio: 'Software developer',
|
|
83
|
+
location: 'San Francisco',
|
|
84
|
+
skills: ['JavaScript', 'TypeScript', 'React']
|
|
85
|
+
},
|
|
86
|
+
tags: ['developer', 'javascript', 'react']
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Custom Types
|
|
91
|
+
|
|
92
|
+
You can define custom complex types:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Define address type
|
|
96
|
+
const Address = {
|
|
97
|
+
street: 'string',
|
|
98
|
+
city: 'string',
|
|
99
|
+
country: 'string',
|
|
100
|
+
zipCode: 'string'
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const User = Entity.create({
|
|
104
|
+
name: 'User',
|
|
105
|
+
properties: [
|
|
106
|
+
Property.create({ name: 'name', type: 'string' }),
|
|
107
|
+
Property.create({
|
|
108
|
+
name: 'address',
|
|
109
|
+
type: 'object',
|
|
110
|
+
collection: false
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Setting Default Values
|
|
117
|
+
|
|
118
|
+
### Static Default Values
|
|
119
|
+
|
|
120
|
+
Set fixed default values for properties:
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
const User = Entity.create({
|
|
124
|
+
name: 'User',
|
|
125
|
+
properties: [
|
|
126
|
+
Property.create({
|
|
127
|
+
name: 'status',
|
|
128
|
+
type: 'string',
|
|
129
|
+
defaultValue: 'active'
|
|
130
|
+
}),
|
|
131
|
+
Property.create({
|
|
132
|
+
name: 'score',
|
|
133
|
+
type: 'number',
|
|
134
|
+
defaultValue: 0
|
|
135
|
+
}),
|
|
136
|
+
Property.create({
|
|
137
|
+
name: 'isVerified',
|
|
138
|
+
type: 'boolean',
|
|
139
|
+
defaultValue: false
|
|
140
|
+
})
|
|
141
|
+
]
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Dynamic Default Values (Functions)
|
|
146
|
+
|
|
147
|
+
Use functions to generate dynamic default values:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
const Order = Entity.create({
|
|
151
|
+
name: 'Order',
|
|
152
|
+
properties: [
|
|
153
|
+
Property.create({
|
|
154
|
+
name: 'orderNumber',
|
|
155
|
+
type: 'string',
|
|
156
|
+
defaultValue: () => `ORDER-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
|
157
|
+
}),
|
|
158
|
+
Property.create({
|
|
159
|
+
name: 'createdAt',
|
|
160
|
+
type: 'string',
|
|
161
|
+
defaultValue: () => new Date().toISOString()
|
|
162
|
+
}),
|
|
163
|
+
Property.create({
|
|
164
|
+
name: 'status',
|
|
165
|
+
type: 'string',
|
|
166
|
+
defaultValue: 'pending'
|
|
167
|
+
})
|
|
168
|
+
]
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Default Values Based on Other Fields
|
|
173
|
+
|
|
174
|
+
You can set default values based on other fields in the same record:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const User = Entity.create({
|
|
178
|
+
name: 'User',
|
|
179
|
+
properties: [
|
|
180
|
+
Property.create({ name: 'firstName', type: 'string' }),
|
|
181
|
+
Property.create({ name: 'lastName', type: 'string' }),
|
|
182
|
+
Property.create({
|
|
183
|
+
name: 'displayName',
|
|
184
|
+
type: 'string',
|
|
185
|
+
defaultValue: (record) => `${record.firstName} ${record.lastName}`
|
|
186
|
+
}),
|
|
187
|
+
Property.create({
|
|
188
|
+
name: 'email',
|
|
189
|
+
type: 'string'
|
|
190
|
+
}),
|
|
191
|
+
Property.create({
|
|
192
|
+
name: 'username',
|
|
193
|
+
type: 'string',
|
|
194
|
+
defaultValue: (record) => record.email.split('@')[0]
|
|
195
|
+
})
|
|
196
|
+
]
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Using Computed Properties
|
|
201
|
+
|
|
202
|
+
Computed properties are one of the core features of the framework. Their values are automatically updated when other data changes.
|
|
203
|
+
|
|
204
|
+
### getValue Function
|
|
205
|
+
|
|
206
|
+
Use the `getValue` function to define simple computed properties:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const User = Entity.create({
|
|
210
|
+
name: 'User',
|
|
211
|
+
properties: [
|
|
212
|
+
Property.create({ name: 'firstName', type: 'string' }),
|
|
213
|
+
Property.create({ name: 'lastName', type: 'string' }),
|
|
214
|
+
Property.create({
|
|
215
|
+
name: 'fullName',
|
|
216
|
+
type: 'string',
|
|
217
|
+
getValue: (record) => `${record.firstName} ${record.lastName}`
|
|
218
|
+
})
|
|
219
|
+
]
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Computations Based on Current Record
|
|
224
|
+
|
|
225
|
+
Computed properties can access all fields of the current record:
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
const Product = Entity.create({
|
|
229
|
+
name: 'Product',
|
|
230
|
+
properties: [
|
|
231
|
+
Property.create({ name: 'price', type: 'number' }),
|
|
232
|
+
Property.create({ name: 'taxRate', type: 'number', defaultValue: 0.1 }),
|
|
233
|
+
Property.create({
|
|
234
|
+
name: 'totalPrice',
|
|
235
|
+
type: 'number',
|
|
236
|
+
getValue: (record) => record.price * (1 + record.taxRate)
|
|
237
|
+
}),
|
|
238
|
+
Property.create({
|
|
239
|
+
name: 'priceCategory',
|
|
240
|
+
type: 'string',
|
|
241
|
+
getValue: (record) => {
|
|
242
|
+
if (record.price < 100) return 'budget';
|
|
243
|
+
if (record.price < 500) return 'mid-range';
|
|
244
|
+
return 'premium';
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Persisting Computed Properties
|
|
252
|
+
|
|
253
|
+
By default, computed properties are not stored in the database but calculated dynamically at query time. If you need to persist computation results (e.g., for performance optimization), you can use reactive computations:
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
import { Count } from 'interaqt';
|
|
257
|
+
|
|
258
|
+
const Post = Entity.create({
|
|
259
|
+
name: 'Post',
|
|
260
|
+
properties: [
|
|
261
|
+
Property.create({ name: 'title', type: 'string' }),
|
|
262
|
+
Property.create({ name: 'content', type: 'string' }),
|
|
263
|
+
Property.create({
|
|
264
|
+
name: 'likeCount',
|
|
265
|
+
type: 'number',
|
|
266
|
+
defaultValue: () => 0,
|
|
267
|
+
computation: Count.create({
|
|
268
|
+
record: Like // This will be persisted to the database
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
]
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Property Configuration Options
|
|
276
|
+
|
|
277
|
+
### Required Fields
|
|
278
|
+
|
|
279
|
+
Set fields as required:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
const User = Entity.create({
|
|
283
|
+
name: 'User',
|
|
284
|
+
properties: [
|
|
285
|
+
Property.create({
|
|
286
|
+
name: 'email',
|
|
287
|
+
type: 'string',
|
|
288
|
+
}),
|
|
289
|
+
Property.create({
|
|
290
|
+
name: 'name',
|
|
291
|
+
type: 'string',
|
|
292
|
+
}),
|
|
293
|
+
Property.create({
|
|
294
|
+
name: 'bio',
|
|
295
|
+
type: 'string',
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Constraints and Validation
|
|
302
|
+
|
|
303
|
+
The framework itself does not provide field-level unique constraints and index configuration. These should be implemented at the database level or through business logic:
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const User = Entity.create({
|
|
307
|
+
name: 'User',
|
|
308
|
+
properties: [
|
|
309
|
+
Property.create({
|
|
310
|
+
name: 'email',
|
|
311
|
+
type: 'string'
|
|
312
|
+
// Uniqueness guaranteed through business logic or database constraints
|
|
313
|
+
}),
|
|
314
|
+
Property.create({
|
|
315
|
+
name: 'username',
|
|
316
|
+
type: 'string'
|
|
317
|
+
// Same as above
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
If you need to perform uniqueness checks at the application level, you can implement them through the Attributive system:
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
const UniqueEmailAttributive = Attributive.create({
|
|
327
|
+
name: 'UniqueEmail',
|
|
328
|
+
content: async function(user, { system }) {
|
|
329
|
+
const existingUser = await system.storage.findOne('User',
|
|
330
|
+
MatchExp.atom({ key: 'email', value: ['=', user.email] })
|
|
331
|
+
);
|
|
332
|
+
return !existingUser || existingUser.id === user.id;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Complete Example
|
|
338
|
+
|
|
339
|
+
Here's a complete example of a user entity definition:
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
import { Entity, Property } from 'interaqt';
|
|
343
|
+
|
|
344
|
+
const User = Entity.create({
|
|
345
|
+
name: 'User',
|
|
346
|
+
properties: [
|
|
347
|
+
// Basic information
|
|
348
|
+
Property.create({
|
|
349
|
+
name: 'email',
|
|
350
|
+
type: 'string',
|
|
351
|
+
}),
|
|
352
|
+
Property.create({
|
|
353
|
+
name: 'firstName',
|
|
354
|
+
type: 'string',
|
|
355
|
+
}),
|
|
356
|
+
Property.create({
|
|
357
|
+
name: 'lastName',
|
|
358
|
+
type: 'string',
|
|
359
|
+
}),
|
|
360
|
+
|
|
361
|
+
// Computed properties
|
|
362
|
+
Property.create({
|
|
363
|
+
name: 'fullName',
|
|
364
|
+
type: 'string',
|
|
365
|
+
getValue: (record) => `${record.firstName} ${record.lastName}`
|
|
366
|
+
}),
|
|
367
|
+
|
|
368
|
+
// Fields with default values
|
|
369
|
+
Property.create({
|
|
370
|
+
name: 'status',
|
|
371
|
+
type: 'string',
|
|
372
|
+
defaultValue: 'active'
|
|
373
|
+
}),
|
|
374
|
+
Property.create({
|
|
375
|
+
name: 'createdAt',
|
|
376
|
+
type: 'string',
|
|
377
|
+
defaultValue: () => new Date().toISOString()
|
|
378
|
+
}),
|
|
379
|
+
|
|
380
|
+
// JSON fields
|
|
381
|
+
Property.create({
|
|
382
|
+
name: 'profile',
|
|
383
|
+
type: 'object',
|
|
384
|
+
collection: false,
|
|
385
|
+
defaultValue: {}
|
|
386
|
+
}),
|
|
387
|
+
Property.create({
|
|
388
|
+
name: 'tags',
|
|
389
|
+
type: 'string',
|
|
390
|
+
collection: true,
|
|
391
|
+
defaultValue: []
|
|
392
|
+
}),
|
|
393
|
+
|
|
394
|
+
// Optional fields
|
|
395
|
+
Property.create({
|
|
396
|
+
name: 'bio',
|
|
397
|
+
type: 'string',
|
|
398
|
+
}),
|
|
399
|
+
Property.create({
|
|
400
|
+
name: 'avatar',
|
|
401
|
+
type: 'string',
|
|
402
|
+
})
|
|
403
|
+
]
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
export { User };
|
|
407
|
+
```
|