@powerhousedao/academy 3.3.0-dev.13 → 3.3.0-dev.15
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/CHANGELOG.md +16 -0
- package/docs/academy/02-MasteryTrack/04-WorkWithData/03-UsingSubgraphs.md +145 -86
- package/docs/academy/02-MasteryTrack/04-WorkWithData/07-OperationalDbProcessorTutorial/_category_.json +8 -0
- package/docs/academy/04-APIReferences/01-ReactHooks.md +36 -0
- package/docs/academy/04-APIReferences/04-RelationalDatabase.md +46 -52
- package/docs/academy/04-APIReferences/05-PHDocumentMigrationGuide.md +8 -9
- package/package.json +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/05-AnalyticsProcessorTutorial/05-AnalyticsTutorial +0 -4
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial/01-SetupBuilderEnvironment.md → _05-AnalyticsProcessorTutorial/_01-SetupBuilderEnvironment.md} +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial/02-CreateNewPowerhouseProject.md → _05-AnalyticsProcessorTutorial/_02-CreateNewPowerhouseProject.md} +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial/03-GenerateAnAnalyticsProcessor.md → _05-AnalyticsProcessorTutorial/_03-GenerateAnAnalyticsProcessor.md} +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial/04-UpdateAnalyticsProcessor.md → _05-AnalyticsProcessorTutorial/_04-UpdateAnalyticsProcessor.md} +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/_category_.json +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/Create-SPV.gif +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/Create-a-new-asset.png +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/Create-a-transaction.gif +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/Transaction-table.png +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/create-a-new-RWA-document.gif +0 -0
- /package/docs/academy/02-MasteryTrack/04-WorkWithData/{05-AnalyticsProcessorTutorial → _05-AnalyticsProcessorTutorial}/images/granularity.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 3.3.0-dev.15 (2025-07-17)
|
|
2
|
+
|
|
3
|
+
### 🩹 Fixes
|
|
4
|
+
|
|
5
|
+
- **codegen:** updated subgraph template to deal with undefined return on getDocument ([7b2862a91](https://github.com/powerhouse-inc/powerhouse/commit/7b2862a91))
|
|
6
|
+
- **academy:** update broken links ([cbbfe9b30](https://github.com/powerhouse-inc/powerhouse/commit/cbbfe9b30))
|
|
7
|
+
|
|
8
|
+
### ❤️ Thank You
|
|
9
|
+
|
|
10
|
+
- acaldas
|
|
11
|
+
- Callme-T
|
|
12
|
+
|
|
13
|
+
## 3.3.0-dev.14 (2025-07-17)
|
|
14
|
+
|
|
15
|
+
This was a version bump only for @powerhousedao/academy to align it with other projects, there were no code changes.
|
|
16
|
+
|
|
1
17
|
## 3.3.0-dev.13 (2025-07-17)
|
|
2
18
|
|
|
3
19
|
This was a version bump only for @powerhousedao/academy to align it with other projects, there were no code changes.
|
|
@@ -19,9 +19,9 @@ A subgraph in Powerhouse is a **GraphQL-based modular data component** that exte
|
|
|
19
19
|
|
|
20
20
|
### Subgraphs consist of
|
|
21
21
|
|
|
22
|
-
- **A schema**
|
|
23
|
-
- **Resolvers**
|
|
24
|
-
- **Context Fields**
|
|
22
|
+
- **A schema** — Which defines the GraphQL Queries and Mutations.
|
|
23
|
+
- **Resolvers** — Which handle data fetching and logic.
|
|
24
|
+
- **Context Fields** — Additional metadata that helps in resolving data efficiently.
|
|
25
25
|
|
|
26
26
|
#### Additionally, context fields allow resolvers to access extra information, such as:
|
|
27
27
|
- **User authentication** (e.g., checking if a user is an admin).
|
|
@@ -40,30 +40,30 @@ context: {
|
|
|
40
40
|
|
|
41
41
|
## 1. How to generate a subgraph
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Let's start by generating a new subgraph. For our tutorial we will create a new subgraph within our To-do List project.
|
|
44
44
|
Open your project and start your terminal.
|
|
45
45
|
The Powerhouse toolkit provides a command-line utility to create new subgraphs easily.
|
|
46
46
|
|
|
47
47
|
```bash title="Run the following command to generate a new subgraph"
|
|
48
|
-
ph generate --subgraph
|
|
48
|
+
ph generate --subgraph to-do-list
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
```bash title="Expected Output"
|
|
52
52
|
Loaded templates: node_modules/@powerhousedao/codegen/dist/codegen/.hygen/templates
|
|
53
|
-
FORCED: ./subgraphs/to-do-list
|
|
53
|
+
FORCED: ./subgraphs/to-do-list/index.ts
|
|
54
54
|
skipped: ./subgraphs/index.ts
|
|
55
55
|
inject: ./subgraphs/index.ts
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
### What happened?
|
|
59
|
-
1. A new subgraph was created in `./subgraphs/to-do-list
|
|
59
|
+
1. A new subgraph was created in `./subgraphs/to-do-list/`
|
|
60
60
|
2. The subgraph was automatically registered in your project's registry
|
|
61
61
|
3. Basic boilerplate code was generated with an example query
|
|
62
62
|
|
|
63
63
|
If we now run `ph reactor` we will see the new subgraph being registered during the startup of the Reactor.
|
|
64
64
|
> Registered /todolist subgraph.
|
|
65
65
|
|
|
66
|
-
Alternatively, when you are running a local reactor with `ph reactor
|
|
66
|
+
Alternatively, when you are running a local reactor with `ph reactor`, a series of subgraphs will automatically get registered, among those, one for the available document models in your Powerhouse project.
|
|
67
67
|
|
|
68
68
|
```
|
|
69
69
|
Initializing Subgraph Manager...
|
|
@@ -120,30 +120,77 @@ Now let's create a subgraph that provides enhanced querying capabilities for our
|
|
|
120
120
|
```typescript
|
|
121
121
|
export const typeDefs = `
|
|
122
122
|
type Query {
|
|
123
|
+
# Dashboard-style summary query - returns high-level metrics
|
|
124
|
+
# Similar to ToDoListStats from document model but optimized for quick queries
|
|
123
125
|
todoList: TodoListSummary
|
|
126
|
+
|
|
127
|
+
# Filtered list query - lets you get items by completion status
|
|
128
|
+
# More flexible than the basic document model - can filter checked/unchecked
|
|
124
129
|
todoItems(checked: Boolean): [TodoItem!]!
|
|
130
|
+
|
|
131
|
+
# Count-only query - when you just need numbers, not full data
|
|
132
|
+
# Faster than getting full list when you only need totals for dashboards
|
|
125
133
|
todoItemsCount(checked: Boolean): Int!
|
|
126
134
|
}
|
|
127
135
|
|
|
136
|
+
# This mirrors ToDoListStats from the document model
|
|
137
|
+
# But it's a "view" optimized for summary reports and dashboards
|
|
128
138
|
type TodoListSummary {
|
|
129
|
-
total: Int!
|
|
130
|
-
checked: Int!
|
|
131
|
-
unchecked: Int!
|
|
139
|
+
total: Int! # Total number of items
|
|
140
|
+
checked: Int! # Number of completed items
|
|
141
|
+
unchecked: Int! # Number of pending items
|
|
132
142
|
}
|
|
133
143
|
|
|
144
|
+
# This matches the ToDoItem from the document model
|
|
145
|
+
# Same data structure, but accessed through subgraph queries for filtering
|
|
134
146
|
type TodoItem {
|
|
135
|
-
id: ID!
|
|
136
|
-
text: String!
|
|
137
|
-
checked: Boolean!
|
|
147
|
+
id: ID! # Unique identifier
|
|
148
|
+
text: String! # The task description
|
|
149
|
+
checked: Boolean! # Completion status
|
|
138
150
|
}
|
|
139
151
|
`;
|
|
140
152
|
```
|
|
141
153
|
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
#### Understanding Resolvers
|
|
157
|
+
|
|
158
|
+
Before diving into the technical implementation, let's understand why these three different query types matter for your product.
|
|
159
|
+
Think of resolvers as custom API endpoints that are automatically created based on what your users actually need to know about your data.
|
|
160
|
+
|
|
161
|
+
When someone asks your system a question through GraphQL, the resolver:
|
|
162
|
+
|
|
163
|
+
1. **Understands the request** - "The customer wants unchecked items"
|
|
164
|
+
2. **Knows where to get the data** - "I need to check the todo_items database table"
|
|
165
|
+
3. **Applies the right filters** - "Only get items where checked = false"
|
|
166
|
+
4. **Returns the answer** - "Here are the 5 unchecked items"
|
|
167
|
+
|
|
168
|
+
**The three resolvers serve different business needs:**
|
|
169
|
+
|
|
170
|
+
- **`todoList` Resolver - The Dashboard**
|
|
171
|
+
- **Business value**: Perfect for executive dashboards or KPI displays
|
|
172
|
+
- **Use case**: "We have 150 total tasks, 89 completed, 61 pending"
|
|
173
|
+
- **Users**: Executives, managers, anyone needing high-level metrics
|
|
174
|
+
|
|
175
|
+
- **`todoItems` Resolver - The Detailed List**
|
|
176
|
+
- **Business value**: Great for operational views where people need to see actual tasks
|
|
177
|
+
- **Use case**: "Show me all pending tasks" or "Show me everything"
|
|
178
|
+
- **Users**: Workers, operators, anyone who needs to act on specific items
|
|
179
|
+
|
|
180
|
+
- **`todoItemsCount` Resolver - The Counter**
|
|
181
|
+
- **Business value**: Super fast for analytics or when you only need numbers
|
|
182
|
+
- **Use case**: "How many completed tasks do we have?" → "47"
|
|
183
|
+
- **Users**: Analysts, automated systems, performance dashboards
|
|
184
|
+
|
|
185
|
+
**Why this architecture matters:**
|
|
186
|
+
- **Performance**: Count queries are much faster than getting full lists when you only need numbers
|
|
187
|
+
- **User Experience**: Different resolvers serve different user needs efficiently
|
|
188
|
+
- **Flexibility**: Users can ask for exactly what they need, nothing more, nothing less
|
|
189
|
+
|
|
142
190
|
**Step 2: Create resolvers in `subgraphs/to-do-list/resolvers.ts`:**
|
|
143
191
|
|
|
144
192
|
```typescript
|
|
145
193
|
// subgraphs/to-do-list/resolvers.ts
|
|
146
|
-
// subgraphs/to-do-list/resolvers.ts
|
|
147
194
|
interface SubgraphInstance {
|
|
148
195
|
operationalStore: any;
|
|
149
196
|
}
|
|
@@ -196,35 +243,48 @@ import { typeDefs } from './schema.js';
|
|
|
196
243
|
import { createResolvers } from './resolvers.js';
|
|
197
244
|
|
|
198
245
|
export default class ToDoListSubgraph {
|
|
246
|
+
// Define the API endpoint where this subgraph will be accessible
|
|
247
|
+
// Users can query this at: http://localhost:4001/graphql/to-do-list
|
|
199
248
|
path = '/to-do-list';
|
|
200
249
|
|
|
250
|
+
// GraphQL schema definition (what queries are available)
|
|
201
251
|
typeDefs = typeDefs;
|
|
252
|
+
|
|
253
|
+
// Query handlers (how to fetch the data)
|
|
202
254
|
resolvers: any;
|
|
255
|
+
|
|
256
|
+
// Database interface (injected by Powerhouse framework)
|
|
203
257
|
operationalStore: any;
|
|
204
258
|
|
|
205
259
|
constructor() {
|
|
260
|
+
// Connect the resolvers to this subgraph instance
|
|
261
|
+
// This gives resolvers access to the database through this.operationalStore
|
|
206
262
|
this.resolvers = createResolvers(this);
|
|
207
263
|
}
|
|
208
264
|
|
|
265
|
+
// Called once when the subgraph starts up
|
|
209
266
|
async onSetup() {
|
|
210
267
|
await this.createOperationalTables();
|
|
211
268
|
}
|
|
212
269
|
|
|
270
|
+
// Create the database tables we need for storing todo items
|
|
213
271
|
async createOperationalTables() {
|
|
214
272
|
await this.operationalStore.schema.createTableIfNotExists(
|
|
215
|
-
"todo_items",
|
|
273
|
+
"todo_items", // Table name
|
|
216
274
|
(table: any) => {
|
|
217
|
-
table.string("id").primary();
|
|
218
|
-
table.string("text").notNullable();
|
|
219
|
-
table.boolean("checked").defaultTo(false);
|
|
220
|
-
table.timestamp("created_at").defaultTo(this.operationalStore.fn.now());
|
|
221
|
-
table.timestamp("updated_at").defaultTo(this.operationalStore.fn.now());
|
|
275
|
+
table.string("id").primary(); // Unique identifier for each todo item
|
|
276
|
+
table.string("text").notNullable(); // The actual todo task text
|
|
277
|
+
table.boolean("checked").defaultTo(false); // Completion status (unchecked by default)
|
|
278
|
+
table.timestamp("created_at").defaultTo(this.operationalStore.fn.now()); // When item was created
|
|
279
|
+
table.timestamp("updated_at").defaultTo(this.operationalStore.fn.now()); // When item was last modified
|
|
222
280
|
}
|
|
223
281
|
);
|
|
224
282
|
}
|
|
225
283
|
|
|
284
|
+
// Event processor: Keeps subgraph data synchronized with document model changes
|
|
285
|
+
// When users add/update/delete todos in Connect, this method handles the updates
|
|
226
286
|
async process(event: any) {
|
|
227
|
-
// Handle
|
|
287
|
+
// Handle new todo item creation
|
|
228
288
|
if (event.type === "ADD_TODO_ITEM") {
|
|
229
289
|
await this.operationalStore.insert("todo_items", {
|
|
230
290
|
id: event.input.id,
|
|
@@ -237,12 +297,13 @@ export default class ToDoListSubgraph {
|
|
|
237
297
|
console.log(`Added todo item: ${event.input.text}`);
|
|
238
298
|
}
|
|
239
299
|
|
|
300
|
+
// Handle todo item updates (text changes, checking/unchecking)
|
|
240
301
|
if (event.type === "UPDATE_TODO_ITEM") {
|
|
241
302
|
const updateData: any = {
|
|
242
|
-
updated_at: new Date()
|
|
303
|
+
updated_at: new Date() // Always update the timestamp
|
|
243
304
|
};
|
|
244
305
|
|
|
245
|
-
// Only update fields that were
|
|
306
|
+
// Only update fields that were actually changed
|
|
246
307
|
if (event.input.text !== undefined) {
|
|
247
308
|
updateData.text = event.input.text;
|
|
248
309
|
}
|
|
@@ -257,6 +318,7 @@ export default class ToDoListSubgraph {
|
|
|
257
318
|
console.log(`Updated todo item: ${event.input.id}`);
|
|
258
319
|
}
|
|
259
320
|
|
|
321
|
+
// Handle todo item deletion
|
|
260
322
|
if (event.type === "DELETE_TODO_ITEM") {
|
|
261
323
|
await this.operationalStore.delete("todo_items")
|
|
262
324
|
.where("id", event.input.id);
|
|
@@ -267,11 +329,6 @@ export default class ToDoListSubgraph {
|
|
|
267
329
|
}
|
|
268
330
|
```
|
|
269
331
|
|
|
270
|
-
**What this schema provides:**
|
|
271
|
-
- `todoList`: Returns statistics about all to-do items (total, checked, unchecked counts)
|
|
272
|
-
- `todoItems`: Returns a list of to-do items, optionally filtered by checked status
|
|
273
|
-
- `todoItemsCount`: Returns just the count of items, optionally filtered by checked status
|
|
274
|
-
|
|
275
332
|
### 2.3 Understanding the Implementation
|
|
276
333
|
|
|
277
334
|
**What this multi-file approach provides:**
|
|
@@ -287,70 +344,72 @@ export default class ToDoListSubgraph {
|
|
|
287
344
|
- Resolvers that fetch and filter todo items from the operational store
|
|
288
345
|
- Event processing to keep the subgraph data synchronized with document model changes
|
|
289
346
|
|
|
290
|
-
### 2.4
|
|
347
|
+
### 2.4 Understanding the Document Model Event Integration
|
|
291
348
|
|
|
292
|
-
|
|
349
|
+
Notice that our `index.ts` file already includes a `process` method - this is the **processor integration** that keeps our subgraph synchronized with To-do List document model events. When users interact with To-do List documents through Connect, this method automatically handles the updates.
|
|
293
350
|
|
|
294
|
-
|
|
351
|
+
**How the existing processor integration works:**
|
|
295
352
|
|
|
353
|
+
The `process` method in our `index.ts` file handles three types of document model events:
|
|
354
|
+
|
|
355
|
+
**1. Adding new todo items:**
|
|
296
356
|
```typescript
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
// Only update fields that were provided
|
|
317
|
-
if (event.input.text !== undefined) {
|
|
318
|
-
updateData.text = event.input.text;
|
|
319
|
-
}
|
|
320
|
-
if (event.input.checked !== undefined) {
|
|
321
|
-
updateData.checked = event.input.checked;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
await this.operationalStore.update("todo_items")
|
|
325
|
-
.where("id", event.input.id)
|
|
326
|
-
.update(updateData);
|
|
327
|
-
|
|
328
|
-
console.log(`Updated todo item: ${event.input.id}`);
|
|
329
|
-
}
|
|
357
|
+
if (event.type === "ADD_TODO_ITEM") {
|
|
358
|
+
await this.operationalStore.insert("todo_items", {
|
|
359
|
+
id: event.input.id,
|
|
360
|
+
text: event.input.text,
|
|
361
|
+
checked: false,
|
|
362
|
+
created_at: new Date(),
|
|
363
|
+
updated_at: new Date()
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**2. Updating existing items:**
|
|
369
|
+
```typescript
|
|
370
|
+
if (event.type === "UPDATE_TODO_ITEM") {
|
|
371
|
+
// Only update fields that were actually changed
|
|
372
|
+
const updateData = { updated_at: new Date() };
|
|
373
|
+
if (event.input.text !== undefined) updateData.text = event.input.text;
|
|
374
|
+
if (event.input.checked !== undefined) updateData.checked = event.input.checked;
|
|
330
375
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
376
|
+
await this.operationalStore.update("todo_items")
|
|
377
|
+
.where("id", event.input.id)
|
|
378
|
+
.update(updateData);
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**3. Deleting items:**
|
|
383
|
+
```typescript
|
|
384
|
+
if (event.type === "DELETE_TODO_ITEM") {
|
|
385
|
+
await this.operationalStore.delete("todo_items")
|
|
386
|
+
.where("id", event.input.id);
|
|
337
387
|
}
|
|
338
388
|
```
|
|
339
389
|
|
|
340
|
-
**
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
390
|
+
**The integration happens automatically:**
|
|
391
|
+
1. **User action**: Someone adds a todo item in Connect
|
|
392
|
+
2. **Document model**: Processes the `ADD_TODO_ITEM` operation
|
|
393
|
+
3. **Framework routing**: Powerhouse automatically calls your subgraph's `process` method
|
|
394
|
+
4. **Subgraph response**: Your `process` method updates the operational store
|
|
395
|
+
5. **Query availability**: Users can now query the updated data via GraphQL
|
|
345
396
|
|
|
346
397
|
### 2.5 Summary of What We've Built
|
|
347
398
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
- **
|
|
351
|
-
- **
|
|
352
|
-
- **
|
|
353
|
-
- **
|
|
399
|
+
Our complete To-do List subgraph includes:
|
|
400
|
+
|
|
401
|
+
- **GraphQL schema** (`schema.ts`): Defines `todoList`, `todoItems`, and `todoItemsCount` queries
|
|
402
|
+
- **Resolvers** (`resolvers.ts`): Handle data fetching and filtering from the operational store
|
|
403
|
+
- **Main subgraph class** (`index.ts`): Coordinates everything and includes:
|
|
404
|
+
- **Operational table creation**: Sets up the `todo_items` table with proper schema
|
|
405
|
+
- **Event processing**: The `process` method keeps subgraph data synchronized with document model changes
|
|
406
|
+
- **Real-time updates**: Automatically handles `ADD_TODO_ITEM`, `UPDATE_TODO_ITEM`, and `DELETE_TODO_ITEM` events
|
|
407
|
+
|
|
408
|
+
**Key features:**
|
|
409
|
+
- **Filtering capability**: The `todoItems` query accepts an optional `checked` parameter
|
|
410
|
+
- **Performance optimization**: The `todoItemsCount` query returns just numbers when you don't need full data
|
|
411
|
+
- **Real-time synchronization**: Changes in Connect immediately appear in subgraph queries
|
|
412
|
+
- **Complete statistics**: The `todoList` query returns total, checked, and unchecked counts
|
|
354
413
|
|
|
355
414
|
## 3. Testing the To-do List Subgraph
|
|
356
415
|
|
|
@@ -485,7 +544,7 @@ This demonstrates the real-time synchronization between the document model and t
|
|
|
485
544
|
|
|
486
545
|
## 4. Working with the supergraph or gateway
|
|
487
546
|
|
|
488
|
-
A supergraph is a GraphQL schema that combines multiple underlying GraphQL APIs, known as subgraphs, into a single, unified graph. This architecture allows different teams to work independently on their respective services (subgraphs) while providing a single entry point for clients or users to query all available data
|
|
547
|
+
A supergraph is a GraphQL schema that combines multiple underlying GraphQL APIs, known as subgraphs, into a single, unified graph. This architecture allows different teams to work independently on their respective services (subgraphs) while providing a single entry point for clients or users to query all available data.
|
|
489
548
|
|
|
490
549
|
### 4.1 Key concepts
|
|
491
550
|
|
|
@@ -503,7 +562,7 @@ A supergraph is a GraphQL schema that combines multiple underlying GraphQL APIs,
|
|
|
503
562
|
|
|
504
563
|
### 4.3 Use the Powerhouse supergraph
|
|
505
564
|
|
|
506
|
-
The Powerhouse supergraph for any given remote drive or reactor can be found under `http://localhost:4001/graphql`. The gateway / supergraph available on `/graphql` combines all the subgraphs, except for the drive subgraph (which is accessible via `/d/:driveId`). To
|
|
565
|
+
The Powerhouse supergraph for any given remote drive or reactor can be found under `http://localhost:4001/graphql`. The gateway / supergraph available on `/graphql` combines all the subgraphs, except for the drive subgraph (which is accessible via `/d/:driveId`). To access the endpoint, start the reactor and navigate to the URL with `graphql` appended. The following commands explain how you can test & try the supergraph.
|
|
507
566
|
|
|
508
567
|
- Start the reactor:
|
|
509
568
|
|
|
@@ -517,7 +576,7 @@ The Powerhouse supergraph for any given remote drive or reactor can be found und
|
|
|
517
576
|
http://localhost:4001/graphql
|
|
518
577
|
```
|
|
519
578
|
|
|
520
|
-
The supergraph allows to both query & mutate data from the same endpoint.
|
|
579
|
+
The supergraph allows you to both query & mutate data from the same endpoint.
|
|
521
580
|
|
|
522
581
|
**Example: Using the supergraph with To-do List documents**
|
|
523
582
|
|
|
@@ -639,7 +698,7 @@ To integrate with them, register them via the Reactor API.
|
|
|
639
698
|
|
|
640
699
|
### Future enhancements
|
|
641
700
|
|
|
642
|
-
Bridge Processors and Subgraphs
|
|
701
|
+
Bridge Processors and Subgraphs — Currently, there's a gap in how processors and subgraphs interact. Powerhouse might improve this in future updates.
|
|
643
702
|
|
|
644
703
|
|
|
645
704
|
|
|
@@ -50,6 +50,42 @@ const updateInvoiceName = useUpdateDocumentField('docId', 'name')
|
|
|
50
50
|
// Combined read + write (like useState)
|
|
51
51
|
const [invoiceName, updateInvoiceName] = useDocumentField('docId', 'name')
|
|
52
52
|
```
|
|
53
|
+
Initial documentation about the hooks can be found [here](https://github.com/powerhouse-inc/powerhouse/blob/main/packages/common/state/README.md)
|
|
54
|
+
|
|
55
|
+
### Temporary use of new hooks on custom drive editors.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
To use the new hooks in custom components or editors today, devs must:
|
|
59
|
+
|
|
60
|
+
1. Pass in the existing Reactor instance as a prop (createReactor).
|
|
61
|
+
2. Call useInitializeReactor(props.createReactor, false) in the custom component.
|
|
62
|
+
3. Optionally wrap dispatch() to trigger a refresh manually, using:
|
|
63
|
+
|
|
64
|
+
const refresh = useSyncDrivesAndDocumentsWithReactor();
|
|
65
|
+
|
|
66
|
+
For maximum compatibility, consider passing data and set functions (drives, documents, etc.) directly as props instead of using the hooks inside the custom editor..
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
+import { AtomStoreProvider } from "@powerhousedao/common";
|
|
72
|
+
|
|
73
|
+
export default function Editor(props: IProps) {
|
|
74
|
+
return (
|
|
75
|
+
+ <AtomStoreProvider reactor={props.context.reactor}>
|
|
76
|
+
<DriveContextProvider value={props.context}>
|
|
77
|
+
<WagmiContext>
|
|
78
|
+
<BaseEditor {...props} />
|
|
79
|
+
</WagmiContext>
|
|
80
|
+
</DriveContextProvider>
|
|
81
|
+
+ </AtomStoreProvider>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Until the hooks are fully integrated and event handling is granular, the team will need to handle some of this manually or limit their use to experimental side projects and internal demos.
|
|
87
|
+
|
|
88
|
+
|
|
53
89
|
|
|
54
90
|
|
|
55
91
|
## An overview of currently available hooks
|
|
@@ -7,11 +7,11 @@ This page covers the relational database tools available in Powerhouse applicati
|
|
|
7
7
|
The relational database layer gives you powerful tools to work with data in your Powerhouse applications. You get type-safe queries, real-time updates, and a simple API that feels familiar to React developers.
|
|
8
8
|
|
|
9
9
|
**Key Benefits:**
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
10
|
+
- **Type-safe queries** with full TypeScript support
|
|
11
|
+
- **Live query capabilities** with real-time updates
|
|
12
|
+
- **Automatic optimization** to prevent infinite re-renders
|
|
13
|
+
- **Simple API** that abstracts away complexity
|
|
14
|
+
- **Smart memorization** for parameters and queries
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
@@ -40,23 +40,26 @@ type MyDatabase = {
|
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
import { createProcessorQuery } from '@powerhousedao/reactor-browser/relational';
|
|
43
|
+
import { MyProcessor } from './processors/my-processor';
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
// Create a typed query hook for your processor
|
|
46
|
+
const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
### Step 3: Use it in your component
|
|
48
50
|
|
|
49
51
|
```typescript
|
|
50
52
|
// Simple query - no parameters needed
|
|
51
|
-
export function useUserList() {
|
|
52
|
-
return useTypedQuery(db => {
|
|
53
|
+
export function useUserList(driveId: string) {
|
|
54
|
+
return useTypedQuery(driveId, db => {
|
|
53
55
|
return db.selectFrom('users').selectAll().compile();
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
// Query with parameters
|
|
58
|
-
export function useUserById(userId: number) {
|
|
60
|
+
export function useUserById(driveId: string, userId: number) {
|
|
59
61
|
return useTypedQuery(
|
|
62
|
+
driveId,
|
|
60
63
|
(db, params) => {
|
|
61
64
|
return db
|
|
62
65
|
.selectFrom('users')
|
|
@@ -72,8 +75,8 @@ export function useUserById(userId: number) {
|
|
|
72
75
|
### Step 4: Use in your React component
|
|
73
76
|
|
|
74
77
|
```typescript
|
|
75
|
-
function UserList() {
|
|
76
|
-
const { isLoading, error, result } = useUserList();
|
|
78
|
+
function UserList({ driveId }: { driveId: string }) {
|
|
79
|
+
const { isLoading, error, result } = useUserList(driveId);
|
|
77
80
|
|
|
78
81
|
if (isLoading) return <div>Loading...</div>;
|
|
79
82
|
if (error) return <div>Error: {error.message}</div>;
|
|
@@ -98,40 +101,40 @@ function UserList() {
|
|
|
98
101
|
### 1. createProcessorQuery()
|
|
99
102
|
|
|
100
103
|
<details>
|
|
101
|
-
<summary>`createProcessorQuery
|
|
104
|
+
<summary>`createProcessorQuery(ProcessorClass)`: Creates a typed query hook factory for your processor</summary>
|
|
102
105
|
|
|
103
|
-
###
|
|
106
|
+
### Function Name and Signature
|
|
104
107
|
|
|
105
108
|
```typescript
|
|
106
|
-
function createProcessorQuery<Schema>(
|
|
109
|
+
function createProcessorQuery<Schema>(
|
|
110
|
+
ProcessorClass: RelationalDbProcessorClass<Schema>
|
|
111
|
+
): TypedQueryHook<Schema>
|
|
107
112
|
```
|
|
108
113
|
|
|
109
114
|
### Description
|
|
110
115
|
|
|
111
|
-
Creates a typed query hook
|
|
116
|
+
Creates a typed query hook factory for a specific processor class. This is the main function you'll use to create hooks for querying your relational database.
|
|
112
117
|
|
|
113
118
|
### Usage Example
|
|
114
119
|
|
|
115
120
|
```typescript
|
|
116
121
|
import { createProcessorQuery } from '@powerhousedao/reactor-browser/relational';
|
|
122
|
+
import { MyProcessor } from './processors/my-processor';
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
posts: { id: number; title: string; author_id: number };
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const useTypedQuery = createProcessorQuery<AppDatabase>();
|
|
124
|
+
// Create a typed query hook for your processor
|
|
125
|
+
const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
124
126
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
return useTypedQuery(db => {
|
|
127
|
+
// Use it to create specific query hooks
|
|
128
|
+
export const useUsers = (driveId: string) => {
|
|
129
|
+
return useTypedQuery(driveId, (db) => {
|
|
128
130
|
return db.selectFrom('users').selectAll().compile();
|
|
129
131
|
});
|
|
130
|
-
}
|
|
132
|
+
};
|
|
131
133
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
+
// With parameters
|
|
135
|
+
export const useUsersByStatus = (driveId: string, status: string) => {
|
|
134
136
|
return useTypedQuery(
|
|
137
|
+
driveId,
|
|
135
138
|
(db, params) => {
|
|
136
139
|
return db
|
|
137
140
|
.selectFrom('users')
|
|
@@ -141,41 +144,32 @@ function useUsersByStatus(status: string) {
|
|
|
141
144
|
},
|
|
142
145
|
{ status }
|
|
143
146
|
);
|
|
144
|
-
}
|
|
147
|
+
};
|
|
145
148
|
```
|
|
146
149
|
|
|
147
150
|
### Parameters
|
|
148
151
|
|
|
149
|
-
The returned hook
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- `
|
|
153
|
-
|
|
154
|
-
**Parameterized queries:**
|
|
155
|
-
- `queryCallback: (db: EnhancedKysely<Schema>, parameters: TParams) => QueryCallbackReturnType` - Function that receives the database instance and parameters
|
|
156
|
-
- `parameters: TParams` - Parameters for the query (automatically memoized)
|
|
152
|
+
The returned hook accepts:
|
|
153
|
+
- `driveId`: The ID of the drive
|
|
154
|
+
- `queryCallback`: Function that receives the database instance and optional parameters
|
|
155
|
+
- `parameters`: Optional parameters for the query
|
|
157
156
|
|
|
158
157
|
### Return Value
|
|
159
158
|
|
|
160
159
|
```typescript
|
|
161
160
|
{
|
|
162
|
-
isLoading: boolean;
|
|
163
|
-
error: Error | null;
|
|
164
|
-
result: LiveQueryResults<T> | null;
|
|
161
|
+
isLoading: boolean; // True while loading or retrying
|
|
162
|
+
error: Error | null; // Any error that occurred
|
|
163
|
+
result: LiveQueryResults<T> | null; // Query results with live updates
|
|
165
164
|
}
|
|
166
165
|
```
|
|
167
166
|
|
|
168
167
|
### Notes / Caveats
|
|
169
168
|
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
|
|
175
|
-
### Related Hooks
|
|
176
|
-
|
|
177
|
-
- [`useOperationalStore`](#useoperationalstore) - For direct database access
|
|
178
|
-
- [`useOperationalQuery`](#useoperationalquery) - Lower-level query hook
|
|
169
|
+
- Create one `useTypedQuery` hook per processor
|
|
170
|
+
- The hook includes automatic retry logic for common errors
|
|
171
|
+
- Parameters are automatically memoized
|
|
172
|
+
- Queries are live and will update automatically when data changes
|
|
179
173
|
|
|
180
174
|
</details>
|
|
181
175
|
|
|
@@ -246,8 +240,8 @@ function DatabaseOperations() {
|
|
|
246
240
|
|
|
247
241
|
### Related Hooks
|
|
248
242
|
|
|
249
|
-
- [`createProcessorQuery`](#
|
|
250
|
-
- [`useOperationalQuery`](#useoperationalquery) - For manual query control
|
|
243
|
+
- [`createProcessorQuery`](#1-createprocessorquery) - For optimized queries
|
|
244
|
+
- [`useOperationalQuery`](#3-useoperationalquery) - For manual query control
|
|
251
245
|
|
|
252
246
|
</details>
|
|
253
247
|
|
|
@@ -314,8 +308,8 @@ function UserCount() {
|
|
|
314
308
|
|
|
315
309
|
### Related Hooks
|
|
316
310
|
|
|
317
|
-
- [`createProcessorQuery`](#
|
|
318
|
-
- [`useOperationalStore`](#useoperationalstore) - For direct database access
|
|
311
|
+
- [`createProcessorQuery`](#1-createprocessorquery) - Recommended higher-level API
|
|
312
|
+
- [`useOperationalStore`](#2-useoperationalstore) - For direct database access
|
|
319
313
|
|
|
320
314
|
</details>
|
|
321
315
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# PHDocument Migration Guide
|
|
1
|
+
# PHDocument Migration Guide
|
|
2
2
|
|
|
3
3
|
:::tip
|
|
4
|
-
This guide covers the **breaking changes** introduced in Powerhouse
|
|
4
|
+
This guide covers the **breaking changes** introduced in Powerhouse v4.0.0 related to PHDocument structure changes. If you're upgrading from v3.2.0 or earlier, **this migration is required** and document models must be regenerated.
|
|
5
5
|
:::
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
Version
|
|
9
|
+
Version 4.0.0 introduced a significant refactor of the `PHDocument` structure that consolidates document metadata into a `header` field. This change enables signed and unsigned documents with cryptographic verification capabilities, but requires updating all code that accesses document properties.
|
|
10
10
|
|
|
11
11
|
## What Changed
|
|
12
12
|
|
|
@@ -28,7 +28,7 @@ const document = {
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
**After (
|
|
31
|
+
**After (v4.0.0):**
|
|
32
32
|
```javascript
|
|
33
33
|
const document = {
|
|
34
34
|
header: {
|
|
@@ -328,11 +328,10 @@ describe('Document Migration', () => {
|
|
|
328
328
|
|
|
329
329
|
## Related Documentation
|
|
330
330
|
|
|
331
|
-
- [PHDocument Architecture](
|
|
332
|
-
- [Document Model Creation](
|
|
333
|
-
- [
|
|
334
|
-
- [React Hooks](./01-ReactHooks.md)
|
|
331
|
+
- [PHDocument Architecture](/academy/Architecture/PowerhouseArchitecture)
|
|
332
|
+
- [Document Model Creation](/academy/MasteryTrack/DocumentModelCreation/WhatIsADocumentModel)
|
|
333
|
+
- [React Hooks](/academy/APIReferences/ReactHooks)
|
|
335
334
|
|
|
336
335
|
---
|
|
337
336
|
|
|
338
|
-
*This migration guide covers the major changes in
|
|
337
|
+
*This migration guide covers the major changes in v4.0.0. For additional technical details, refer to the [RELEASE-NOTES.md](https://github.com/powerhouse-dao/powerhouse/blob/main/RELEASE-NOTES.md) in the main repository.*
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|