diff --git a/.eslintrc b/.eslintrc index c471e81..4e74490 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,8 +5,10 @@ "project": "./tsconfig.eslint.json" }, "rules": { + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-namespace": "off", "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-floating-promises": ["error"], + "@typescript-eslint/no-floating-promises": "error", "no-constant-binary-expression": "error", "no-console": ["error", { "allow": ["info", "warn", "error", "trace", "time", "timeEnd"] }] } diff --git a/.gqmrc.json b/.gqmrc.json index 734d96e..3307971 100644 --- a/.gqmrc.json +++ b/.gqmrc.json @@ -2,7 +2,7 @@ "modelsPath": "tests/utils/models.ts", "generatedFolderPath": "tests/generated", "graphqlQueriesPath": "tests", - "gqlModule": "../../../src", + "gqmModule": "../../../src", "knexfilePath": "knexfile.ts", "dateLibrary": "luxon" -} \ No newline at end of file +} diff --git a/docs/docs/1-tutorial.md b/docs/docs/1-tutorial.md index 7bae569..a23cf20 100644 --- a/docs/docs/1-tutorial.md +++ b/docs/docs/1-tutorial.md @@ -21,47 +21,52 @@ Replace `src/app/globals.css`: @tailwind utilities; main { - @apply w-96 mx-auto + @apply w-96 mx-auto; } nav { - @apply flex items-center + @apply flex items-center; } -h1, h2, h3, h4 { - @apply font-bold +h1, +h2, +h3, +h4 { + @apply font-bold; } h1 { - @apply text-4xl mb-4 flex-grow + @apply text-4xl mb-4 flex-grow; } h2 { - @apply text-3xl mb-3 + @apply text-3xl mb-3; } h3 { - @apply text-2xl mb-2 + @apply text-2xl mb-2; } h4 { - @apply text-xl mb-1 + @apply text-xl mb-1; } a { - @apply text-blue-500 + @apply text-blue-500; } -article, form { - @apply mb-4 p-3 rounded-lg shadow-md border border-gray-100 +article, +form { + @apply mb-4 p-3 rounded-lg shadow-md border border-gray-100; } -input, textarea { - @apply border border-gray-300 w-full rounded-md p-1 +input, +textarea { + @apply border border-gray-300 w-full rounded-md p-1; } label span { - @apply font-bold + @apply font-bold; } ``` @@ -69,11 +74,13 @@ Replace `src/app/page.tsx`: ```tsx export default async function Home() { - return
+ return ( +
+ ); } ``` @@ -89,9 +96,9 @@ Add this setting to `next.config.mjs`: ```ts const nextConfig = { - experimental: { - serverComponentsExternalPackages: ['knex'], - } + experimental: { + serverComponentsExternalPackages: ['knex'], + }, }; ``` @@ -137,7 +144,6 @@ npx gqm generate-migration Enter a migration name, e.g. "setup". - Run the migration ```bash @@ -157,36 +163,38 @@ import { getSession } from '@auth0/nextjs-auth0'; export default async function Page() { const session = await getSession(); - return
- -
+ return ( +
+ +
+ ); } ``` It should now be possible for you to log in and out again. -### Account setup +### Account setup Now, we need to ensure that the user is stored in the database. First extend the user model in `src/config/models.ts` with the following fields: ```tsx - fields: [ - { - name: 'authId', - type: 'String', - nonNull: true, - }, - { - name: 'username', - type: 'String', - nonNull: true - } - ] +fields: [ + { + name: 'authId', + type: 'String', + nonNull: true, + }, + { + name: 'username', + type: 'String', + nonNull: true, + }, +]; ``` The models have changed, generate the new types: @@ -210,28 +218,28 @@ npx env-cmd knex migrate:latest Now let's implement the `// TODO: get user` part in the `src/graphql/execute.ts` file ```ts - const session = await getSession(); - if (session) { - let dbUser = await db('User').where({ authId: session.user.sub }).first(); - if (!user) { - await db('User').insert({ - id: randomUUID(), - authId: session.user.sub, - username: session.user.nickname - }) - dbUser = await db('User').where({ authId: session.user.sub }).first(); - } - user = { - ...dbUser!, - role: 'ADMIN' - } +const session = await getSession(); +if (session) { + let dbUser = await db('User').where({ authId: session.user.sub }).first(); + if (!user) { + await db('User').insert({ + id: randomUUID(), + authId: session.user.sub, + username: session.user.nickname, + }); + dbUser = await db('User').where({ authId: session.user.sub }).first(); } + user = { + ...dbUser!, + role: 'ADMIN', + }; +} ``` Extend `src/graphql/client/queries/get-me.ts` to also fetch the user's username: ```ts -import { gql } from '@smartive/graphql-magic'; +import { gql } from 'graphql-request'; export const GET_ME = gql` query GetMe { @@ -252,18 +260,26 @@ npx gqm generate Now, let's modify `src/app/page.tsx` so that it fetches the user from the database: ```tsx -import { GetMeQuery } from "@/generated/client"; -import { GET_ME } from "@/graphql/client/queries/get-me"; -import { executeGraphql } from "@/graphql/execute"; +import { GetMeQuery } from '@/generated/client'; +import { GET_ME } from '@/graphql/client/queries/get-me'; +import { executeGraphql } from '@/graphql/execute'; export default async function Home() { - const { data: { me } } = await executeGraphql({ query: GET_ME }); + const { + data: { me }, + } = await executeGraphql({ query: GET_ME }); return (
); @@ -334,24 +350,24 @@ npx env-cmd knex migrate:latest Create a new query `src/graphql/client/queries/get-posts.ts`: ```ts -import { gql } from '@smartive/graphql-magic'; +import { gql } from 'graphql-request'; export const GET_POSTS = gql` query GetPosts { posts { + id + title + content + createdBy { + username + } + comments { id - title - content createdBy { - username - } - comments { - id - createdBy { - username - } - content + username } + content + } } } `; @@ -365,23 +381,37 @@ npx gqm generate Now add all the logic to create and display posts and comments to `src/app/page.tsx` - ```tsx -import { CreateCommentMutationMutation, CreateCommentMutationMutationVariables, CreatePostMutationMutation, CreatePostMutationMutationVariables, GetMeQuery, GetPostsQuery } from "@/generated/client"; -import { CREATE_COMMENT, CREATE_POST } from "@/generated/client/mutations"; -import { GET_ME } from "@/graphql/client/queries/get-me"; -import { GET_POSTS } from "@/graphql/client/queries/get-posts"; -import { executeGraphql } from "@/graphql/execute"; -import { revalidatePath } from "next/cache"; +import { + CreateCommentMutationMutation, + CreateCommentMutationMutationVariables, + CreatePostMutationMutation, + CreatePostMutationMutationVariables, + GetMeQuery, + GetPostsQuery, +} from '@/generated/client'; +import { CREATE_COMMENT, CREATE_POST } from '@/generated/client/mutations'; +import { GET_ME } from '@/graphql/client/queries/get-me'; +import { GET_POSTS } from '@/graphql/client/queries/get-posts'; +import { executeGraphql } from '@/graphql/execute'; +import { revalidatePath } from 'next/cache'; export default async function Home() { - const { data: { me } } = await executeGraphql({ query: GET_ME }); + const { + data: { me }, + } = await executeGraphql({ query: GET_ME }); return (
{me && } @@ -390,81 +420,92 @@ export default async function Home() { } async function Posts({ me }: { me: GetMeQuery['me'] }) { - const { data: { posts } } = await executeGraphql({ query: GET_POSTS }) - - return
- {posts.map(post =>
-
-

{post.title}

-
by {post.createdBy.username}
-

{post.content}

-

Comments

- {post.comments.map(comment => (
-
{comment.createdBy.username}
-

{comment.content}

by {comment.createdBy.username} -
) - )} - {me && } -
-
)} -
+ const { + data: { posts }, + } = await executeGraphql({ query: GET_POSTS }); + + return ( +
+ {posts.map((post) => ( +
+
+

{post.title}

+
by {post.createdBy.username}
+

{post.content}

+

Comments

+ {post.comments.map((comment) => ( +
+
{comment.createdBy.username}
+

{comment.content}

by {comment.createdBy.username} +
+ ))} + {me && } +
+
+ ))} +
+ ); } async function CreatePost() { async function createPost(formData: FormData) { - 'use server' + 'use server'; await executeGraphql({ query: CREATE_POST, variables: { data: { title: formData.get('title') as string, - content: formData.get('content') as string - } - } - }) - revalidatePath('/') + content: formData.get('content') as string, + }, + }, + }); + revalidatePath('/'); } - return
-

New Post

- -