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,283 @@
|
|
|
1
|
+
# Performance Optimization Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This chapter introduces key performance optimization strategies in the interaqt framework, particularly incremental computation optimization for reactive computations. Proper data modeling and dependency design can greatly improve system performance and avoid unnecessary full table scans.
|
|
6
|
+
|
|
7
|
+
## Core Principle: Incremental vs Full Computation
|
|
8
|
+
|
|
9
|
+
### Advantages of Incremental Computation
|
|
10
|
+
|
|
11
|
+
The core advantage of the interaqt framework lies in its **incremental computation** capability. When data changes occur, the framework can:
|
|
12
|
+
|
|
13
|
+
1. **Precise Targeting**: Only recompute affected portions
|
|
14
|
+
2. **Incremental Updates**: Directly calculate new results using change deltas
|
|
15
|
+
3. **Avoid Full Table Scans**: No need to re-read all related data
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Example: Incremental computation for Count
|
|
19
|
+
class CountComputation {
|
|
20
|
+
async incrementalCompute(lastValue: number, mutationEvent: RecordMutationEvent): Promise<number> {
|
|
21
|
+
switch (mutationEvent.type) {
|
|
22
|
+
case 'create': return lastValue + 1; // O(1) operation
|
|
23
|
+
case 'delete': return lastValue - 1; // O(1) operation
|
|
24
|
+
case 'update': return lastValue; // Usually doesn't affect count
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Performance Issues with Full Computation
|
|
31
|
+
|
|
32
|
+
When the framework cannot perform incremental computation, it degrades to **full recomputation**:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Full recomputation: needs to read all related records
|
|
36
|
+
async compute(dataDeps: any): Promise<number> {
|
|
37
|
+
const allRecords = await this.storage.find(entityName); // Full table scan!
|
|
38
|
+
return allRecords.length;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Key Performance Trap: x:n Relationship Dependency Paths
|
|
43
|
+
|
|
44
|
+
### Problem Description
|
|
45
|
+
|
|
46
|
+
When reactive computations access dependency paths containing **x:n relationships** through `attributeQuery`, without proper modeling, it can lead to performance issues:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// ⚠️ Potential performance issue: dependency path contains 1:n relationship
|
|
50
|
+
const User = Entity.create({
|
|
51
|
+
name: 'User',
|
|
52
|
+
properties: [
|
|
53
|
+
Property.create({
|
|
54
|
+
name: 'totalPostLikes',
|
|
55
|
+
type: 'number',
|
|
56
|
+
defaultValue: () => 0,
|
|
57
|
+
computation: Count.create({
|
|
58
|
+
record: userPostRelation, // User 1:n Post
|
|
59
|
+
// Issue: accessing Post's likes through relationship path
|
|
60
|
+
attributeQuery: [['target', { attributeQuery: ['likes'] }]] // Post 1:n Like
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Problem Analysis
|
|
68
|
+
|
|
69
|
+
**Difficulty of incremental computation in x:n relationships**:
|
|
70
|
+
|
|
71
|
+
1. **Complex dependency paths**: `User → Posts → Likes` contains two levels of x:n relationships
|
|
72
|
+
2. **Incremental computation complexity**: When a Post's Like changes, the framework struggles to efficiently:
|
|
73
|
+
- Determine which Users are affected
|
|
74
|
+
- Calculate incremental changes
|
|
75
|
+
- Avoid rescanning all Posts and Likes
|
|
76
|
+
|
|
77
|
+
3. **Degradation to full computation**: The framework may:
|
|
78
|
+
- Re-read all of the user's Posts
|
|
79
|
+
- Recount all Posts' Likes
|
|
80
|
+
- Result in O(n) or even O(n²) performance overhead
|
|
81
|
+
|
|
82
|
+
## Solution: Express n-side Computation Through Properties
|
|
83
|
+
|
|
84
|
+
### Core Strategy
|
|
85
|
+
|
|
86
|
+
**Define computed properties directly on n-side entities**, allowing reactive computations to utilize incremental updates:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// ✅ Optimization solution: Define likeCount property on Post entity
|
|
90
|
+
const Post = Entity.create({
|
|
91
|
+
name: 'Post',
|
|
92
|
+
properties: [
|
|
93
|
+
Property.create({ name: 'title', type: 'string' }),
|
|
94
|
+
Property.create({ name: 'content', type: 'string' }),
|
|
95
|
+
// Define computed property directly on n-side
|
|
96
|
+
Property.create({
|
|
97
|
+
name: 'likeCount',
|
|
98
|
+
type: 'number',
|
|
99
|
+
defaultValue: () => 0,
|
|
100
|
+
computation: Count.create({
|
|
101
|
+
record: postLikeRelation // Post 1:n Like, simple one-level relationship
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ✅ Then use simplified dependency path on User side
|
|
108
|
+
const User = Entity.create({
|
|
109
|
+
name: 'User',
|
|
110
|
+
properties: [
|
|
111
|
+
Property.create({
|
|
112
|
+
name: 'totalPostLikes',
|
|
113
|
+
type: 'number',
|
|
114
|
+
defaultValue: () => 0,
|
|
115
|
+
computation: Summation.create({
|
|
116
|
+
record: userPostRelation, // User 1:n Post
|
|
117
|
+
// Now only need to access Post's likeCount property (already pre-computed)
|
|
118
|
+
attributeQuery: [['target', { attributeQuery: ['likeCount'] }]]
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
]
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Optimization Results
|
|
126
|
+
|
|
127
|
+
With this approach:
|
|
128
|
+
|
|
129
|
+
1. **Incremental computation for Post.likeCount**:
|
|
130
|
+
- When Like is created/deleted: `likeCount += 1` or `likeCount -= 1`
|
|
131
|
+
- Time complexity: O(1)
|
|
132
|
+
|
|
133
|
+
2. **Incremental computation for User.totalPostLikes**:
|
|
134
|
+
- When Post.likeCount changes: `totalPostLikes += delta`
|
|
135
|
+
- Time complexity: O(1)
|
|
136
|
+
|
|
137
|
+
3. **Avoid full table scans**:
|
|
138
|
+
- No need to re-read all Likes
|
|
139
|
+
- No need to recompute statistics for all Posts
|
|
140
|
+
|
|
141
|
+
## Performance Optimization Patterns
|
|
142
|
+
|
|
143
|
+
### Pattern 1: Hierarchical Computed Properties
|
|
144
|
+
|
|
145
|
+
**Principle**: Define aggregate computations on the n-side of relationships, reference pre-computed results on the 1-side.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// 1. Calculate subtotal on order items
|
|
149
|
+
const OrderItem = Entity.create({
|
|
150
|
+
name: 'OrderItem',
|
|
151
|
+
properties: [
|
|
152
|
+
Property.create({ name: 'quantity', type: 'number' }),
|
|
153
|
+
Property.create({ name: 'unitPrice', type: 'number' }),
|
|
154
|
+
// Compute on n-side
|
|
155
|
+
Property.create({
|
|
156
|
+
name: 'subtotal',
|
|
157
|
+
type: 'number',
|
|
158
|
+
computed: function(item) {
|
|
159
|
+
return (item.quantity || 0) * (item.unitPrice || 0);
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// 2. Aggregate pre-computed subtotals on order
|
|
166
|
+
const Order = Entity.create({
|
|
167
|
+
name: 'Order',
|
|
168
|
+
properties: [
|
|
169
|
+
// Use pre-computed subtotal instead of recalculating quantity * unitPrice
|
|
170
|
+
Property.create({
|
|
171
|
+
name: 'totalAmount',
|
|
172
|
+
type: 'number',
|
|
173
|
+
defaultValue: () => 0,
|
|
174
|
+
computation: Summation.create({
|
|
175
|
+
record: orderItemRelation,
|
|
176
|
+
attributeQuery: [['target', { attributeQuery: ['subtotal'] }]] // Reference pre-computed result
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
]
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Pattern 2: Avoid Deep Dependency Paths
|
|
184
|
+
|
|
185
|
+
**Principle**: Limit the nesting depth of attributeQuery, especially when crossing multiple x:n relationships.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// ❌ Avoid: Deep dependency paths
|
|
189
|
+
Property.create({
|
|
190
|
+
name: 'badMetric',
|
|
191
|
+
computation: Count.create({
|
|
192
|
+
record: userRelation,
|
|
193
|
+
// Issue: User → Posts → Comments → Likes (3 levels of x:n relationships)
|
|
194
|
+
attributeQuery: [['target', {
|
|
195
|
+
attributeQuery: ['posts', {
|
|
196
|
+
attributeQuery: ['comments', {
|
|
197
|
+
attributeQuery: ['likes']
|
|
198
|
+
}]
|
|
199
|
+
}]
|
|
200
|
+
}]]
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// ✅ Recommended: Layered pre-computation
|
|
205
|
+
// Layer 1: Comment.likeCount
|
|
206
|
+
// Layer 2: Post.commentLikeCount = Summation(Comment.likeCount)
|
|
207
|
+
// Layer 3: User.totalCommentLikes = Summation(Post.commentLikeCount)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Pattern 3: Proper Use of Every/Any Computations
|
|
211
|
+
|
|
212
|
+
**Principle**: When using Every/Any, ensure judgment conditions are based on pre-computed properties of the n-side.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// ✅ Optimized Every computation
|
|
216
|
+
const User = Entity.create({
|
|
217
|
+
name: 'User',
|
|
218
|
+
properties: [
|
|
219
|
+
Property.create({
|
|
220
|
+
name: 'allPostsPopular',
|
|
221
|
+
type: 'boolean',
|
|
222
|
+
defaultValue: () => false,
|
|
223
|
+
computation: Every.create({
|
|
224
|
+
record: userPostRelation,
|
|
225
|
+
// Use Post's pre-computed property
|
|
226
|
+
attributeQuery: [['target', { attributeQuery: ['likeCount'] }]],
|
|
227
|
+
callback: (posts) => {
|
|
228
|
+
return posts.every(post => post.target.likeCount >= 10);
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
]
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Best Practices Summary
|
|
237
|
+
|
|
238
|
+
### Design Principles
|
|
239
|
+
|
|
240
|
+
1. **Compute Locally**: Perform computations where data is generated
|
|
241
|
+
2. **Layered Aggregation**: Use multi-layer pre-computation to avoid deep dependencies
|
|
242
|
+
3. **Incremental-Friendly**: Consider incremental computation feasibility during design
|
|
243
|
+
|
|
244
|
+
### Checklist
|
|
245
|
+
|
|
246
|
+
When designing reactive computations, check the following points:
|
|
247
|
+
|
|
248
|
+
- [ ] **Dependency Path Depth**: Does it exceed 2 levels of x:n relationships?
|
|
249
|
+
- [ ] **N-side Pre-computation**: Do n-side entities have necessary aggregate properties?
|
|
250
|
+
- [ ] **Computation Complexity**: Are callback functions simple enough?
|
|
251
|
+
- [ ] **Incremental Possibility**: Can incremental computation be performed when changes occur?
|
|
252
|
+
|
|
253
|
+
### Refactoring Guidelines
|
|
254
|
+
|
|
255
|
+
Refactor existing performance-problematic code to high-performance versions:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Before refactoring: performance issue
|
|
259
|
+
const problematicComputation = Count.create({
|
|
260
|
+
record: complexRelation,
|
|
261
|
+
attributeQuery: [['deep', { attributeQuery: ['nested', { attributeQuery: ['path'] }] }]]
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// After refactoring: performance optimized
|
|
265
|
+
// 1. Add pre-computed property to intermediate entity
|
|
266
|
+
MiddleEntity.properties.push(
|
|
267
|
+
Property.create({
|
|
268
|
+
name: 'nestedCount',
|
|
269
|
+
computation: Count.create({
|
|
270
|
+
record: simpleRelation,
|
|
271
|
+
attributeQuery: [['target', { attributeQuery: ['path'] }]]
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// 2. Use pre-computed result
|
|
277
|
+
const optimizedComputation = Summation.create({
|
|
278
|
+
record: topLevelRelation,
|
|
279
|
+
attributeQuery: [['target', { attributeQuery: ['nestedCount'] }]]
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
By following these performance optimization principles, you can ensure that interaqt applications maintain high-performance reactive computation capabilities even with large-scale data.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Complete API Exports Reference
|
|
2
|
+
|
|
3
|
+
This document lists all available exports from the 'interaqt' package. Use this as a reference to understand what's available and avoid importing non-existent items.
|
|
4
|
+
|
|
5
|
+
## Core Exports
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import {
|
|
9
|
+
// Entity-related
|
|
10
|
+
Entity,
|
|
11
|
+
Property,
|
|
12
|
+
|
|
13
|
+
// Relation-related
|
|
14
|
+
Relation,
|
|
15
|
+
|
|
16
|
+
// Interaction-related
|
|
17
|
+
Interaction,
|
|
18
|
+
Action,
|
|
19
|
+
Payload,
|
|
20
|
+
PayloadItem,
|
|
21
|
+
|
|
22
|
+
// Activity-related
|
|
23
|
+
Activity,
|
|
24
|
+
|
|
25
|
+
// Computation-related
|
|
26
|
+
Count,
|
|
27
|
+
Every,
|
|
28
|
+
Any,
|
|
29
|
+
Average,
|
|
30
|
+
Sum,
|
|
31
|
+
Summation,
|
|
32
|
+
WeightedSummation,
|
|
33
|
+
Transform,
|
|
34
|
+
StateMachine,
|
|
35
|
+
StateNode,
|
|
36
|
+
StateTransfer,
|
|
37
|
+
RealTime,
|
|
38
|
+
MathResolver,
|
|
39
|
+
|
|
40
|
+
// Attributive and Conditions
|
|
41
|
+
Attributive,
|
|
42
|
+
Attributives,
|
|
43
|
+
Condition,
|
|
44
|
+
Conditions,
|
|
45
|
+
|
|
46
|
+
// Expression and Matching
|
|
47
|
+
BoolExp,
|
|
48
|
+
MatchExp,
|
|
49
|
+
Expression,
|
|
50
|
+
Inequality,
|
|
51
|
+
Equation,
|
|
52
|
+
|
|
53
|
+
// Storage and Query
|
|
54
|
+
Controller,
|
|
55
|
+
MonoSystem,
|
|
56
|
+
|
|
57
|
+
// Dictionary (Global State)
|
|
58
|
+
Dictionary,
|
|
59
|
+
|
|
60
|
+
// Special Entities
|
|
61
|
+
InteractionEventEntity, // NOT InteractionEvent
|
|
62
|
+
|
|
63
|
+
// Database Drivers
|
|
64
|
+
PGLiteDB,
|
|
65
|
+
SQLiteDB,
|
|
66
|
+
PostgreSQLDB,
|
|
67
|
+
MysqlDB,
|
|
68
|
+
|
|
69
|
+
// Class Reference
|
|
70
|
+
KlassByName
|
|
71
|
+
|
|
72
|
+
} from 'interaqt';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## What is NOT Exported
|
|
76
|
+
|
|
77
|
+
The following are commonly mistaken as exports but do NOT exist:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
// ❌ These do NOT exist in interaqt:
|
|
81
|
+
import {
|
|
82
|
+
User, // No pre-built User entity
|
|
83
|
+
RelationBasedEvery, // Only 'Every' exists
|
|
84
|
+
InteractionEvent, // Correct name is 'InteractionEventEntity'
|
|
85
|
+
FilteredEntity, // Created via Entity.create with baseEntity
|
|
86
|
+
SideEffect, // Not a direct export
|
|
87
|
+
DataAttributive // Use Attributive for all purposes
|
|
88
|
+
} from 'interaqt';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Common Import Patterns
|
|
92
|
+
|
|
93
|
+
### Basic Entity Definition
|
|
94
|
+
```javascript
|
|
95
|
+
import { Entity, Property } from 'interaqt';
|
|
96
|
+
|
|
97
|
+
const User = Entity.create({
|
|
98
|
+
name: 'User',
|
|
99
|
+
properties: [
|
|
100
|
+
Property.create({ name: 'name', type: 'string' }),
|
|
101
|
+
Property.create({ name: 'email', type: 'string' })
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Complete CRUD Setup
|
|
107
|
+
```javascript
|
|
108
|
+
import {
|
|
109
|
+
Entity,
|
|
110
|
+
Property,
|
|
111
|
+
Relation,
|
|
112
|
+
Interaction,
|
|
113
|
+
Action,
|
|
114
|
+
Payload,
|
|
115
|
+
PayloadItem,
|
|
116
|
+
Transform,
|
|
117
|
+
InteractionEventEntity
|
|
118
|
+
} from 'interaqt';
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Computation Setup
|
|
122
|
+
```javascript
|
|
123
|
+
import {
|
|
124
|
+
Count,
|
|
125
|
+
Every,
|
|
126
|
+
Any,
|
|
127
|
+
Summation,
|
|
128
|
+
WeightedSummation,
|
|
129
|
+
Transform,
|
|
130
|
+
StateMachine,
|
|
131
|
+
StateNode,
|
|
132
|
+
StateTransfer
|
|
133
|
+
} from 'interaqt';
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Controller Setup
|
|
137
|
+
```javascript
|
|
138
|
+
import {
|
|
139
|
+
Controller,
|
|
140
|
+
MonoSystem,
|
|
141
|
+
PGLiteDB,
|
|
142
|
+
KlassByName
|
|
143
|
+
} from 'interaqt';
|
|
144
|
+
|
|
145
|
+
const system = new MonoSystem(new PGLiteDB());
|
|
146
|
+
system.conceptClass = KlassByName;
|
|
147
|
+
const controller = new Controller({
|
|
148
|
+
|
|
149
|
+
system: system,
|
|
150
|
+
|
|
151
|
+
entities: entities,
|
|
152
|
+
|
|
153
|
+
relations: relations,
|
|
154
|
+
|
|
155
|
+
activities: activities,
|
|
156
|
+
|
|
157
|
+
interactions: interactions,
|
|
158
|
+
|
|
159
|
+
dict: dictionaries,
|
|
160
|
+
|
|
161
|
+
recordMutationSideEffects: []
|
|
162
|
+
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Important Notes
|
|
167
|
+
|
|
168
|
+
1. **No Built-in Entities**: interaqt does not provide any pre-built entities like User, Post, etc. You must define all entities yourself.
|
|
169
|
+
|
|
170
|
+
2. **Entity References in Imports**: When you see `base: User` in examples, User is not imported from interaqt but defined in your application.
|
|
171
|
+
|
|
172
|
+
3. **Special Entity Names**: `InteractionEventEntity` is the only pre-defined entity, used for listening to interaction events.
|
|
173
|
+
|
|
174
|
+
4. **Filtered Entities**: Created using `Entity.create()` with `baseEntity` and `filterCondition`, not a separate import.
|
|
175
|
+
|
|
176
|
+
5. **Database Drivers**: Choose one based on your needs - PGLiteDB for in-memory testing, PostgreSQLDB for production, etc.
|