nextjs-hasura-auth 0.1.0

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/GENERATOR.md ADDED
@@ -0,0 +1,671 @@
1
+ # GraphQL Query Generator Documentation (`GENERATOR.md`)
2
+
3
+ ## Purpose
4
+
5
+ This document describes the `Generator` function located in `lib/generator.ts`. Its purpose is to dynamically generate GraphQL query strings, `DocumentNode` objects (compatible with Apollo Client), and corresponding variables based on a provided set of options and a Hasura-like schema (`schema.json`). This simplifies the process of constructing GraphQL operations (queries, mutations, subscriptions) within the application.
6
+
7
+ ## Usage
8
+
9
+ 1. **Import:** Import the `Generator` factory function and the schema.
10
+ 2. **Initialize:** Create a `generate` function instance by calling `Generator` with your schema.
11
+ 3. **Generate:** Call the `generate` function with an `options` object defining the desired operation.
12
+
13
+ ```typescript
14
+ // Assuming 'nextjs-hasura-auth' is your published package name
15
+ import { Generator, GenerateOptions, GenerateResult } from 'nextjs-hasura-auth';
16
+ // Assuming schema is correctly loaded (you might need to handle schema loading differently when using the package)
17
+ // import schema from './schema.json';
18
+
19
+ // Initialize the generator (Schema needs to be passed)
20
+ // const generate = Generator(schema);
21
+ // TODO: Document how schema should be provided when using the package
22
+
23
+ // Define options for your query
24
+ const options: GenerateOptions = {
25
+ operation: 'query',
26
+ table: 'users',
27
+ where: { id: { _eq: 'some-uuid' } },
28
+ returning: ['id', 'name', 'email']
29
+ };
30
+
31
+ // Generate the query components
32
+ const { queryString, query, variables }: GenerateResult = generate(options);
33
+
34
+ // Now you can use `query` and `variables` with Apollo Client
35
+ // e.g., useQuery(query, { variables });
36
+ // or `queryString` for logging/debugging.
37
+ ```
38
+
39
+ <details>
40
+ <summary>Options (`GenerateOptions` Interface)</summary>
41
+
42
+ ## Options (`GenerateOptions` Interface)
43
+
44
+ The `generate` function accepts an object with the following properties:
45
+
46
+ * `operation`: (Required) The type of GraphQL operation.
47
+ * Type: `'query' | 'subscription' | 'insert' | 'update' | 'delete'`
48
+ * `table`: (Required) The base name of the table or root field for the operation (e.g., 'users'). The generator will attempt to find the correct specific query/mutation name (e.g., `users`, `users_by_pk`, `insert_users`, `insert_users_one`, `update_users_by_pk`, `delete_users_by_pk`) based on the operation and other options like `pk_columns` or `object`.
49
+ * Type: `string`
50
+ * `where`: (Optional) An object defining the filtering conditions for `query`, `subscription`, `update`, and `delete` operations. Structure should match Hasura's `_bool_exp` input type.
51
+ * Type: `Record<string, any>`
52
+ * `returning`: (Optional) Specifies the fields to return from the operation. Can be an array of strings or objects for nested fields/relations, or a single object to append fields/relations to defaults. If omitted for queries/subscriptions, defaults to `id` and common fields like `name`, `email`, `created_at`, `updated_at` if found in the schema. For mutations, defaults vary (e.g., `affected_rows` for bulk, specific fields for `_by_pk`/`_one`).
53
+ * Type: `(string | Record<string, any>)[] | Record<string, any> | string`
54
+ * `aggregate`: (Optional) An object defining aggregation operations for `query` operations. Will generate a query targeting the `<table>_aggregate` field.
55
+ * Type: `Record<string, any>` (e.g., `{ count: true, max: { created_at: true } }`)
56
+ * `object`: (Optional) For `insert` operations targeting a single row (`insert_<table>_one`). The object containing the data to insert. Use this OR `objects`, not both.
57
+ * Type: `Record<string, any>`
58
+ * `objects`: (Optional) For `insert` operations targeting multiple rows. An array of objects containing the data to insert.
59
+ * Type: `Record<string, any>[]`
60
+ * `pk_columns`: (Optional) An object specifying the primary key columns and values. Used to target specific `_by_pk` queries/mutations (`query`, `update`, `delete`).
61
+ * Type: `Record<string, any>` (e.g., `{ id: 'some-uuid' }`)
62
+ * `_set`: (Optional) For `update` operations. An object containing the fields and new values to set.
63
+ * Type: `Record<string, any>`
64
+ * `limit`: (Optional) Limits the number of rows returned for `query` and `subscription` operations (not applicable to `_by_pk`).
65
+ * Type: `number`
66
+ * `offset`: (Optional) Skips the specified number of rows for `query` and `subscription` operations (not applicable to `_by_pk`).
67
+ * Type: `number`
68
+ * `order_by`: (Optional) Specifies the sorting order for `query` and `subscription` operations (not applicable to `_by_pk`). Structure should match Hasura's `_order_by` input type.
69
+ * Type: `Record<string, any>[] | Record<string, any>`
70
+ * `fragments`: (Optional) An array of raw GraphQL fragment strings to include at the end of the generated query string.
71
+ * Type: `string[]`
72
+ * `variables`: (Optional) Pre-existing variables object if integrating with other logic. Not typically needed.
73
+ * Type: `Record<string, any>`
74
+ * `varCounter`: (Optional) Initial counter for variable naming (e.g., `$v1`, `$v2`). Defaults to 1.
75
+ * Type: `number`
76
+ </details>
77
+
78
+ ## Examples
79
+
80
+ *(Note: Variable types like `users_bool_exp`, `[users_order_by!]`, `uuid!`, `users_pk_columns_input!`, `users_set_input!`, `[users_insert_input!]!` are inferred based on schema structure and conventions. Ensure your `schema.json` reflects the actual types used by Hasura.)*
81
+
82
+ **Navigation**
83
+
84
+ * [1. Advanced Nested Query (Appending to Defaults)](#1-advanced-nested-query-appending-to-defaults)
85
+ * [2. Basic Query with `where`](#2-basic-query-with-where)
86
+ * [3. Query with Pagination and Sorting](#3-query-with-pagination-and-sorting)
87
+ * [4. Query by Primary Key](#4-query-by-primary-key)
88
+ * [5. Nested Query with Parameters and Alias](#5-nested-query-with-parameters-and-alias)
89
+ * [6. Aggregate Query](#6-aggregate-query)
90
+ * [7. Insert Mutation (Single Object)](#7-insert-mutation-single-object)
91
+ * [8. Insert Mutation (Bulk)](#8-insert-mutation-bulk)
92
+ * [9. Update Mutation by Primary Key](#9-update-mutation-by-primary-key)
93
+ * [10. Update Mutation by `where` Condition](#10-update-mutation-by-where-condition)
94
+ * [11. Delete Mutation by Primary Key](#11-delete-mutation-by-primary-key)
95
+ * [12. Delete Mutation by `where` Condition](#12-delete-mutation-by-where-condition)
96
+ * [13. Subscription](#13-subscription)
97
+
98
+
99
+ ### 1. Advanced Nested Query (Appending to Defaults)
100
+
101
+ This primary example demonstrates appending a complex relation to the default returned fields by providing `returning` as an object. This relation includes an alias, filtering (`where`), and pagination (`limit`).
102
+
103
+ ```typescript
104
+ const options: GenerateOptions = {
105
+ operation: 'query',
106
+ table: 'users',
107
+ where: { id: { _eq: 'user-for-test-13' } },
108
+ // Provide returning as an object to append relations/fields to defaults
109
+ returning: {
110
+ accounts: { // Key is the relation name from schema
111
+ // --- Parameters for the relation ---
112
+ alias: 'github_accounts', // Optional: Alias for the field in the result
113
+ where: { provider: { _eq: 'github' } }, // Optional: Filter relation results
114
+ limit: 5, // Optional: Limit relation results
115
+ // order_by: { created_at: 'desc' }, // Also supported
116
+ // offset: 10, // Also supported
117
+ // ... any other valid args for this relation from schema
118
+ // -------------------------------------
119
+ returning: ['id', 'provider'] // Fields to return for this relation
120
+ }
121
+ // Can add more relations here, e.g.:
122
+ // posts: { where: { published: { _eq: true } }, returning: ['id', 'title'] }
123
+ }
124
+ };
125
+ const result = generate(options);
126
+ ```
127
+
128
+ <details>
129
+ <summary>Generated `queryString`</summary>
130
+
131
+ ```graphql
132
+ // Note: Type github_accounts_bool_exp is derived from the alias
133
+ query QueryUsers($v1: users_bool_exp, $v2: github_accounts_bool_exp, $v3: Int) {
134
+ users(where: $v1) {
135
+ # Default fields (id, name, etc. based on schema):
136
+ id
137
+ name
138
+ email
139
+ created_at
140
+ updated_at
141
+ # Appended relation (using alias) with parameters:
142
+ accounts: github_accounts(where: $v2, limit: $v3) {
143
+ id
144
+ provider
145
+ }
146
+ }
147
+ }
148
+ ```
149
+ </details>
150
+
151
+ <details>
152
+ <summary>Generated `variables`</summary>
153
+
154
+ ```json
155
+ {
156
+ "v1": { "id": { "_eq": "user-for-test-13" } },
157
+ "v2": { "provider": { "_eq": "github" } },
158
+ "v3": 5
159
+ }
160
+ ```
161
+ </details>
162
+
163
+ ### 2. Basic Query with `where`
164
+
165
+ ```typescript
166
+ const options: GenerateOptions = {
167
+ operation: 'query',
168
+ table: 'users',
169
+ where: { email: { _ilike: '%@example.com' } },
170
+ returning: ['id', 'name', 'email'] // Explicit returning array (overrides defaults)
171
+ };
172
+ const result = generate(options);
173
+ ```
174
+
175
+ <details>
176
+ <summary>Generated `queryString`</summary>
177
+
178
+ ```graphql
179
+ query QueryUsers($v1: users_bool_exp) {
180
+ users(where: $v1) {
181
+ id
182
+ name
183
+ email
184
+ }
185
+ }
186
+ ```
187
+ </details>
188
+
189
+ <details>
190
+ <summary>Generated `variables`</summary>
191
+
192
+ ```json
193
+ {
194
+ "v1": {
195
+ "email": {
196
+ "_ilike": "%@example.com"
197
+ }
198
+ }
199
+ }
200
+ ```
201
+ </details>
202
+
203
+ ### 3. Query with Pagination and Sorting
204
+
205
+ ```typescript
206
+ const options: GenerateOptions = {
207
+ operation: 'query',
208
+ table: 'users',
209
+ returning: ['id', 'name', 'email'], // Explicit array
210
+ limit: 5,
211
+ offset: 10,
212
+ order_by: [{ created_at: 'desc' }]
213
+ };
214
+ const result = generate(options);
215
+ ```
216
+
217
+ <details>
218
+ <summary>Generated `queryString`</summary>
219
+
220
+ ```graphql
221
+ query QueryUsers($v1: Int, $v2: Int, $v3: [users_order_by!]) {
222
+ users(limit: $v1, offset: $v2, order_by: $v3) {
223
+ id
224
+ name
225
+ email
226
+ }
227
+ }
228
+ ```
229
+ </details>
230
+
231
+ <details>
232
+ <summary>Generated `variables`</summary>
233
+
234
+ ```json
235
+ {
236
+ "v1": 5,
237
+ "v2": 10,
238
+ "v3": [
239
+ {
240
+ "created_at": "desc"
241
+ }
242
+ ]
243
+ }
244
+ ```
245
+ </details>
246
+
247
+ ### 4. Query by Primary Key
248
+
249
+ ```typescript
250
+ const options: GenerateOptions = {
251
+ operation: 'query',
252
+ table: 'users', // Base table name
253
+ returning: ['id', 'name', 'email'], // Explicit array
254
+ pk_columns: { id: '123e4567-e89b-12d3-a456-426614174000' }
255
+ };
256
+ const result = generate(options);
257
+ ```
258
+
259
+ <details>
260
+ <summary>Generated `queryString`</summary>
261
+
262
+ ```graphql
263
+ query QueryUsersByPk($v1: uuid!) {
264
+ users_by_pk(id: $v1) {
265
+ id
266
+ name
267
+ email
268
+ }
269
+ }
270
+ ```
271
+ </details>
272
+
273
+ <details>
274
+ <summary>Generated `variables`</summary>
275
+
276
+ ```json
277
+ {
278
+ "v1": "123e4567-e89b-12d3-a456-426614174000"
279
+ }
280
+ ```
281
+ </details>
282
+
283
+ ### 5. Nested Query with Parameters and Alias
284
+
285
+ This example uses an *explicit array* for `returning`, fully defining the structure including the nested relation.
286
+
287
+ ```typescript
288
+ const options: GenerateOptions = {
289
+ operation: 'query',
290
+ table: 'users',
291
+ where: { id: { _eq: 'user-123' } },
292
+ returning: [
293
+ 'id',
294
+ 'name',
295
+ {
296
+ user_accounts: { // Relation name from schema
297
+ alias: 'active_google_accounts', // Alias for result field
298
+ where: { provider: { _eq: 'google' }, active: { _eq: true } },
299
+ limit: 3,
300
+ order_by: { created_at: 'desc' },
301
+ returning: ['id', 'provider', 'provider_account_id', 'created_at']
302
+ }
303
+ }
304
+ ]
305
+ };
306
+ const result = generate(options);
307
+ ```
308
+
309
+ <details>
310
+ <summary>Generated `queryString`</summary>
311
+
312
+ ```graphql
313
+ query QueryUsers($v1: users_bool_exp, $v2: active_google_accounts_bool_exp, $v3: Int, $v4: [active_google_accounts_order_by!]) {
314
+ users(where: $v1) {
315
+ id
316
+ name
317
+ user_accounts: active_google_accounts(where: $v2, limit: $v3, order_by: $v4) {
318
+ id
319
+ provider
320
+ provider_account_id
321
+ created_at
322
+ }
323
+ }
324
+ }
325
+ ```
326
+ </details>
327
+
328
+ <details>
329
+ <summary>Generated `variables`</summary>
330
+
331
+ ```json
332
+ {
333
+ "v1": { "id": { "_eq": "user-123" } },
334
+ "v2": { "provider": { "_eq": "google" }, "active": { "_eq": true } },
335
+ "v3": 3,
336
+ "v4": { "created_at": "desc" }
337
+ }
338
+ ```
339
+ </details>
340
+
341
+ ### 6. Aggregate Query
342
+
343
+ ```typescript
344
+ const options: GenerateOptions = {
345
+ operation: 'query',
346
+ table: 'users',
347
+ where: { email: { _ilike: '%@test.com' } },
348
+ aggregate: {
349
+ count: true,
350
+ max: { created_at: true }
351
+ },
352
+ // Optionally add `returning` (as array) to get nodes alongside aggregate
353
+ // returning: ['id', 'name']
354
+ };
355
+ const result = generate(options);
356
+ ```
357
+
358
+ <details>
359
+ <summary>Generated `queryString`</summary>
360
+
361
+ ```graphql
362
+ query QueryUsersAggregate($v1: users_bool_exp) {
363
+ users_aggregate(where: $v1) {
364
+ aggregate {
365
+ count
366
+ max {
367
+ created_at
368
+ }
369
+ }
370
+ # nodes { # Only if returning array was provided
371
+ # id
372
+ # name
373
+ # }
374
+ }
375
+ }
376
+ ```
377
+ </details>
378
+
379
+ <details>
380
+ <summary>Generated `variables`</summary>
381
+
382
+ ```json
383
+ {
384
+ "v1": {
385
+ "email": {
386
+ "_ilike": "%@test.com"
387
+ }
388
+ }
389
+ }
390
+ ```
391
+ </details>
392
+
393
+ ### 7. Insert Mutation (Single Object)
394
+
395
+ ```typescript
396
+ const options: GenerateOptions = {
397
+ operation: 'insert',
398
+ table: 'users',
399
+ object: {
400
+ name: 'Single User',
401
+ email: 'single@example.com'
402
+ },
403
+ returning: ['id', 'name', 'email'] // Explicit array
404
+ };
405
+ const result = generate(options);
406
+ ```
407
+
408
+ <details>
409
+ <summary>Generated `queryString`</summary>
410
+
411
+ ```graphql
412
+ mutation MutationInsertUsersOne($v1: users_insert_input!) {
413
+ insert_users_one(object: $v1) {
414
+ id
415
+ name
416
+ email
417
+ }
418
+ }
419
+ ```
420
+ </details>
421
+
422
+ <details>
423
+ <summary>Generated `variables`</summary>
424
+
425
+ ```json
426
+ {
427
+ "v1": {
428
+ "name": "Single User",
429
+ "email": "single@example.com"
430
+ }
431
+ }
432
+ ```
433
+ </details>
434
+
435
+ ### 8. Insert Mutation (Bulk)
436
+
437
+ ```typescript
438
+ const options: GenerateOptions = {
439
+ operation: 'insert',
440
+ table: 'users',
441
+ objects: [{
442
+ name: 'New User 1', email: 'new1@example.com'
443
+ },{
444
+ name: 'New User 2', email: 'new2@example.com'
445
+ }],
446
+ returning: ['id', 'name'] // Explicit array
447
+ };
448
+ const result = generate(options);
449
+ ```
450
+
451
+ <details>
452
+ <summary>Generated `queryString`</summary>
453
+
454
+ ```graphql
455
+ mutation MutationInsertUsers($v1: [users_insert_input!]!) {
456
+ insert_users(objects: $v1) {
457
+ affected_rows
458
+ returning {
459
+ id
460
+ name
461
+ }
462
+ }
463
+ }
464
+ ```
465
+ </details>
466
+
467
+ <details>
468
+ <summary>Generated `variables`</summary>
469
+
470
+ ```json
471
+ {
472
+ "v1": [
473
+ { "name": "New User 1", "email": "new1@example.com" },
474
+ { "name": "New User 2", "email": "new2@example.com" }
475
+ ]
476
+ }
477
+ ```
478
+ </details>
479
+
480
+ ### 9. Update Mutation by Primary Key
481
+
482
+ ```typescript
483
+ const options: GenerateOptions = {
484
+ operation: 'update',
485
+ table: 'users',
486
+ pk_columns: { id: '123e4567-e89b-12d3-a456-426614174000' },
487
+ _set: { name: 'Updated User' },
488
+ returning: ['id', 'name', 'updated_at'] // Explicit array
489
+ };
490
+ const result = generate(options);
491
+ ```
492
+
493
+ <details>
494
+ <summary>Generated `queryString`</summary>
495
+
496
+ ```graphql
497
+ mutation MutationUpdateUsersByPk($v1: users_pk_columns_input!, $v2: users_set_input!) {
498
+ update_users_by_pk(pk_columns: $v1, _set: $v2) {
499
+ id
500
+ name
501
+ updated_at
502
+ }
503
+ }
504
+ ```
505
+ </details>
506
+
507
+ <details>
508
+ <summary>Generated `variables`</summary>
509
+
510
+ ```json
511
+ {
512
+ "v1": {
513
+ "id": "123e4567-e89b-12d3-a456-426614174000"
514
+ },
515
+ "v2": {
516
+ "name": "Updated User"
517
+ }
518
+ }
519
+ ```
520
+ </details>
521
+
522
+ ### 10. Update Mutation by `where` Condition
523
+
524
+ ```typescript
525
+ const options: GenerateOptions = {
526
+ operation: 'update',
527
+ table: 'users',
528
+ where: { email: { _ilike: '%@test.com' } },
529
+ _set: { name: 'Updated Bulk User' },
530
+ returning: ['affected_rows'] // Explicit array (can also use object returning { ... })
531
+ };
532
+ const result = generate(options);
533
+ ```
534
+
535
+ <details>
536
+ <summary>Generated `queryString`</summary>
537
+
538
+ ```graphql
539
+ mutation MutationUpdateUsers($v1: users_bool_exp!, $v2: users_set_input!) {
540
+ update_users(where: $v1, _set: $v2) {
541
+ affected_rows
542
+ # returning { ... } # Only if returning fields were specified
543
+ }
544
+ }
545
+ ```
546
+ </details>
547
+
548
+ <details>
549
+ <summary>Generated `variables`</summary>
550
+
551
+ ```json
552
+ {
553
+ "v1": { "email": { "_ilike": "%@test.com" } },
554
+ "v2": { "name": "Updated Bulk User" }
555
+ }
556
+ ```
557
+ </details>
558
+
559
+ ### 11. Delete Mutation by Primary Key
560
+
561
+ ```typescript
562
+ const options: GenerateOptions = {
563
+ operation: 'delete',
564
+ table: 'users',
565
+ pk_columns: { id: '123e4567-e89b-12d3-a456-426614174000' },
566
+ returning: ['id', 'name', 'email'] // Fields of the deleted object
567
+ };
568
+ const result = generate(options);
569
+ ```
570
+
571
+ <details>
572
+ <summary>Generated `queryString`</summary>
573
+
574
+ ```graphql
575
+ mutation MutationDeleteUsersByPk($v1: uuid!) {
576
+ delete_users_by_pk(id: $v1) {
577
+ id
578
+ name
579
+ email
580
+ }
581
+ }
582
+ ```
583
+ </details>
584
+
585
+ <details>
586
+ <summary>Generated `variables`</summary>
587
+
588
+ ```json
589
+ {
590
+ "v1": "123e4567-e89b-12d3-a456-426614174000"
591
+ }
592
+ ```
593
+ </details>
594
+
595
+ ### 12. Delete Mutation by `where` Condition
596
+
597
+ ```typescript
598
+ const options: GenerateOptions = {
599
+ operation: 'delete',
600
+ table: 'users',
601
+ where: { email: { _ilike: '%@test.com' } },
602
+ returning: ['id', 'name'] // Fields of the deleted objects
603
+ };
604
+ const result = generate(options);
605
+ ```
606
+
607
+ <details>
608
+ <summary>Generated `queryString`</summary>
609
+
610
+ ```graphql
611
+ mutation MutationDeleteUsers($v1: users_bool_exp!) {
612
+ delete_users(where: $v1) {
613
+ affected_rows
614
+ returning {
615
+ id
616
+ name
617
+ }
618
+ }
619
+ }
620
+ ```
621
+ </details>
622
+
623
+ <details>
624
+ <summary>Generated `variables`</summary>
625
+
626
+ ```json
627
+ {
628
+ "v1": { "email": { "_ilike": "%@test.com" } }
629
+ }
630
+ ```
631
+ </details>
632
+
633
+ ### 13. Subscription
634
+
635
+ ```typescript
636
+ const options: GenerateOptions = {
637
+ operation: 'subscription',
638
+ table: 'users',
639
+ where: { is_admin: { _eq: true } },
640
+ returning: ['id', 'name', 'email']
641
+ };
642
+ const result = generate(options);
643
+ ```
644
+
645
+ <details>
646
+ <summary>Generated `queryString`</summary>
647
+
648
+ ```graphql
649
+ subscription SubscriptionUsers($v1: users_bool_exp) {
650
+ users(where: $v1) {
651
+ id
652
+ name
653
+ email
654
+ }
655
+ }
656
+ ```
657
+ </details>
658
+
659
+ <details>
660
+ <summary>Generated `variables`</summary>
661
+
662
+ ```json
663
+ {
664
+ "v1": {
665
+ "is_admin": {
666
+ "_eq": true
667
+ }
668
+ }
669
+ }
670
+ ```
671
+ </details>