@smartive/graphql-magic 15.4.0 → 16.0.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/.gqmrc.json +4 -2
- package/CHANGELOG.md +1 -6
- package/dist/bin/gqm.cjs +115 -42
- package/dist/cjs/index.cjs +111 -30
- package/dist/esm/api/execute.d.ts +1 -1
- package/dist/esm/context.d.ts +5 -4
- package/dist/esm/db/generate.d.ts +2 -1
- package/dist/esm/db/generate.js +13 -8
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/migrations/generate.d.ts +1 -0
- package/dist/esm/migrations/generate.js +28 -6
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/mutation-hook.d.ts +5 -12
- package/dist/esm/models/utils.d.ts +20 -7
- package/dist/esm/models/utils.js +8 -0
- package/dist/esm/models/utils.js.map +1 -1
- package/dist/esm/permissions/check.d.ts +2 -3
- package/dist/esm/permissions/check.js.map +1 -1
- package/dist/esm/resolvers/arguments.d.ts +1 -1
- package/dist/esm/resolvers/mutations.js +5 -2
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/schema/utils.js +19 -8
- package/dist/esm/schema/utils.js.map +1 -1
- package/dist/esm/utils/dates.d.ts +12 -0
- package/dist/esm/utils/dates.js +37 -0
- package/dist/esm/utils/dates.js.map +1 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/values.d.ts +1 -3
- package/docker-compose.yml +0 -1
- package/docs/docs/1-tutorial.md +6 -6
- package/docs/docs/6-graphql-server.md +1 -3
- package/docs/docs/7-graphql-client.md +1 -1
- package/docs/docs/8-permissions.md +145 -0
- package/docs/package-lock.json +177 -177
- package/docs/package.json +6 -6
- package/knexfile.ts +2 -2
- package/migrations/20230912185644_setup.ts +37 -8
- package/package.json +5 -4
- package/src/bin/gqm/codegen.ts +4 -3
- package/src/bin/gqm/gqm.ts +4 -2
- package/src/bin/gqm/settings.ts +37 -2
- package/src/bin/gqm/templates.ts +19 -8
- package/src/context.ts +9 -5
- package/src/db/generate.ts +15 -8
- package/src/index.ts +1 -0
- package/src/migrations/generate.ts +34 -16
- package/src/models/mutation-hook.ts +5 -8
- package/src/models/utils.ts +24 -0
- package/src/permissions/check.ts +2 -3
- package/src/resolvers/mutations.ts +10 -6
- package/src/schema/utils.ts +14 -2
- package/src/utils/dates.ts +48 -0
- package/src/utils/index.ts +3 -0
- package/src/values.ts +1 -5
- package/tests/generated/client/index.ts +3 -1
- package/tests/generated/db/index.ts +43 -43
- package/tests/utils/database/seed.ts +9 -5
- package/tests/utils/server.ts +3 -3
package/docs/docs/1-tutorial.md
CHANGED
|
@@ -95,10 +95,10 @@ const nextConfig = {
|
|
|
95
95
|
};
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
Install `@smartive/graphql-magic
|
|
98
|
+
Install `@smartive/graphql-magic` and needed dependencies:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
npm install @smartive/graphql-magic
|
|
101
|
+
npm install @smartive/graphql-magic @graphql-codegen/typescript-compatibility
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
Run the gqm cli:
|
|
@@ -123,7 +123,6 @@ services:
|
|
|
123
123
|
POSTGRES_USER: postgres
|
|
124
124
|
POSTGRES_PASSWORD: password
|
|
125
125
|
POSTGRES_HOST_AUTH_METHOD: trust
|
|
126
|
-
TZ: 'Europe/Zurich'
|
|
127
126
|
ports:
|
|
128
127
|
- '5432:5432'
|
|
129
128
|
```
|
|
@@ -213,14 +212,14 @@ Now let's implement the `// TODO: get user` part in the `src/graphql/execute.ts`
|
|
|
213
212
|
```ts
|
|
214
213
|
const session = await getSession();
|
|
215
214
|
if (session) {
|
|
216
|
-
let dbUser = await db('User').where({ authId: session.user.
|
|
215
|
+
let dbUser = await db('User').where({ authId: session.user.sub }).first();
|
|
217
216
|
if (!user) {
|
|
218
217
|
await db('User').insert({
|
|
219
218
|
id: randomUUID(),
|
|
220
|
-
authId: session.user.
|
|
219
|
+
authId: session.user.sub,
|
|
221
220
|
username: session.user.nickname
|
|
222
221
|
})
|
|
223
|
-
dbUser = await db('User').where({ authId: session.user.
|
|
222
|
+
dbUser = await db('User').where({ authId: session.user.sub }).first();
|
|
224
223
|
}
|
|
225
224
|
user = {
|
|
226
225
|
...dbUser!,
|
|
@@ -322,6 +321,7 @@ Let's make a blog out of this app by adding new models in `src/config/models.ts`
|
|
|
322
321
|
updatable: true,
|
|
323
322
|
}
|
|
324
323
|
]
|
|
324
|
+
}
|
|
325
325
|
```
|
|
326
326
|
|
|
327
327
|
Generate and run the new migrations and generate the new models:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Graphql server
|
|
2
2
|
|
|
3
|
-
## `
|
|
3
|
+
## `executeGraphql`
|
|
4
4
|
|
|
5
5
|
`graphql-magic` generates an `execute.ts` file for you, with this structure:
|
|
6
6
|
|
|
@@ -9,7 +9,6 @@ import knexConfig from "@/knexfile";
|
|
|
9
9
|
import { Context, User, execute } from "@smartive/graphql-magic";
|
|
10
10
|
import { randomUUID } from "crypto";
|
|
11
11
|
import { knex } from 'knex';
|
|
12
|
-
import { DateTime } from "luxon";
|
|
13
12
|
import { models } from "../config/models";
|
|
14
13
|
|
|
15
14
|
export const executeGraphql = async <T, V = undefined>(
|
|
@@ -32,7 +31,6 @@ export const executeGraphql = async <T, V = undefined>(
|
|
|
32
31
|
user,
|
|
33
32
|
models: models,
|
|
34
33
|
permissions: { ADMIN: true, UNAUTHENTICATED: true },
|
|
35
|
-
now: DateTime.local(),
|
|
36
34
|
});
|
|
37
35
|
await db.destroy();
|
|
38
36
|
|
|
@@ -18,7 +18,7 @@ module.exports = {
|
|
|
18
18
|
|
|
19
19
|
### Server side
|
|
20
20
|
|
|
21
|
-
On the server side, and with `next.js` server actions, a graphql api becomes unnecessary, and you can execute
|
|
21
|
+
On the server side, and with `next.js` server actions, a graphql api becomes unnecessary, and you can execute queries directly using `executeGraphql`:
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
import { GetMeQuery, GetPostsQuery } from "@/generated/client";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Permissions
|
|
2
|
+
|
|
3
|
+
Permissions are an object provided to the `execute` function.
|
|
4
|
+
The root keys of the objects are the user roles (including the special role `UNAUTHENTICATED` for when the user object is undefined).
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
execute({
|
|
8
|
+
...
|
|
9
|
+
user: {
|
|
10
|
+
// ...
|
|
11
|
+
role: 'USER' // this is the role that will apply
|
|
12
|
+
},
|
|
13
|
+
permissions: {
|
|
14
|
+
ADMIN: ... // admin permissions
|
|
15
|
+
USER: ... // user permissions
|
|
16
|
+
UNAUTHENTICATED: ... // permissions for unauthenticated users
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Grant all permissions
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
ADMIN: true
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Actions
|
|
28
|
+
|
|
29
|
+
- READ
|
|
30
|
+
- CREATE
|
|
31
|
+
- UPDATE
|
|
32
|
+
- DELETE
|
|
33
|
+
- RESTORE
|
|
34
|
+
- LINK
|
|
35
|
+
|
|
36
|
+
Grant all READ permissions on a specific table:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
User: {} // same as User: { READ: true }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Grant actions other than READ on a specific table:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
User: { CREATE: true }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Linking
|
|
49
|
+
|
|
50
|
+
The LINK permission doesn't give one permission to modify these records,
|
|
51
|
+
but to use them as options for foreign keys in _other_ records that one does have the permission to CREATE/UPDATE.
|
|
52
|
+
|
|
53
|
+
So, for example, if you want a manager to be able to assign a user to a task, you would model it like this:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
MANAGER: {
|
|
57
|
+
User: { LINK: true }
|
|
58
|
+
Task: { UPDATE: true }
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Narrowing the record set
|
|
63
|
+
|
|
64
|
+
Use WHERE, which accepts simple table column/value pairs that are then used as sql where filter.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
GUEST: {
|
|
68
|
+
Post: {
|
|
69
|
+
WHERE: { published: true }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Derivative permissions
|
|
75
|
+
|
|
76
|
+
In the following way you can define permissions that follow the relational structure.
|
|
77
|
+
|
|
78
|
+
"If I can read a board (because it is public), then I can follow all threads and their authors, and their replies, which I can like."
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
GUEST: {
|
|
82
|
+
Board: {
|
|
83
|
+
WHERE: { public: true }
|
|
84
|
+
RELATIONS: {
|
|
85
|
+
threads: {
|
|
86
|
+
RELATIONS: {
|
|
87
|
+
LINK: true,
|
|
88
|
+
author: {},
|
|
89
|
+
replies: {
|
|
90
|
+
CREATE: true,
|
|
91
|
+
LINK: true,
|
|
92
|
+
likes: {
|
|
93
|
+
CREATE: true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Me
|
|
104
|
+
|
|
105
|
+
You can use `me` as a special `User` record set containing just yourself.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
EMPLOYEE: {
|
|
109
|
+
me: {
|
|
110
|
+
UPDATE: true,
|
|
111
|
+
LINK: true,
|
|
112
|
+
RELATIONS: {
|
|
113
|
+
tasks: {
|
|
114
|
+
UPDATE: true
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Note: for ownership patterns (I own what I create, I can update what I own),
|
|
122
|
+
one must use implicitly generated relationships such as `createdPosts`, `updatedPosts`, `deletedPosts`:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
GUEST: {
|
|
126
|
+
me: {
|
|
127
|
+
LINK: true,
|
|
128
|
+
RELATIONS: {
|
|
129
|
+
createdPosts: {
|
|
130
|
+
// "guests can create a post with the field createdBy === me"
|
|
131
|
+
CREATE: true,
|
|
132
|
+
UPDATE: true
|
|
133
|
+
},
|
|
134
|
+
updatedPosts: {
|
|
135
|
+
// this is necessary or it won't be possible to create a post
|
|
136
|
+
// "guests can create a post with the field updatedBy === me"
|
|
137
|
+
CREATE: true
|
|
138
|
+
|
|
139
|
+
// this is *not* necessary because the user can already update posts they created
|
|
140
|
+
// UPDATE: true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|