@cedarjs/cli 7.0.1-next.333 → 7.0.1-next.467
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/dist/commands/deploy/baremetal/baremetalHandler.js +363 -72
- package/dist/commands/deploy/baremetal/monitors.js +66 -0
- package/dist/commands/deploy/baremetal.js +6 -0
- package/dist/commands/destroy/scaffold/scaffoldHandler.js +63 -25
- package/dist/commands/dev/devHandler.js +13 -1
- package/dist/commands/generate/dbAuth/templates/login.webAuthn.tsx.template +20 -12
- package/dist/commands/generate/helpers.js +26 -0
- package/dist/commands/generate/ogImage/templates/ogImage.og.tsx.template +1 -1
- package/dist/commands/generate/package/templates/tsconfig.json.template +1 -0
- package/dist/commands/generate/realtime/templates/liveQueries/blank/blank.service.ts.template +12 -4
- package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.service.ts.template +2 -2
- package/dist/commands/generate/realtime/templates/subscriptions/blank/blank.ts.template +3 -3
- package/dist/commands/generate/scaffold/scaffold.js +1 -1
- package/dist/commands/generate/scaffold/scaffoldHandler.js +83 -44
- package/dist/commands/generate/scaffold/templates/assets/scaffold.tailwind.css.template +12 -7
- package/dist/commands/generate/scaffold/templates/components/EditNameCell.tsx.template +7 -7
- package/dist/commands/generate/scaffold/templates/components/NameForm.tsx.template +7 -6
- package/dist/commands/generate/scaffold/templates/layouts/NamesScaffoldLayout.tsx.template +18 -0
- package/dist/commands/generate/scaffold/templates/lib/formatters.tsx.template +3 -3
- package/dist/commands/generate/script/templates/tsconfig.json.template +1 -0
- package/dist/commands/generate/sdl/sdlHandler.js +8 -3
- package/dist/commands/generate/service/serviceHandler.js +32 -11
- package/dist/commands/generate/service/templates/service.ts.template +21 -8
- package/dist/commands/generate/service/templates/test.ts.template +7 -5
- package/dist/commands/jobsHandler.js +5 -3
- package/dist/commands/setup/cache/templates/memcached.ts.template +14 -17
- package/dist/commands/setup/cache/templates/redis.ts.template +12 -20
- package/dist/commands/setup/deploy/helpers/index.js +3 -1
- package/dist/commands/setup/deploy/providers/baremetal.js +7 -0
- package/dist/commands/setup/deploy/providers/baremetalHandler.js +128 -20
- package/dist/commands/setup/deploy/providers/netlifyHandler.js +25 -3
- package/dist/commands/setup/deploy/templates/baremetal.js +119 -9
- package/dist/commands/setup/deploy/templates/netlifyUD.js +3 -0
- package/dist/commands/setup/jobs/jobsHandler.js +2 -0
- package/dist/commands/setup/monitoring/sentry/sentryHandler.js +5 -2
- package/dist/commands/setup/monitoring/sentry/templates/sentryApi.ts.template +1 -4
- package/dist/commands/setup/monitoring/sentry/templates/sentryWeb.ts.template +7 -4
- package/dist/commands/setup/realtime/templates/defer/fastAndSlowFields/fastAndSlowFields.ts.template +4 -1
- package/dist/commands/setup/realtime/templates/liveQueries/auctions/auctions.ts.template +12 -4
- package/dist/commands/setup/realtime/templates/subscriptions/newMessage/newMessage.ts.template +1 -1
- package/dist/commands/setup/tenancy/signupCodemod.js +2 -1
- package/dist/commands/setup/tenancy/templates/InvitePage.tsx.template +10 -1
- package/dist/commands/setup/tenancy/templates/organizations.scenarios.ts.template +0 -2
- package/dist/commands/setup/tenancy/templates/organizations.test.ts.template +0 -8
- package/dist/commands/setup/tenancy/templates/organizations.ts.template +1 -1
- package/dist/commands/setup/tenancy/templates/requireMembership.test.ts.template +1 -1
- package/dist/commands/setup/tenancy/tenancyHandler.js +1 -1
- package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +61 -81
- package/dist/commands/setup/uploads/gitignore.js +17 -0
- package/dist/commands/setup/uploads/templates/uploads.ts.template +14 -5
- package/dist/commands/setup/uploads/uploadsHandler.js +22 -1
- package/dist/lib/index.js +10 -6
- package/package.json +24 -24
- package/dist/commands/setup/ui/templates/postcss.config.cjs.template +0 -9
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Makes your app's Tailwind theme and utilities available to `@apply`
|
|
3
|
+
* without emitting any of the styles in index.css a second time
|
|
4
|
+
*/
|
|
5
|
+
@reference './index.css';
|
|
6
|
+
|
|
1
7
|
.rw-scaffold {
|
|
2
8
|
@apply bg-white text-gray-600;
|
|
3
9
|
}
|
|
@@ -27,8 +33,7 @@
|
|
|
27
33
|
@apply mx-4 pb-4;
|
|
28
34
|
}
|
|
29
35
|
.rw-segment {
|
|
30
|
-
@apply rounded-lg overflow-hidden w-full border border-gray-200;
|
|
31
|
-
scrollbar-color: theme('colors.zinc.400') transparent;
|
|
36
|
+
@apply rounded-lg overflow-hidden w-full border border-gray-200 scrollbar-thumb-zinc-400 scrollbar-track-transparent;
|
|
32
37
|
}
|
|
33
38
|
.rw-segment::-webkit-scrollbar {
|
|
34
39
|
height: initial;
|
|
@@ -80,7 +85,7 @@
|
|
|
80
85
|
}
|
|
81
86
|
.rw-cell-error,
|
|
82
87
|
.rw-form-error-wrapper {
|
|
83
|
-
@apply p-4 bg-red-50 text-red-600 border border-red-100 rounded my-4;
|
|
88
|
+
@apply p-4 bg-red-50 text-red-600 border border-red-100 rounded-sm my-4;
|
|
84
89
|
}
|
|
85
90
|
.rw-form-error-title {
|
|
86
91
|
@apply m-0 font-semibold;
|
|
@@ -89,13 +94,13 @@
|
|
|
89
94
|
@apply mt-2 list-disc list-inside;
|
|
90
95
|
}
|
|
91
96
|
.rw-button {
|
|
92
|
-
@apply flex justify-center py-1 px-4 border-0 rounded bg-gray-200 text-gray-500 text-xs font-semibold uppercase tracking-wide leading-loose no-underline cursor-pointer transition duration-100;
|
|
97
|
+
@apply flex justify-center py-1 px-4 border-0 rounded-sm bg-gray-200 text-gray-500 text-xs font-semibold uppercase tracking-wide leading-loose no-underline cursor-pointer transition duration-100;
|
|
93
98
|
}
|
|
94
99
|
.rw-button:hover {
|
|
95
100
|
@apply bg-gray-500 text-white;
|
|
96
101
|
}
|
|
97
102
|
.rw-button.rw-button-small {
|
|
98
|
-
@apply text-xs rounded-
|
|
103
|
+
@apply text-xs rounded-xs py-1 px-2;
|
|
99
104
|
}
|
|
100
105
|
.rw-button.rw-button-green {
|
|
101
106
|
@apply bg-green-500 text-white;
|
|
@@ -134,7 +139,7 @@
|
|
|
134
139
|
@apply text-red-600;
|
|
135
140
|
}
|
|
136
141
|
.rw-input {
|
|
137
|
-
@apply block mt-2 w-full p-2 bg-white border border-gray-200 rounded outline-
|
|
142
|
+
@apply block mt-2 w-full p-2 bg-white border border-gray-200 rounded-sm outline-hidden;
|
|
138
143
|
}
|
|
139
144
|
.rw-check-radio-items {
|
|
140
145
|
@apply flex justify-items-center;
|
|
@@ -153,7 +158,7 @@
|
|
|
153
158
|
@apply border-red-600 text-red-600;
|
|
154
159
|
}
|
|
155
160
|
.rw-input-error:focus {
|
|
156
|
-
@apply border-red-600 outline-
|
|
161
|
+
@apply border-red-600 outline-hidden;
|
|
157
162
|
box-shadow: 0 0 5px #c53030;
|
|
158
163
|
}
|
|
159
164
|
.rw-field-error {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
${useClientDirective}import type {
|
|
2
2
|
Edit${singularPascalName}By${pascalIdName},
|
|
3
3
|
Update${singularPascalName}Input,
|
|
4
|
+
Update${singularPascalName}Mutation,
|
|
4
5
|
Update${singularPascalName}MutationVariables
|
|
5
6
|
} from 'types/graphql'
|
|
6
7
|
|
|
@@ -24,7 +25,7 @@ export const QUERY: TypedDocumentNode<Edit${singularPascalName}By${pascalIdName}
|
|
|
24
25
|
`
|
|
25
26
|
|
|
26
27
|
const UPDATE_${singularConstantName}_MUTATION: TypedDocumentNode<
|
|
27
|
-
|
|
28
|
+
Update${singularPascalName}Mutation,
|
|
28
29
|
Update${singularPascalName}MutationVariables
|
|
29
30
|
> = gql`
|
|
30
31
|
mutation Update${singularPascalName}Mutation($${idName}: ${idType}!, $input: Update${singularPascalName}Input!) {
|
|
@@ -36,6 +37,8 @@ const UPDATE_${singularConstantName}_MUTATION: TypedDocumentNode<
|
|
|
36
37
|
|
|
37
38
|
export const Loading = () => <div>Loading...</div>
|
|
38
39
|
|
|
40
|
+
export const Empty = () => <div>${singularPascalName} not found</div>
|
|
41
|
+
|
|
39
42
|
export const Failure = ({ error }: CellFailureProps) => (
|
|
40
43
|
<div className="rw-cell-error">{error?.message}</div>
|
|
41
44
|
)
|
|
@@ -54,17 +57,14 @@ export const Success = ({ ${singularCamelName} }: CellSuccessProps<Edit${singula
|
|
|
54
57
|
}
|
|
55
58
|
)
|
|
56
59
|
|
|
57
|
-
const onSave = (
|
|
58
|
-
|
|
59
|
-
id: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}']['id']
|
|
60
|
-
) => {
|
|
61
|
-
update${singularPascalName}({ variables: { id, input } })
|
|
60
|
+
const onSave = (input: Update${singularPascalName}Input) => {
|
|
61
|
+
update${singularPascalName}({ variables: { ${idName}: ${singularCamelName}.${idName}, input } })
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
65
|
<div className="rw-segment">
|
|
66
66
|
<header className="rw-segment-header">
|
|
67
|
-
<h2 className="rw-heading rw-heading-secondary">Edit ${singularPascalName} {${singularCamelName}
|
|
67
|
+
<h2 className="rw-heading rw-heading-secondary">Edit ${singularPascalName} {${singularCamelName}.${idName}}</h2>
|
|
68
68
|
</header>
|
|
69
69
|
<div className="rw-segment-main">
|
|
70
70
|
<${singularPascalName}Form ${singularCamelName}={${singularCamelName}} onSave={onSave} error={error} loading={loading} />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Edit${singularPascalName}By${pascalIdName},
|
|
1
|
+
import type { Edit${singularPascalName}By${pascalIdName}, Create${singularPascalName}Input } from 'types/graphql'
|
|
2
2
|
|
|
3
3
|
import type { RWGqlError } from '@cedarjs/forms'
|
|
4
4
|
import {
|
|
@@ -48,8 +48,8 @@ type Form${singularPascalName} = NonNullable<Edit${singularPascalName}By${pascal
|
|
|
48
48
|
|
|
49
49
|
interface ${singularPascalName}FormProps {
|
|
50
50
|
${singularCamelName}?: Edit${singularPascalName}By${pascalIdName}['${singularCamelName}']
|
|
51
|
-
onSave: (data:
|
|
52
|
-
error
|
|
51
|
+
onSave: (data: Create${singularPascalName}Input) => void
|
|
52
|
+
error?: RWGqlError
|
|
53
53
|
loading: boolean
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -70,7 +70,8 @@ const ${singularPascalName}Form = (props: ${singularPascalName}FormProps) => {
|
|
|
70
70
|
}
|
|
71
71
|
<% } %>
|
|
72
72
|
<% if (column.isEnum && !column.isList && !column.isRequired) { %>
|
|
73
|
-
|
|
73
|
+
// The "None" option has an empty value
|
|
74
|
+
if (!data.${column.name}) {
|
|
74
75
|
data.${column.name} = null
|
|
75
76
|
}
|
|
76
77
|
<% } %>
|
|
@@ -80,7 +81,7 @@ const ${singularPascalName}Form = (props: ${singularPascalName}FormProps) => {
|
|
|
80
81
|
}
|
|
81
82
|
<% } %>
|
|
82
83
|
<% }) %>
|
|
83
|
-
props.onSave(data
|
|
84
|
+
props.onSave(data)
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
return (
|
|
@@ -136,7 +137,7 @@ const ${singularPascalName}Form = (props: ${singularPascalName}FormProps) => {
|
|
|
136
137
|
<% } else { %>
|
|
137
138
|
<${column.component}
|
|
138
139
|
name="${column.name}"
|
|
139
|
-
${column.defaultProp}={${column.deserializeFunction && column.deserializeFunction + '('}props.${singularCamelName}?.<%= column.name %>${column.deserializeFunction && ')'}}
|
|
140
|
+
${column.defaultProp}={${column.deserializeFunction && column.deserializeFunction + '('}props.${singularCamelName}?.<%= column.name %>${column.deserializeFunction && ')'}<%= !column.deserializeFunction && !column.isRequired ? ' ?? undefined' : '' %>}
|
|
140
141
|
className="rw-input"
|
|
141
142
|
errorClassName="rw-input rw-input-error"
|
|
142
143
|
<%= !column.validation ? '' : `validation=${column.validation}` %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { WrapperProps } from '@cedarjs/router'
|
|
2
|
+
|
|
3
|
+
import ScaffoldLayout from '${importLayoutNames}'
|
|
4
|
+
|
|
5
|
+
function ${pluralPascalName}ScaffoldLayout({ children }: WrapperProps) {
|
|
6
|
+
return (
|
|
7
|
+
<ScaffoldLayout
|
|
8
|
+
title="${pluralPascalName}"
|
|
9
|
+
titleTo="${pluralRouteName}"
|
|
10
|
+
buttonLabel="New ${singularPascalName}"
|
|
11
|
+
buttonTo="${newRouteName}"
|
|
12
|
+
>
|
|
13
|
+
{children}
|
|
14
|
+
</ScaffoldLayout>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default ${pluralPascalName}ScaffoldLayout
|
|
@@ -25,7 +25,7 @@ export const jsonDisplay = (obj: unknown) => {
|
|
|
25
25
|
)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const truncate = (value: string | number) => {
|
|
28
|
+
export const truncate = (value: string | number | null | undefined) => {
|
|
29
29
|
let output = value?.toString() ?? ''
|
|
30
30
|
|
|
31
31
|
if (output.length > MAX_STRING_LENGTH) {
|
|
@@ -65,6 +65,6 @@ export function timeTag(dateTime: <%= parsedDateTime ? 'Date' : 'string' %> | un
|
|
|
65
65
|
return output
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export const checkboxInputTag = (checked: boolean) => {
|
|
69
|
-
return <input type="checkbox" checked={checked} disabled />
|
|
68
|
+
export const checkboxInputTag = (checked: boolean | null | undefined) => {
|
|
69
|
+
return <input type="checkbox" checked={!!checked} disabled />
|
|
70
70
|
}
|
|
@@ -19,7 +19,11 @@ import {
|
|
|
19
19
|
getEnum,
|
|
20
20
|
verifyModelName
|
|
21
21
|
} from "../../../lib/schemaHelpers.js";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
DEFAULT_IGNORE_FIELDS_FOR_INPUT,
|
|
24
|
+
redactedModelFields,
|
|
25
|
+
relationsForModel
|
|
26
|
+
} from "../helpers.js";
|
|
23
27
|
import { files as serviceFiles } from "../service/serviceHandler.js";
|
|
24
28
|
import { templateForFile } from "../yargsHandlerHelpers.js";
|
|
25
29
|
import {
|
|
@@ -27,7 +31,6 @@ import {
|
|
|
27
31
|
missingRelatedModels,
|
|
28
32
|
writeFilesWithStubsTask
|
|
29
33
|
} from "./stubFiles.js";
|
|
30
|
-
const DEFAULT_IGNORE_FIELDS_FOR_INPUT = ["createdAt", "updatedAt"];
|
|
31
34
|
const missingIdConsoleMessage = () => {
|
|
32
35
|
const line1 = ansis.bold.yellow("WARNING") + ": Cannot generate CRUD SDL without an `@id` database column.";
|
|
33
36
|
const line2 = "If you are trying to generate for a many-to-many join table ";
|
|
@@ -61,7 +64,8 @@ const modelFieldToSDL = ({
|
|
|
61
64
|
Bytes: "Byte"
|
|
62
65
|
};
|
|
63
66
|
const gqlType = prismaTypeToGraphqlType[field.type] || field.type;
|
|
64
|
-
const
|
|
67
|
+
const listItemType = field.kind === "object" ? gqlType : `${gqlType}!`;
|
|
68
|
+
const type = field.isList ? `[${listItemType}]` : gqlType;
|
|
65
69
|
const isRequired = field.isRequired && required || field.isList || field.isId;
|
|
66
70
|
const fieldContent = `${field.name}: ${type}${isRequired ? "!" : ""}`;
|
|
67
71
|
if (docs) {
|
|
@@ -332,6 +336,7 @@ const handler = async ({
|
|
|
332
336
|
export {
|
|
333
337
|
files,
|
|
334
338
|
handler,
|
|
339
|
+
modelFieldToSDL,
|
|
335
340
|
printRedactedFieldsNote,
|
|
336
341
|
redactedSensitiveFields,
|
|
337
342
|
stubFiles
|
|
@@ -3,7 +3,14 @@ import camelcase from "camelcase";
|
|
|
3
3
|
import { pluralize, singularize } from "@cedarjs/utils/cedarPluralize";
|
|
4
4
|
import { transformTSToJS } from "../../../lib/index.js";
|
|
5
5
|
import { getSchema, verifyModelName } from "../../../lib/schemaHelpers.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_IGNORE_FIELDS_FOR_INPUT,
|
|
8
|
+
nullableJsonFieldsInInput,
|
|
9
|
+
nullableRelationsForModel,
|
|
10
|
+
redactedModelFields,
|
|
11
|
+
relationsForModel,
|
|
12
|
+
requiredFieldsInUpdateInput
|
|
13
|
+
} from "../helpers.js";
|
|
7
14
|
import { createHandler, templateForFile } from "../yargsHandlerHelpers.js";
|
|
8
15
|
function isServiceModel(schema) {
|
|
9
16
|
return typeof schema === "object" && schema !== null && "fields" in schema && "name" in schema;
|
|
@@ -59,11 +66,13 @@ function scenarioFieldValue(field) {
|
|
|
59
66
|
return randInt;
|
|
60
67
|
case "Json":
|
|
61
68
|
return { foo: "bar" };
|
|
62
|
-
case "String":
|
|
69
|
+
case "String": {
|
|
70
|
+
const isUnique = field.isUnique || field.isId;
|
|
63
71
|
if (field.name?.toLowerCase().includes("email")) {
|
|
64
|
-
return
|
|
72
|
+
return isUnique ? `foo${randInt}@bar.com` : "foo@bar.com";
|
|
65
73
|
}
|
|
66
|
-
return
|
|
74
|
+
return isUnique ? `String${randInt}` : "String";
|
|
75
|
+
}
|
|
67
76
|
case "Bytes":
|
|
68
77
|
return `new Uint8Array([${randIntArray}])`;
|
|
69
78
|
default: {
|
|
@@ -152,11 +161,14 @@ const fieldsToInput = async (model) => {
|
|
|
152
161
|
const modelName = camelcase(singularize(model));
|
|
153
162
|
const inputObj = {};
|
|
154
163
|
if (scalarFields.some(
|
|
155
|
-
(field) => redactedFields.includes(field.name)
|
|
164
|
+
(field) => redactedFields.includes(field.name) || DEFAULT_IGNORE_FIELDS_FOR_INPUT.includes(field.name) && !field.isUpdatedAt
|
|
156
165
|
)) {
|
|
157
166
|
return false;
|
|
158
167
|
}
|
|
159
168
|
scalarFields.forEach((field) => {
|
|
169
|
+
if (DEFAULT_IGNORE_FIELDS_FOR_INPUT.includes(field.name)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
160
172
|
if (foreignKeys.includes(field.name)) {
|
|
161
173
|
inputObj[field.name] = `scenario.${modelName}.two.${field.name}`;
|
|
162
174
|
} else {
|
|
@@ -174,7 +186,7 @@ const fieldsToUpdate = async (model) => {
|
|
|
174
186
|
const modelName = camelcase(singularize(model));
|
|
175
187
|
let field, newValue, fieldName;
|
|
176
188
|
const updatableFields = scalarFields.filter(
|
|
177
|
-
(scalar) => !redactedFields.includes(scalar.name)
|
|
189
|
+
(scalar) => !redactedFields.includes(scalar.name) && !DEFAULT_IGNORE_FIELDS_FOR_INPUT.includes(scalar.name)
|
|
178
190
|
);
|
|
179
191
|
field = updatableFields.find(
|
|
180
192
|
(scalar) => !foreignKeys.includes(scalar.name)
|
|
@@ -273,13 +285,19 @@ const files = async ({
|
|
|
273
285
|
}
|
|
274
286
|
const prismaImportSource = "src/lib/db";
|
|
275
287
|
let modelRelations;
|
|
288
|
+
let updateInputRequiredFields = [];
|
|
289
|
+
let nullableJsonFields = [];
|
|
290
|
+
let nullableRelations = [];
|
|
291
|
+
const schemaResult = await getSchema(model);
|
|
292
|
+
if (isServiceModel(schemaResult)) {
|
|
293
|
+
updateInputRequiredFields = requiredFieldsInUpdateInput(schemaResult);
|
|
294
|
+
nullableJsonFields = nullableJsonFieldsInInput(schemaResult);
|
|
295
|
+
nullableRelations = nullableRelationsForModel(schemaResult);
|
|
296
|
+
}
|
|
276
297
|
if (relations) {
|
|
277
298
|
modelRelations = relations;
|
|
278
|
-
} else {
|
|
279
|
-
|
|
280
|
-
if (isServiceModel(schemaResult)) {
|
|
281
|
-
modelRelations = relationsForModel(schemaResult);
|
|
282
|
-
}
|
|
299
|
+
} else if (isServiceModel(schemaResult)) {
|
|
300
|
+
modelRelations = relationsForModel(schemaResult);
|
|
283
301
|
}
|
|
284
302
|
const serviceFile = await templateForFile({
|
|
285
303
|
name,
|
|
@@ -292,6 +310,9 @@ const files = async ({
|
|
|
292
310
|
relations: modelRelations,
|
|
293
311
|
idName,
|
|
294
312
|
prismaImportSource,
|
|
313
|
+
updateInputRequiredFields,
|
|
314
|
+
nullableJsonFields,
|
|
315
|
+
nullableRelations,
|
|
295
316
|
...rest
|
|
296
317
|
}
|
|
297
318
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { QueryResolvers<% if (crud) { %>, MutationResolvers<% } %><% if (relations.length) { %>, ${singularPascalName}RelationResolvers<% } %> } from 'types/graphql'
|
|
2
2
|
|
|
3
|
-
import { db } from 'src/lib/db'
|
|
3
|
+
import { db<% if (crud && nullableJsonFields.length) { %>, Prisma<% } %> } from 'src/lib/db'
|
|
4
4
|
<%
|
|
5
5
|
// A compound `@@id([...])` key comes through as `{ fields, whereArg }`
|
|
6
6
|
// instead of a single field name -- build the destructure/where-clause
|
|
@@ -13,8 +13,8 @@ import { db } from 'src/lib/db'
|
|
|
13
13
|
? `${idName.whereArg}: { ${idFields.join(', ')} }`
|
|
14
14
|
: idName
|
|
15
15
|
const idWhereFromRoot = idIsComposite
|
|
16
|
-
? `${idName.whereArg}: { ${idFields.map((f) => `${f}: root
|
|
17
|
-
: `${idName}: root
|
|
16
|
+
? `${idName.whereArg}: { ${idFields.map((f) => `${f}: root.${f}`).join(', ')} }`
|
|
17
|
+
: `${idName}: root.${idName}`
|
|
18
18
|
%>
|
|
19
19
|
export const ${pluralCamelName}: QueryResolvers['${pluralCamelName}'] = () => {
|
|
20
20
|
return db.${singularCamelName}.findMany()
|
|
@@ -27,14 +27,27 @@ export const ${singularCamelName}: QueryResolvers['${singularCamelName}'] = ({ $
|
|
|
27
27
|
}<% } %><% if (crud) { %>
|
|
28
28
|
|
|
29
29
|
export const create${singularPascalName}: MutationResolvers['create${singularPascalName}'] = ({ input }) => {
|
|
30
|
-
return db.${singularCamelName}.create({
|
|
31
|
-
data:
|
|
30
|
+
return db.${singularCamelName}.create({<% if (nullableJsonFields.length) { %>
|
|
31
|
+
data: {
|
|
32
|
+
...input,
|
|
33
|
+
// Prisma uses Prisma.DbNull, not null, to set a Json field to NULL<% nullableJsonFields.forEach((field) => { %>
|
|
34
|
+
${field}: input.${field} === null ? Prisma.DbNull : input.${field},<% }) %>
|
|
35
|
+
},<% } else { %>
|
|
36
|
+
data: input,<% } %>
|
|
32
37
|
})
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
export const update${singularPascalName}: MutationResolvers['update${singularPascalName}'] = ({ ${idArgs}, input }) => {
|
|
36
|
-
return db.${singularCamelName}.update({
|
|
37
|
-
data:
|
|
41
|
+
return db.${singularCamelName}.update({<% if (updateInputRequiredFields.length || nullableJsonFields.length) { %>
|
|
42
|
+
data: {
|
|
43
|
+
...input,<% if (updateInputRequiredFields.length) { %>
|
|
44
|
+
// Every field in the GraphQL input is nullable, but Prisma doesn't
|
|
45
|
+
// accept null for required fields. undefined leaves the field unchanged<% updateInputRequiredFields.forEach((field) => { %>
|
|
46
|
+
${field}: input.${field} ?? undefined,<% }) %><% } %><% if (nullableJsonFields.length) { %>
|
|
47
|
+
// Prisma uses Prisma.DbNull, not null, to set a Json field to NULL<% nullableJsonFields.forEach((field) => { %>
|
|
48
|
+
${field}: input.${field} === null ? Prisma.DbNull : input.${field},<% }) %><% } %>
|
|
49
|
+
},<% } else { %>
|
|
50
|
+
data: input,<% } %>
|
|
38
51
|
where: { ${idWhere} },
|
|
39
52
|
})
|
|
40
53
|
}
|
|
@@ -47,6 +60,6 @@ export const delete${singularPascalName}: MutationResolvers['delete${singularPas
|
|
|
47
60
|
|
|
48
61
|
export const ${singularPascalName}: ${singularPascalName}RelationResolvers = {<% relations.forEach(relation => { %>
|
|
49
62
|
${relation}: (_obj, { root }) => {
|
|
50
|
-
return db.${singularCamelName}.findUnique({ where: { ${idWhereFromRoot} } }).${relation}()
|
|
63
|
+
return db.${singularCamelName}.findUnique<%= nullableRelations.includes(relation) ? '' : 'OrThrow' %>({ where: { ${idWhereFromRoot} } }).${relation}()
|
|
51
64
|
},<% }) %>
|
|
52
65
|
}<% } %>
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
// Looks for quoted strings, either by single (') or double (") quotes.
|
|
8
8
|
// When found
|
|
9
9
|
// - Removes the quotes around `scenario` variables.
|
|
10
|
-
// - Removes the quotes around `BigInt` fields.
|
|
11
|
-
|
|
10
|
+
// - Removes the quotes around `BigInt` fields. GraphQL inputs type BigInt
|
|
11
|
+
// values as numbers, so the `n` suffix is also removed when `asInput` is
|
|
12
|
+
// set
|
|
13
|
+
const transformValue = (obj, type, asInput = false) => {
|
|
12
14
|
if (type === 'DateTime') {
|
|
13
15
|
return `new Date('${obj.toISOString()}')`
|
|
14
16
|
} else if (type === 'Decimal') {
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
|
|
23
25
|
// BigInt
|
|
24
26
|
if (string.match(/^\"\d+n\"$/)) {
|
|
25
|
-
return string.slice(1, string.length - 1)
|
|
27
|
+
return string.slice(1, string.length - (asInput ? 2 : 1))
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
return string
|
|
@@ -57,7 +59,7 @@ describe('${pluralCamelName}', () => {
|
|
|
57
59
|
|
|
58
60
|
<% if (create) { %>scenario('creates a ${singularCamelName}', async (${transformValue(create).includes('scenario.') ? 'scenario: StandardScenario' : ''}) => {
|
|
59
61
|
const result = await create${singularPascalName}({
|
|
60
|
-
input: ${transformValue(create)},
|
|
62
|
+
input: ${transformValue(create, undefined, true)},
|
|
61
63
|
})
|
|
62
64
|
|
|
63
65
|
<% for (const [name, value] of Object.entries(create)) { %>
|
|
@@ -68,7 +70,7 @@ describe('${pluralCamelName}', () => {
|
|
|
68
70
|
const original = await (${singularCamelName}({ ${idName}: scenario.${singularCamelName}.one.${idName} })) as ${prismaModel}
|
|
69
71
|
const result = await update${singularPascalName}({
|
|
70
72
|
${idName}: original.${idName},
|
|
71
|
-
input: ${transformValue(update)},
|
|
73
|
+
input: ${transformValue(update, undefined, true)},
|
|
72
74
|
})
|
|
73
75
|
|
|
74
76
|
<% for (const [name, value] of Object.entries(update)) { %>
|
|
@@ -7,9 +7,11 @@ const handler = async ({
|
|
|
7
7
|
commands: _commands,
|
|
8
8
|
...options
|
|
9
9
|
}) => {
|
|
10
|
-
const positionalArgs = Array.isArray(_) ?
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const positionalArgs = (Array.isArray(_) ? _ : []).map(String);
|
|
11
|
+
if (positionalArgs[0] === "jobs") {
|
|
12
|
+
positionalArgs.shift();
|
|
13
|
+
}
|
|
14
|
+
const args = positionalArgs.length > 0 ? positionalArgs : [""];
|
|
13
15
|
for (const [name, value] of Object.entries(options)) {
|
|
14
16
|
args.push(name.length > 1 ? `--${name}` : `-${name}`);
|
|
15
17
|
args.push(String(value));
|
|
@@ -10,21 +10,18 @@ const memJsFormattedLogger = {
|
|
|
10
10
|
log: (msg: string) => logger.error(msg),
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// The client connects to Memcached the first time it's used. If it can't
|
|
14
|
+
// connect, the error is logged and `cache()` runs the uncached function
|
|
15
|
+
// instead
|
|
16
|
+
export const client =
|
|
17
|
+
process.env.NODE_ENV === 'test'
|
|
18
|
+
? new InMemoryClient()
|
|
19
|
+
: new MemcachedClient(process.env.CACHE_HOST, {
|
|
20
|
+
logger: memJsFormattedLogger,
|
|
21
|
+
})
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
client
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
logger: memJsFormattedLogger,
|
|
21
|
-
})
|
|
22
|
-
} catch (e) {
|
|
23
|
-
logger.error(`Could not connect to cache: ${e.message}`)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const { cache, cacheFindMany, cacheClient, deleteCacheKey } = createCache(client, {
|
|
28
|
-
logger,
|
|
29
|
-
timeout: 500,
|
|
30
|
-
})
|
|
23
|
+
export const { cache, cacheFindMany, cacheClient, deleteCacheKey } =
|
|
24
|
+
createCache(client, {
|
|
25
|
+
logger,
|
|
26
|
+
timeout: 500,
|
|
27
|
+
})
|
|
@@ -1,24 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createCache,
|
|
3
|
-
InMemoryClient,
|
|
4
|
-
RedisClient,
|
|
5
|
-
} from '@cedarjs/api/cache'
|
|
1
|
+
import { createCache, InMemoryClient, RedisClient } from '@cedarjs/api/cache'
|
|
6
2
|
|
|
7
3
|
import { logger } from './logger'
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
// The client connects to Redis the first time it's used. If it can't connect,
|
|
6
|
+
// the error is logged and `cache()` runs the uncached function instead
|
|
7
|
+
export const client =
|
|
8
|
+
process.env.NODE_ENV === 'test'
|
|
9
|
+
? new InMemoryClient()
|
|
10
|
+
: new RedisClient({ url: process.env.CACHE_HOST, logger })
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
client
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} catch (e) {
|
|
17
|
-
logger.error(`Could not connect to cache: ${e.message}`)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const { cache, cacheFindMany, cacheClient, deleteCacheKey } = createCache(client, {
|
|
22
|
-
logger,
|
|
23
|
-
timeout: 500,
|
|
24
|
-
})
|
|
12
|
+
export const { cache, cacheFindMany, cacheClient, deleteCacheKey } =
|
|
13
|
+
createCache(client, {
|
|
14
|
+
logger,
|
|
15
|
+
timeout: 500,
|
|
16
|
+
})
|
|
@@ -131,7 +131,9 @@ function insertPluginsBeforeCedar({
|
|
|
131
131
|
if (!configArg) {
|
|
132
132
|
return null;
|
|
133
133
|
}
|
|
134
|
-
const pluginsProp = configArg.properties.find(
|
|
134
|
+
const pluginsProp = configArg.properties.find(
|
|
135
|
+
(prop) => t.isObjectProperty(prop) && (!prop.computed && t.isIdentifier(prop.key, { name: "plugins" }) || t.isStringLiteral(prop.key, { value: "plugins" }))
|
|
136
|
+
);
|
|
135
137
|
if (!t.isArrayExpression(pluginsProp?.value)) {
|
|
136
138
|
return null;
|
|
137
139
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { MONITORS } from "../../../deploy/baremetal/monitors.js";
|
|
1
2
|
import { createHandler } from "../helpers/helpers.js";
|
|
2
3
|
const command = "baremetal";
|
|
3
4
|
const description = "Setup Baremetal deploy";
|
|
5
|
+
const builder = (yargs) => yargs.option("monitor", {
|
|
6
|
+
description: "Process monitor to generate config for. Asks when not given. pm2 gets an ecosystem.config.js, systemd gets unit files in systemd/",
|
|
7
|
+
choices: MONITORS,
|
|
8
|
+
type: "string"
|
|
9
|
+
});
|
|
4
10
|
const handler = createHandler("baremetal");
|
|
5
11
|
export {
|
|
12
|
+
builder,
|
|
6
13
|
command,
|
|
7
14
|
description,
|
|
8
15
|
handler
|