@smartive/graphql-magic 15.1.1 → 15.2.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/CHANGELOG.md +2 -2
- package/docs/docs/tutorial.md +133 -89
- package/docs/src/components/HomepageFeatures/index.tsx +8 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
## [15.
|
|
1
|
+
## [15.2.1](https://github.com/smartive/graphql-magic/compare/v15.2.0...v15.2.1) (2024-04-03)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* Finish intro ([4ecc445](https://github.com/smartive/graphql-magic/commit/4ecc44575901cbe731dca7b70f109da6eaa847ba))
|
package/docs/docs/tutorial.md
CHANGED
|
@@ -10,59 +10,85 @@ Let's create a blog with `graphql-magic`!
|
|
|
10
10
|
|
|
11
11
|
### Code base
|
|
12
12
|
|
|
13
|
-
First create a next.js website:
|
|
13
|
+
First create a `next.js` website:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
16
|
npx create-next-app@latest magic-blog --ts --app --tailwind --eslint --src
|
|
17
17
|
cd magic-blog
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Replace `src/app/globals.css`:
|
|
21
21
|
|
|
22
22
|
```
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
@tailwind base;
|
|
24
|
+
@tailwind components;
|
|
25
|
+
@tailwind utilities;
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
main {
|
|
28
|
+
@apply w-96 mx-auto
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
],
|
|
32
|
-
```
|
|
31
|
+
nav {
|
|
32
|
+
@apply flex items-center
|
|
33
|
+
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
h1, h2, h3, h4 {
|
|
36
|
+
@apply font-bold
|
|
37
|
+
}
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
h1 {
|
|
40
|
+
@apply text-4xl mb-4 flex-grow
|
|
41
|
+
}
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
h2 {
|
|
44
|
+
@apply text-3xl mb-3
|
|
45
|
+
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
h3 {
|
|
48
|
+
@apply text-2xl mb-2
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
h4 {
|
|
52
|
+
@apply text-xl mb-1
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
a {
|
|
56
|
+
@apply text-blue-500
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
article, form {
|
|
60
|
+
@apply mb-4 p-3 rounded-lg shadow-md border border-gray-100
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
input, textarea {
|
|
64
|
+
@apply border border-gray-300 w-full rounded-md p-1
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
label span {
|
|
68
|
+
@apply font-bold
|
|
53
69
|
}
|
|
54
70
|
```
|
|
55
71
|
|
|
56
|
-
Replace `app/page.tsx`:
|
|
72
|
+
Replace `src/app/page.tsx`:
|
|
57
73
|
|
|
58
74
|
```
|
|
59
|
-
export default function
|
|
60
|
-
return <
|
|
75
|
+
export default async function Home() {
|
|
76
|
+
return <main>
|
|
77
|
+
<nav>
|
|
61
78
|
<h1>Magic Blog</h1>
|
|
62
|
-
|
|
79
|
+
</nav>
|
|
80
|
+
</main>
|
|
63
81
|
}
|
|
64
82
|
```
|
|
65
83
|
|
|
84
|
+
Start the website:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
npm run dev
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Install graphql-magic
|
|
91
|
+
|
|
66
92
|
Add this setting to `next.config.mjs`:
|
|
67
93
|
|
|
68
94
|
```
|
|
@@ -79,28 +105,16 @@ Install `@smartive/graphql-magic`:
|
|
|
79
105
|
npm install @smartive/graphql-magic
|
|
80
106
|
```
|
|
81
107
|
|
|
82
|
-
Temporary:
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
npm i @graphql-codegen/typescript-compatibility
|
|
86
|
-
```
|
|
87
|
-
|
|
88
108
|
Run the gqm cli:
|
|
89
109
|
|
|
90
110
|
```
|
|
91
111
|
npx gqm generate
|
|
92
112
|
```
|
|
93
113
|
|
|
94
|
-
Start the website:
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
npm run dev
|
|
98
|
-
```
|
|
99
|
-
|
|
100
114
|
### Database setup
|
|
101
115
|
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
Let's boot a local database instance.
|
|
117
|
+
Create the following `docker-compose.yml`:
|
|
104
118
|
|
|
105
119
|
```
|
|
106
120
|
version: '3.4'
|
|
@@ -126,7 +140,7 @@ Generate the first migration:
|
|
|
126
140
|
npx gqm generate-migration
|
|
127
141
|
```
|
|
128
142
|
|
|
129
|
-
Enter
|
|
143
|
+
Enter a migration name, e.g. "setup".
|
|
130
144
|
|
|
131
145
|
|
|
132
146
|
Run the migration
|
|
@@ -148,10 +162,12 @@ import { getSession } from '@auth0/nextjs-auth0';
|
|
|
148
162
|
export default async function Page() {
|
|
149
163
|
const session = await getSession();
|
|
150
164
|
|
|
151
|
-
return <
|
|
165
|
+
return <main>
|
|
166
|
+
<nav>
|
|
152
167
|
<h1>Welcome to my Blog</h1>
|
|
153
168
|
{session ? <a href="/api/auth/logout">Logout</a> : <a href="/api/auth/login">Login</a>}
|
|
154
|
-
|
|
169
|
+
</nav>
|
|
170
|
+
</main>
|
|
155
171
|
}
|
|
156
172
|
```
|
|
157
173
|
|
|
@@ -241,23 +257,27 @@ npx gqm generate
|
|
|
241
257
|
Now, let's modify `src/app/page.tsx` so that it fetches the user from the database:
|
|
242
258
|
|
|
243
259
|
```
|
|
244
|
-
import { GetMeQuery } from "
|
|
245
|
-
import { GET_ME } from "
|
|
246
|
-
import { executeGraphql } from "
|
|
260
|
+
import { GetMeQuery } from "@/generated/client";
|
|
261
|
+
import { GET_ME } from "@/graphql/client/queries/get-me";
|
|
262
|
+
import { executeGraphql } from "@/graphql/execute";
|
|
247
263
|
|
|
248
|
-
export default async function
|
|
249
|
-
const { data: { me }} = await executeGraphql<GetMeQuery>({ query: GET_ME });
|
|
264
|
+
export default async function Home() {
|
|
265
|
+
const { data: { me } } = await executeGraphql<GetMeQuery>({ query: GET_ME });
|
|
250
266
|
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
267
|
+
return (
|
|
268
|
+
<main>
|
|
269
|
+
<nav>
|
|
270
|
+
<h1>Blog</h1>
|
|
271
|
+
{me ? <span>Hello, {me.username}! <a href="/api/auth/logout"> Logout</a></span> : <a href="/api/auth/login">Login</a>}
|
|
272
|
+
</nav>
|
|
273
|
+
</main>
|
|
274
|
+
);
|
|
255
275
|
}
|
|
256
276
|
```
|
|
257
277
|
|
|
258
278
|
### Content!
|
|
259
279
|
|
|
260
|
-
Let's
|
|
280
|
+
Let's make a blog out of this app by adding new models in `src/config/models.ts`:
|
|
261
281
|
|
|
262
282
|
```
|
|
263
283
|
{
|
|
@@ -313,10 +333,9 @@ Generate and run the new migrations and generate the new models:
|
|
|
313
333
|
```
|
|
314
334
|
npx gqm generate-migration
|
|
315
335
|
npx env-cmd knex migrate:up
|
|
316
|
-
npx gqm generate
|
|
317
336
|
```
|
|
318
337
|
|
|
319
|
-
new get-posts
|
|
338
|
+
Create a new query `src/graphql/client/queries/get-posts.ts`:
|
|
320
339
|
|
|
321
340
|
```
|
|
322
341
|
import { gql } from '@smartive/graphql-magic';
|
|
@@ -342,12 +361,59 @@ export const GET_POSTS = gql`
|
|
|
342
361
|
`;
|
|
343
362
|
```
|
|
344
363
|
|
|
364
|
+
Generate the new types:
|
|
365
|
+
|
|
345
366
|
```
|
|
346
|
-
|
|
347
|
-
<Posts/>
|
|
367
|
+
npx gqm generate
|
|
348
368
|
```
|
|
349
369
|
|
|
370
|
+
Now add all the logic to create and display posts and comments to `src/app/page.tsx`
|
|
371
|
+
|
|
372
|
+
|
|
350
373
|
```
|
|
374
|
+
import { CreateCommentMutationMutation, CreateCommentMutationMutationVariables, CreatePostMutationMutation, CreatePostMutationMutationVariables, GetMeQuery, GetPostsQuery } from "@/generated/client";
|
|
375
|
+
import { CREATE_COMMENT, CREATE_POST } from "@/generated/client/mutations";
|
|
376
|
+
import { GET_ME } from "@/graphql/client/queries/get-me";
|
|
377
|
+
import { GET_POSTS } from "@/graphql/client/queries/get-posts";
|
|
378
|
+
import { executeGraphql } from "@/graphql/execute";
|
|
379
|
+
import { revalidatePath } from "next/cache";
|
|
380
|
+
|
|
381
|
+
export default async function Home() {
|
|
382
|
+
const { data: { me } } = await executeGraphql<GetMeQuery>({ query: GET_ME });
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
<main>
|
|
386
|
+
<nav>
|
|
387
|
+
<h1>Blog</h1>
|
|
388
|
+
{me ? <span>Hello, {me.username}! <a href="/api/auth/logout"> Logout</a></span> : <a href="/api/auth/login">Login</a>}
|
|
389
|
+
</nav>
|
|
390
|
+
{me && <CreatePost />}
|
|
391
|
+
<Posts me={me} />
|
|
392
|
+
</main>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function Posts({ me }: { me: GetMeQuery['me'] }) {
|
|
397
|
+
const { data: { posts } } = await executeGraphql<GetPostsQuery>({ query: GET_POSTS })
|
|
398
|
+
|
|
399
|
+
return <div>
|
|
400
|
+
{posts.map(post => <div key={post.id}>
|
|
401
|
+
<article>
|
|
402
|
+
<h2>{post.title}</h2>
|
|
403
|
+
<div>by {post.createdBy.username}</div>
|
|
404
|
+
<p>{post.content}</p>
|
|
405
|
+
<h4>Comments</h4>
|
|
406
|
+
{post.comments.map(comment => (<div key={comment.id}>
|
|
407
|
+
<div>{comment.createdBy.username}</div>
|
|
408
|
+
<p>{comment.content}</p> by {comment.createdBy.username}
|
|
409
|
+
</div>)
|
|
410
|
+
)}
|
|
411
|
+
{me && <CreateComment postId={post.id} />}
|
|
412
|
+
</article>
|
|
413
|
+
</div>)}
|
|
414
|
+
</div>
|
|
415
|
+
}
|
|
416
|
+
|
|
351
417
|
async function CreatePost() {
|
|
352
418
|
async function createPost(formData: FormData) {
|
|
353
419
|
'use server'
|
|
@@ -365,44 +431,20 @@ async function CreatePost() {
|
|
|
365
431
|
|
|
366
432
|
return <form action={createPost}>
|
|
367
433
|
<h2>New Post</h2>
|
|
368
|
-
<
|
|
434
|
+
<label>
|
|
369
435
|
<span>Title</span>
|
|
370
436
|
<input name="title" />
|
|
371
|
-
</
|
|
372
|
-
<
|
|
437
|
+
</label>
|
|
438
|
+
<label>
|
|
373
439
|
<span>Content</span>
|
|
374
440
|
<textarea rows={5} name="content" />
|
|
375
|
-
</
|
|
441
|
+
</label>
|
|
376
442
|
<div>
|
|
377
443
|
<button type="submit">Create</button>
|
|
378
444
|
</div>
|
|
379
445
|
</form>
|
|
380
446
|
}
|
|
381
|
-
```
|
|
382
447
|
|
|
383
|
-
```
|
|
384
|
-
async function Posts() {
|
|
385
|
-
const { data: { posts } } = await executeGraphql<GetPostsQuery>({ query: GET_POSTS })
|
|
386
|
-
|
|
387
|
-
return <div>
|
|
388
|
-
{posts.map(post => <div key={post.id}>
|
|
389
|
-
<article>
|
|
390
|
-
<h3>{post.title}</h3>
|
|
391
|
-
<div>{post.createdBy.username}</div>
|
|
392
|
-
<div>{post.content}</div>
|
|
393
|
-
{post.comments.map(comment => (<div key={comment.id}>
|
|
394
|
-
<div>{comment.createdBy.username}</div>
|
|
395
|
-
<p>{comment.content}</p> by {comment.createdBy.username}
|
|
396
|
-
</div>)
|
|
397
|
-
)}
|
|
398
|
-
<CreateComment postId={post.id} />
|
|
399
|
-
</article>
|
|
400
|
-
</div>)}
|
|
401
|
-
</div>
|
|
402
|
-
}
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
```
|
|
406
448
|
function CreateComment({ postId }: { postId: string }) {
|
|
407
449
|
async function createComment(formData: FormData) {
|
|
408
450
|
'use server'
|
|
@@ -429,3 +471,5 @@ function CreateComment({ postId }: { postId: string }) {
|
|
|
429
471
|
</form>
|
|
430
472
|
}
|
|
431
473
|
```
|
|
474
|
+
|
|
475
|
+
Now you should have a working minimal blog example!
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import clsx from 'clsx';
|
|
2
1
|
import Heading from '@theme/Heading';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
3
|
import styles from './styles.module.css';
|
|
4
4
|
|
|
5
5
|
type FeatureItem = {
|
|
@@ -10,38 +10,35 @@ type FeatureItem = {
|
|
|
10
10
|
|
|
11
11
|
const FeatureList: FeatureItem[] = [
|
|
12
12
|
{
|
|
13
|
-
title: '
|
|
13
|
+
title: 'Model-first',
|
|
14
14
|
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
|
|
15
15
|
description: (
|
|
16
16
|
<>
|
|
17
|
-
|
|
18
|
-
used to get your website up and running quickly.
|
|
17
|
+
Define your model, generate everything else.
|
|
19
18
|
</>
|
|
20
19
|
),
|
|
21
20
|
},
|
|
22
21
|
{
|
|
23
|
-
title: '
|
|
22
|
+
title: 'CLI',
|
|
24
23
|
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
|
|
25
24
|
description: (
|
|
26
25
|
<>
|
|
27
|
-
|
|
28
|
-
ahead and move your docs into the <code>docs</code> directory.
|
|
26
|
+
Generate things with our cli.
|
|
29
27
|
</>
|
|
30
28
|
),
|
|
31
29
|
},
|
|
32
30
|
{
|
|
33
|
-
title: '
|
|
31
|
+
title: 'Brought to you by smartive',
|
|
34
32
|
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
|
|
35
33
|
description: (
|
|
36
34
|
<>
|
|
37
|
-
|
|
38
|
-
be extended while reusing the same header and footer.
|
|
35
|
+
We developed this as an internal tool.
|
|
39
36
|
</>
|
|
40
37
|
),
|
|
41
38
|
},
|
|
42
39
|
];
|
|
43
40
|
|
|
44
|
-
function Feature({title, Svg, description}: FeatureItem) {
|
|
41
|
+
function Feature({ title, Svg, description }: FeatureItem) {
|
|
45
42
|
return (
|
|
46
43
|
<div className={clsx('col col--4')}>
|
|
47
44
|
<div className="text--center">
|