@powerhousedao/academy 5.0.0-staging.2 → 5.0.0-staging.20
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/.vscode/settings.json +1 -1
- package/CHANGELOG.md +115 -0
- package/README.md +3 -3
- package/babel.config.js +1 -1
- package/blog/BeyondCommunication-ABlueprintForDevelopment.md +25 -24
- package/blog/TheChallengeOfChange.md +21 -21
- package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +61 -24
- package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +21 -12
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +24 -19
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +44 -41
- package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +10 -10
- package/docs/academy/01-GetStarted/05-SpecDrivenAI.md +143 -0
- package/docs/academy/01-GetStarted/home.mdx +185 -90
- package/docs/academy/01-GetStarted/styles.module.css +5 -5
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/01-Prerequisites.md +46 -18
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/02-StandardDocumentModelWorkflow.md +118 -68
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +75 -33
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/01-WhatIsADocumentModel.md +30 -21
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +41 -37
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +29 -25
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +36 -37
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +128 -109
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +95 -86
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +7 -9
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +65 -47
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +77 -62
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/03-BuildingADriveExplorer.md +360 -349
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +16 -10
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +10 -7
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/02-RevisionHistoryTimeline.md +26 -11
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/01-RenownAuthenticationFlow.md +14 -7
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/02-Authorization.md +0 -1
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/_category_.json +5 -5
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/_category_.json +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/01-GraphQLAtPowerhouse.md +45 -33
- package/docs/academy/02-MasteryTrack/04-WorkWithData/02-UsingTheAPI.mdx +61 -18
- package/docs/academy/02-MasteryTrack/04-WorkWithData/03-UsingSubgraphs.md +50 -54
- package/docs/academy/02-MasteryTrack/04-WorkWithData/04-analytics-processor.md +126 -110
- package/docs/academy/02-MasteryTrack/04-WorkWithData/05-RelationalDbProcessor.md +75 -45
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/GraphQL References/QueryingADocumentWithGraphQL.md +23 -21
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/best-practices.md +9 -9
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/index.md +11 -23
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/integration.md +25 -9
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/intro.md +10 -10
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/benchmarks.md +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/index.md +16 -11
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/memory.md +6 -5
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/schema.md +2 -2
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/utilities.md +7 -5
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/maker.md +32 -58
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/processors.md +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/07-drive-analytics.md +105 -71
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_01-SetupBuilderEnvironment.md +22 -0
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_02-CreateNewPowerhouseProject.md +9 -8
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_03-GenerateAnAnalyticsProcessor.md +28 -32
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_04-UpdateAnalyticsProcessor.md +25 -26
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_category_.json +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_category_.json +7 -7
- package/docs/academy/02-MasteryTrack/05-Launch/01-IntroductionToPackages.md +3 -4
- package/docs/academy/02-MasteryTrack/05-Launch/02-PublishYourProject.md +69 -45
- package/docs/academy/02-MasteryTrack/05-Launch/03-SetupEnvironment.md +70 -40
- package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -0
- package/docs/academy/02-MasteryTrack/05-Launch/_category_.json +7 -7
- package/docs/academy/02-MasteryTrack/_category_.json +6 -6
- package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +5 -3
- package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +38 -37
- package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +45 -41
- package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +14 -14
- package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +6 -6
- package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
- package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +14 -7
- package/docs/academy/04-APIReferences/01-ReactHooks.md +177 -129
- package/docs/academy/04-APIReferences/04-RelationalDatabase.md +121 -113
- package/docs/academy/04-APIReferences/05-PHDocumentMigrationGuide.md +48 -41
- package/docs/academy/04-APIReferences/_category_.json +6 -6
- package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +1 -2
- package/docs/academy/05-Architecture/01-WorkingWithTheReactor.md +11 -8
- package/docs/academy/05-Architecture/05-DocumentModelTheory/_category_.json +1 -1
- package/docs/academy/05-Architecture/_category_.json +6 -6
- package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +25 -23
- package/docs/academy/06-ComponentLibrary/02-CreateCustomScalars.md +105 -93
- package/docs/academy/06-ComponentLibrary/03-IntegrateIntoAReactComponent.md +1 -0
- package/docs/academy/06-ComponentLibrary/_category_.json +7 -7
- package/docs/academy/07-Cookbook.md +267 -34
- package/docs/academy/08-Glossary.md +7 -1
- package/docs/bookofpowerhouse/01-Overview.md +2 -2
- package/docs/bookofpowerhouse/02-GeneralFrameworkAndPhilosophy.md +1 -7
- package/docs/bookofpowerhouse/03-PowerhouseSoftwareArchitecture.md +10 -7
- package/docs/bookofpowerhouse/04-DevelopmentApproaches.md +10 -4
- package/docs/bookofpowerhouse/05-SNOsandANewModelForOSSandPublicGoods.md +23 -30
- package/docs/bookofpowerhouse/06-SNOsInActionAndPlatformEconomies.md +0 -7
- package/docusaurus.config.ts +64 -66
- package/package.json +1 -1
- package/scripts/generate-combined-cli-docs.ts +43 -13
- package/sidebars.ts +1 -0
- package/src/components/HomepageFeatures/index.tsx +171 -78
- package/src/components/HomepageFeatures/styles.module.css +1 -2
- package/src/css/custom.css +89 -89
- package/src/pages/_archive-homepage.tsx +17 -16
- package/src/theme/DocCardList/index.tsx +9 -8
- package/static.json +6 -6
|
@@ -7,8 +7,9 @@ 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
|
+
|
|
10
11
|
- **Type-safe queries** with full TypeScript support
|
|
11
|
-
- **Live query capabilities** with real-time updates
|
|
12
|
+
- **Live query capabilities** with real-time updates
|
|
12
13
|
- **Automatic optimization** to prevent infinite re-renders
|
|
13
14
|
- **Simple API** that abstracts away complexity
|
|
14
15
|
- **Smart memorization** for parameters and queries
|
|
@@ -39,8 +40,8 @@ type MyDatabase = {
|
|
|
39
40
|
### Step 2: Create a typed query hook
|
|
40
41
|
|
|
41
42
|
```typescript
|
|
42
|
-
import { createProcessorQuery } from
|
|
43
|
-
import { MyProcessor } from
|
|
43
|
+
import { createProcessorQuery } from "@powerhousedao/reactor-browser/relational";
|
|
44
|
+
import { MyProcessor } from "./processors/my-processor";
|
|
44
45
|
|
|
45
46
|
// Create a typed query hook for your processor
|
|
46
47
|
const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
@@ -51,8 +52,8 @@ const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
|
51
52
|
```typescript
|
|
52
53
|
// Simple query - no parameters needed
|
|
53
54
|
export function useUserList(driveId: string) {
|
|
54
|
-
return useTypedQuery(driveId, db => {
|
|
55
|
-
return db.selectFrom(
|
|
55
|
+
return useTypedQuery(driveId, (db) => {
|
|
56
|
+
return db.selectFrom("users").selectAll().compile();
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -62,12 +63,12 @@ export function useUserById(driveId: string, userId: number) {
|
|
|
62
63
|
driveId,
|
|
63
64
|
(db, params) => {
|
|
64
65
|
return db
|
|
65
|
-
.selectFrom(
|
|
66
|
+
.selectFrom("users")
|
|
66
67
|
.selectAll()
|
|
67
|
-
.where(
|
|
68
|
+
.where("id", "=", params.userId)
|
|
68
69
|
.compile();
|
|
69
70
|
},
|
|
70
|
-
{ userId }
|
|
71
|
+
{ userId },
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
```
|
|
@@ -107,8 +108,8 @@ function UserList({ driveId }: { driveId: string }) {
|
|
|
107
108
|
|
|
108
109
|
```typescript
|
|
109
110
|
function createProcessorQuery<Schema>(
|
|
110
|
-
ProcessorClass: RelationalDbProcessorClass<Schema
|
|
111
|
-
): TypedQueryHook<Schema
|
|
111
|
+
ProcessorClass: RelationalDbProcessorClass<Schema>,
|
|
112
|
+
): TypedQueryHook<Schema>;
|
|
112
113
|
```
|
|
113
114
|
|
|
114
115
|
### Description
|
|
@@ -118,8 +119,8 @@ Creates a typed query hook factory for a specific processor class. This is the m
|
|
|
118
119
|
### Usage Example
|
|
119
120
|
|
|
120
121
|
```typescript
|
|
121
|
-
import { createProcessorQuery } from
|
|
122
|
-
import { MyProcessor } from
|
|
122
|
+
import { createProcessorQuery } from "@powerhousedao/reactor-browser/relational";
|
|
123
|
+
import { MyProcessor } from "./processors/my-processor";
|
|
123
124
|
|
|
124
125
|
// Create a typed query hook for your processor
|
|
125
126
|
const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
@@ -127,7 +128,7 @@ const useTypedQuery = createProcessorQuery(MyProcessor);
|
|
|
127
128
|
// Use it to create specific query hooks
|
|
128
129
|
export const useUsers = (driveId: string) => {
|
|
129
130
|
return useTypedQuery(driveId, (db) => {
|
|
130
|
-
return db.selectFrom(
|
|
131
|
+
return db.selectFrom("users").selectAll().compile();
|
|
131
132
|
});
|
|
132
133
|
};
|
|
133
134
|
|
|
@@ -137,12 +138,12 @@ export const useUsersByStatus = (driveId: string, status: string) => {
|
|
|
137
138
|
driveId,
|
|
138
139
|
(db, params) => {
|
|
139
140
|
return db
|
|
140
|
-
.selectFrom(
|
|
141
|
+
.selectFrom("users")
|
|
141
142
|
.selectAll()
|
|
142
|
-
.where(
|
|
143
|
+
.where("status", "=", params.status)
|
|
143
144
|
.compile();
|
|
144
145
|
},
|
|
145
|
-
{ status }
|
|
146
|
+
{ status },
|
|
146
147
|
);
|
|
147
148
|
};
|
|
148
149
|
```
|
|
@@ -150,6 +151,7 @@ export const useUsersByStatus = (driveId: string, status: string) => {
|
|
|
150
151
|
### Parameters
|
|
151
152
|
|
|
152
153
|
The returned hook accepts:
|
|
154
|
+
|
|
153
155
|
- `driveId`: The ID of the drive
|
|
154
156
|
- `queryCallback`: Function that receives the database instance and optional parameters
|
|
155
157
|
- `parameters`: Optional parameters for the query
|
|
@@ -158,9 +160,9 @@ The returned hook accepts:
|
|
|
158
160
|
|
|
159
161
|
```typescript
|
|
160
162
|
{
|
|
161
|
-
isLoading: boolean;
|
|
162
|
-
error: Error | null;
|
|
163
|
-
result: LiveQueryResults<T> | null;
|
|
163
|
+
isLoading: boolean; // True while loading or retrying
|
|
164
|
+
error: Error | null; // Any error that occurred
|
|
165
|
+
result: LiveQueryResults<T> | null; // Query results with live updates
|
|
164
166
|
}
|
|
165
167
|
```
|
|
166
168
|
|
|
@@ -181,7 +183,7 @@ The returned hook accepts:
|
|
|
181
183
|
### Hook Name and Signature
|
|
182
184
|
|
|
183
185
|
```typescript
|
|
184
|
-
function useRelationalDb<Schema>(): IRelationalDb<Schema
|
|
186
|
+
function useRelationalDb<Schema>(): IRelationalDb<Schema>;
|
|
185
187
|
```
|
|
186
188
|
|
|
187
189
|
### Description
|
|
@@ -195,20 +197,20 @@ import { useRelationalDb } from '@powerhousedao/reactor-browser/relational';
|
|
|
195
197
|
|
|
196
198
|
function DatabaseOperations() {
|
|
197
199
|
const { db, isLoading, error } = useRelationalDb<MyDatabase>();
|
|
198
|
-
|
|
200
|
+
|
|
199
201
|
const createUser = async (name: string, email: string) => {
|
|
200
202
|
if (!db) return;
|
|
201
|
-
|
|
203
|
+
|
|
202
204
|
// Direct database operations
|
|
203
205
|
await db
|
|
204
206
|
.insertInto('users')
|
|
205
207
|
.values({ name, email })
|
|
206
208
|
.execute();
|
|
207
209
|
};
|
|
208
|
-
|
|
210
|
+
|
|
209
211
|
if (isLoading) return <div>Database initializing...</div>;
|
|
210
212
|
if (error) return <div>Database error: {error.message}</div>;
|
|
211
|
-
|
|
213
|
+
|
|
212
214
|
return (
|
|
213
215
|
<button onClick={() => createUser('John', 'john@example.com')}>
|
|
214
216
|
Create User
|
|
@@ -225,9 +227,9 @@ function DatabaseOperations() {
|
|
|
225
227
|
|
|
226
228
|
```typescript
|
|
227
229
|
{
|
|
228
|
-
db: EnhancedKysely<Schema> | null;
|
|
229
|
-
isLoading: boolean;
|
|
230
|
-
error: Error | null;
|
|
230
|
+
db: EnhancedKysely<Schema> | null; // Enhanced Kysely instance with live capabilities
|
|
231
|
+
isLoading: boolean; // True while database is initializing
|
|
232
|
+
error: Error | null; // Any initialization error
|
|
231
233
|
}
|
|
232
234
|
```
|
|
233
235
|
|
|
@@ -254,9 +256,12 @@ function DatabaseOperations() {
|
|
|
254
256
|
|
|
255
257
|
```typescript
|
|
256
258
|
function useRelationalQuery<Schema, T, TParams>(
|
|
257
|
-
queryCallback: (
|
|
258
|
-
|
|
259
|
-
|
|
259
|
+
queryCallback: (
|
|
260
|
+
db: EnhancedKysely<Schema>,
|
|
261
|
+
parameters?: TParams,
|
|
262
|
+
) => QueryCallbackReturnType,
|
|
263
|
+
parameters?: TParams,
|
|
264
|
+
): QueryResult<T>;
|
|
260
265
|
```
|
|
261
266
|
|
|
262
267
|
### Description
|
|
@@ -277,10 +282,10 @@ function UserCount() {
|
|
|
277
282
|
.compile();
|
|
278
283
|
}
|
|
279
284
|
);
|
|
280
|
-
|
|
285
|
+
|
|
281
286
|
if (isLoading) return <div>Loading...</div>;
|
|
282
287
|
if (error) return <div>Error: {error.message}</div>;
|
|
283
|
-
|
|
288
|
+
|
|
284
289
|
return <div>User count: {result?.rows[0]?.count ?? 0}</div>;
|
|
285
290
|
}
|
|
286
291
|
```
|
|
@@ -294,9 +299,9 @@ function UserCount() {
|
|
|
294
299
|
|
|
295
300
|
```typescript
|
|
296
301
|
{
|
|
297
|
-
result: LiveQueryResults<T> | null;
|
|
298
|
-
isLoading: boolean;
|
|
299
|
-
error: Error | null;
|
|
302
|
+
result: LiveQueryResults<T> | null; // Live query results
|
|
303
|
+
isLoading: boolean; // Combined loading state
|
|
304
|
+
error: Error | null; // Any error that occurred
|
|
300
305
|
}
|
|
301
306
|
```
|
|
302
307
|
|
|
@@ -330,25 +335,25 @@ The `createProcessorQuery` hook automatically handles parameter changes and memo
|
|
|
330
335
|
|
|
331
336
|
```typescript
|
|
332
337
|
function useSearchResults() {
|
|
333
|
-
const [searchTerm, setSearchTerm] = useState(
|
|
334
|
-
const [category, setCategory] = useState(
|
|
338
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
339
|
+
const [category, setCategory] = useState("all");
|
|
335
340
|
|
|
336
341
|
// Query automatically updates when searchTerm or category changes
|
|
337
342
|
const result = useTypedQuery(
|
|
338
343
|
(db, params) => {
|
|
339
|
-
let query = db.selectFrom(
|
|
340
|
-
|
|
344
|
+
let query = db.selectFrom("products").selectAll();
|
|
345
|
+
|
|
341
346
|
if (params.searchTerm) {
|
|
342
|
-
query = query.where(
|
|
347
|
+
query = query.where("name", "like", `%${params.searchTerm}%`);
|
|
343
348
|
}
|
|
344
|
-
|
|
345
|
-
if (params.category !==
|
|
346
|
-
query = query.where(
|
|
349
|
+
|
|
350
|
+
if (params.category !== "all") {
|
|
351
|
+
query = query.where("category", "=", params.category);
|
|
347
352
|
}
|
|
348
|
-
|
|
353
|
+
|
|
349
354
|
return query.compile();
|
|
350
355
|
},
|
|
351
|
-
{ searchTerm, category }
|
|
356
|
+
{ searchTerm, category },
|
|
352
357
|
);
|
|
353
358
|
|
|
354
359
|
return { result, setSearchTerm, setCategory };
|
|
@@ -390,7 +395,7 @@ function useCustomUserStats() {
|
|
|
390
395
|
LEFT JOIN posts p ON u.id = p.author_id
|
|
391
396
|
GROUP BY u.id, u.name
|
|
392
397
|
ORDER BY post_count DESC
|
|
393
|
-
|
|
398
|
+
`,
|
|
394
399
|
};
|
|
395
400
|
});
|
|
396
401
|
}
|
|
@@ -407,10 +412,10 @@ function useUserPostsByDateRange(startDate: string, endDate: string) {
|
|
|
407
412
|
WHERE p.created_at BETWEEN $1 AND $2
|
|
408
413
|
ORDER BY p.created_at DESC
|
|
409
414
|
`,
|
|
410
|
-
parameters: [params.startDate, params.endDate]
|
|
415
|
+
parameters: [params.startDate, params.endDate],
|
|
411
416
|
};
|
|
412
417
|
},
|
|
413
|
-
{ startDate, endDate }
|
|
418
|
+
{ startDate, endDate },
|
|
414
419
|
);
|
|
415
420
|
}
|
|
416
421
|
```
|
|
@@ -438,16 +443,16 @@ Use Kysely's join capabilities within your query callbacks:
|
|
|
438
443
|
|
|
439
444
|
```typescript
|
|
440
445
|
function useUsersWithPosts() {
|
|
441
|
-
return useTypedQuery(db => {
|
|
446
|
+
return useTypedQuery((db) => {
|
|
442
447
|
return db
|
|
443
|
-
.selectFrom(
|
|
444
|
-
.leftJoin(
|
|
448
|
+
.selectFrom("users")
|
|
449
|
+
.leftJoin("posts", "users.id", "posts.author_id")
|
|
445
450
|
.select([
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
+
"users.id",
|
|
452
|
+
"users.name",
|
|
453
|
+
"users.email",
|
|
454
|
+
"posts.title as post_title",
|
|
455
|
+
"posts.content as post_content",
|
|
451
456
|
])
|
|
452
457
|
.compile();
|
|
453
458
|
});
|
|
@@ -458,21 +463,21 @@ function useUserDashboardData(userId: number) {
|
|
|
458
463
|
return useTypedQuery(
|
|
459
464
|
(db, params) => {
|
|
460
465
|
return db
|
|
461
|
-
.selectFrom(
|
|
462
|
-
.leftJoin(
|
|
463
|
-
.leftJoin(
|
|
466
|
+
.selectFrom("users")
|
|
467
|
+
.leftJoin("posts", "users.id", "posts.author_id")
|
|
468
|
+
.leftJoin("comments", "posts.id", "comments.post_id")
|
|
464
469
|
.select([
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
db.fn.count(
|
|
469
|
-
db.fn.count(
|
|
470
|
+
"users.id",
|
|
471
|
+
"users.name",
|
|
472
|
+
"users.email",
|
|
473
|
+
db.fn.count("posts.id").as("post_count"),
|
|
474
|
+
db.fn.count("comments.id").as("comment_count"),
|
|
470
475
|
])
|
|
471
|
-
.where(
|
|
472
|
-
.groupBy([
|
|
476
|
+
.where("users.id", "=", params.userId)
|
|
477
|
+
.groupBy(["users.id", "users.name", "users.email"])
|
|
473
478
|
.compile();
|
|
474
479
|
},
|
|
475
|
-
{ userId }
|
|
480
|
+
{ userId },
|
|
476
481
|
);
|
|
477
482
|
}
|
|
478
483
|
```
|
|
@@ -533,39 +538,32 @@ Create focused, reusable hooks for different data access patterns:
|
|
|
533
538
|
```typescript
|
|
534
539
|
// ✅ Good - Focused, reusable hooks
|
|
535
540
|
export function useUsers() {
|
|
536
|
-
return useTypedQuery(db =>
|
|
537
|
-
db.selectFrom('users').selectAll().compile()
|
|
538
|
-
);
|
|
541
|
+
return useTypedQuery((db) => db.selectFrom("users").selectAll().compile());
|
|
539
542
|
}
|
|
540
543
|
|
|
541
544
|
export function useUserById(id: number) {
|
|
542
545
|
return useTypedQuery(
|
|
543
|
-
(db, params) =>
|
|
544
|
-
.selectFrom(
|
|
545
|
-
|
|
546
|
-
.where('id', '=', params.id)
|
|
547
|
-
.compile(),
|
|
548
|
-
{ id }
|
|
546
|
+
(db, params) =>
|
|
547
|
+
db.selectFrom("users").selectAll().where("id", "=", params.id).compile(),
|
|
548
|
+
{ id },
|
|
549
549
|
);
|
|
550
550
|
}
|
|
551
551
|
|
|
552
552
|
export function useActiveUsers() {
|
|
553
|
-
return useTypedQuery(db =>
|
|
554
|
-
db.selectFrom(
|
|
555
|
-
.selectAll()
|
|
556
|
-
.where('active', '=', true)
|
|
557
|
-
.compile()
|
|
553
|
+
return useTypedQuery((db) =>
|
|
554
|
+
db.selectFrom("users").selectAll().where("active", "=", true).compile(),
|
|
558
555
|
);
|
|
559
556
|
}
|
|
560
557
|
|
|
561
558
|
// ❌ Avoid - Too generic or complex
|
|
562
559
|
export function useEverything() {
|
|
563
|
-
return useTypedQuery(db =>
|
|
564
|
-
db
|
|
565
|
-
.
|
|
566
|
-
.leftJoin(
|
|
560
|
+
return useTypedQuery((db) =>
|
|
561
|
+
db
|
|
562
|
+
.selectFrom("users")
|
|
563
|
+
.leftJoin("posts", "users.id", "posts.author_id")
|
|
564
|
+
.leftJoin("comments", "posts.id", "comments.post_id")
|
|
567
565
|
.selectAll() // Too much data
|
|
568
|
-
.compile()
|
|
566
|
+
.compile(),
|
|
569
567
|
);
|
|
570
568
|
}
|
|
571
569
|
```
|
|
@@ -600,7 +598,7 @@ function UserList() {
|
|
|
600
598
|
// ❌ Avoid - Missing error handling
|
|
601
599
|
function BadUserList() {
|
|
602
600
|
const { result } = useUsers();
|
|
603
|
-
|
|
601
|
+
|
|
604
602
|
return (
|
|
605
603
|
<ul>
|
|
606
604
|
{result?.rows.map(user => (
|
|
@@ -625,32 +623,35 @@ function BadUserList() {
|
|
|
625
623
|
```typescript
|
|
626
624
|
// ✅ Good - Focused query
|
|
627
625
|
function useUserNames() {
|
|
628
|
-
return useTypedQuery(db =>
|
|
629
|
-
db
|
|
630
|
-
.
|
|
631
|
-
.
|
|
626
|
+
return useTypedQuery((db) =>
|
|
627
|
+
db
|
|
628
|
+
.selectFrom("users")
|
|
629
|
+
.select(["id", "name"]) // Only what you need
|
|
630
|
+
.compile(),
|
|
632
631
|
);
|
|
633
632
|
}
|
|
634
633
|
|
|
635
634
|
// ✅ Good - Stable parameters
|
|
636
635
|
function useUsersByStatus(status: string) {
|
|
637
636
|
return useTypedQuery(
|
|
638
|
-
(db, params) =>
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
637
|
+
(db, params) =>
|
|
638
|
+
db
|
|
639
|
+
.selectFrom("users")
|
|
640
|
+
.selectAll()
|
|
641
|
+
.where("status", "=", params.status)
|
|
642
|
+
.compile(),
|
|
643
|
+
{ status }, // Simple, stable parameter
|
|
644
644
|
);
|
|
645
645
|
}
|
|
646
646
|
|
|
647
647
|
// ❌ Avoid - Unnecessary data
|
|
648
648
|
function useEverythingAboutUsers() {
|
|
649
|
-
return useTypedQuery(db =>
|
|
650
|
-
db
|
|
651
|
-
.
|
|
649
|
+
return useTypedQuery((db) =>
|
|
650
|
+
db
|
|
651
|
+
.selectFrom("users")
|
|
652
|
+
.leftJoin("posts", "users.id", "posts.author_id")
|
|
652
653
|
.selectAll() // Too much data
|
|
653
|
-
.compile()
|
|
654
|
+
.compile(),
|
|
654
655
|
);
|
|
655
656
|
}
|
|
656
657
|
```
|
|
@@ -665,9 +666,11 @@ function useEverythingAboutUsers() {
|
|
|
665
666
|
<summary>My query results aren't updating when I expect them to</summary>
|
|
666
667
|
|
|
667
668
|
### Problem
|
|
669
|
+
|
|
668
670
|
Your query results don't update when you expect them to, even though you've changed parameters.
|
|
669
671
|
|
|
670
672
|
### Solution
|
|
673
|
+
|
|
671
674
|
Check that your parameters are actually changing in content, not just reference:
|
|
672
675
|
|
|
673
676
|
```typescript
|
|
@@ -690,6 +693,7 @@ const result = useTypedQuery(
|
|
|
690
693
|
```
|
|
691
694
|
|
|
692
695
|
### Debugging Tips
|
|
696
|
+
|
|
693
697
|
- Log your parameters to see if they're actually changing
|
|
694
698
|
- Check the `isLoading` state to see if queries are re-running
|
|
695
699
|
- Use React DevTools to inspect hook state changes
|
|
@@ -702,27 +706,29 @@ const result = useTypedQuery(
|
|
|
702
706
|
<summary>Getting TypeScript errors with my queries</summary>
|
|
703
707
|
|
|
704
708
|
### Problem
|
|
709
|
+
|
|
705
710
|
TypeScript is showing errors about query return types or database schema.
|
|
706
711
|
|
|
707
712
|
### Solution
|
|
713
|
+
|
|
708
714
|
Make sure your callback returns the correct type:
|
|
709
715
|
|
|
710
716
|
```typescript
|
|
711
717
|
// ✅ Good - Returns QueryCallbackReturnType
|
|
712
|
-
const result = useTypedQuery(db => {
|
|
713
|
-
return db.selectFrom(
|
|
718
|
+
const result = useTypedQuery((db) => {
|
|
719
|
+
return db.selectFrom("users").selectAll().compile(); // Has sql property
|
|
714
720
|
});
|
|
715
721
|
|
|
716
722
|
// ❌ Error - Missing .compile()
|
|
717
|
-
const result = useTypedQuery(db => {
|
|
718
|
-
return db.selectFrom(
|
|
723
|
+
const result = useTypedQuery((db) => {
|
|
724
|
+
return db.selectFrom("users").selectAll(); // No sql property
|
|
719
725
|
});
|
|
720
726
|
|
|
721
727
|
// ✅ Good - Raw SQL format
|
|
722
728
|
const result = useTypedQuery(() => {
|
|
723
729
|
return {
|
|
724
|
-
sql:
|
|
725
|
-
parameters: []
|
|
730
|
+
sql: "SELECT * FROM users",
|
|
731
|
+
parameters: [],
|
|
726
732
|
};
|
|
727
733
|
});
|
|
728
734
|
```
|
|
@@ -735,9 +741,11 @@ const result = useTypedQuery(() => {
|
|
|
735
741
|
<summary>My queries are running too frequently or causing lag</summary>
|
|
736
742
|
|
|
737
743
|
### Problem
|
|
744
|
+
|
|
738
745
|
Your queries are running more often than expected, causing performance issues.
|
|
739
746
|
|
|
740
747
|
### Solution
|
|
748
|
+
|
|
741
749
|
Check for unstable parameters or overly complex queries:
|
|
742
750
|
|
|
743
751
|
```typescript
|
|
@@ -745,7 +753,7 @@ Check for unstable parameters or overly complex queries:
|
|
|
745
753
|
function BadComponent({ user }) {
|
|
746
754
|
const result = useTypedQuery(
|
|
747
755
|
(db, params) => /* query */,
|
|
748
|
-
{
|
|
756
|
+
{
|
|
749
757
|
filter: { status: 'active', dept: user.department } // New object each render
|
|
750
758
|
}
|
|
751
759
|
);
|
|
@@ -757,7 +765,7 @@ function GoodComponent({ user }) {
|
|
|
757
765
|
status: 'active',
|
|
758
766
|
dept: user.department
|
|
759
767
|
}), [user.department]);
|
|
760
|
-
|
|
768
|
+
|
|
761
769
|
const result = useTypedQuery(
|
|
762
770
|
(db, params) => /* query */,
|
|
763
771
|
{ filter }
|
|
@@ -768,9 +776,9 @@ function GoodComponent({ user }) {
|
|
|
768
776
|
function BetterComponent({ user }) {
|
|
769
777
|
const result = useTypedQuery(
|
|
770
778
|
(db, params) => /* query */,
|
|
771
|
-
{
|
|
772
|
-
status: 'active',
|
|
773
|
-
dept: user.department
|
|
779
|
+
{
|
|
780
|
+
status: 'active',
|
|
781
|
+
dept: user.department
|
|
774
782
|
}
|
|
775
783
|
);
|
|
776
784
|
}
|
|
@@ -789,4 +797,4 @@ function BetterComponent({ user }) {
|
|
|
789
797
|
|
|
790
798
|
- [`useDocuments`](/academy/APIReferences/ReactHooks#usedocuments) - Working with Powerhouse documents
|
|
791
799
|
- [`useDrives`](/academy/APIReferences/ReactHooks#usedrives) - Managing document drives
|
|
792
|
-
- [`useSelectedDocument`](/academy/APIReferences/ReactHooks#useselecteddocument) - Document selection state
|
|
800
|
+
- [`useSelectedDocument`](/academy/APIReferences/ReactHooks#useselecteddocument) - Document selection state
|