@nixxie-cms/core 1.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/CHANGELOG.md +3158 -0
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-id-field-view.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-id-field-view.cjs.js +244 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-id-field-view.esm.js +235 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-App.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-App.cjs.js +59 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-App.esm.js +55 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-CreateItemPage.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-CreateItemPage.cjs.js +116 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-CreateItemPage.esm.js +112 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-HomePage.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-HomePage.cjs.js +336 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-HomePage.esm.js +332 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ItemPage.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ItemPage.cjs.js +463 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ItemPage.esm.js +455 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ListPage.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ListPage.cjs.js +1195 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-ListPage.esm.js +1187 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-NoAccessPage.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-NoAccessPage.cjs.js +40 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-admin-ui-pages-NoAccessPage.esm.js +35 -0
- package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +4 -0
- package/___internal-do-not-use-will-break-in-patch/artifacts/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-artifacts.cjs.d.ts +2 -0
- package/___internal-do-not-use-will-break-in-patch/artifacts/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-artifacts.cjs.js +51 -0
- package/___internal-do-not-use-will-break-in-patch/artifacts/dist/nixxie-cms-core-___internal-do-not-use-will-break-in-patch-artifacts.esm.js +38 -0
- package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +4 -0
- package/access/dist/nixxie-cms-core-access.cjs.d.ts +2 -0
- package/access/dist/nixxie-cms-core-access.cjs.js +26 -0
- package/access/dist/nixxie-cms-core-access.esm.js +19 -0
- package/access/package.json +4 -0
- package/admin-ui/apollo/dist/nixxie-cms-core-admin-ui-apollo.cjs.d.ts +2 -0
- package/admin-ui/apollo/dist/nixxie-cms-core-admin-ui-apollo.cjs.js +87 -0
- package/admin-ui/apollo/dist/nixxie-cms-core-admin-ui-apollo.esm.js +2 -0
- package/admin-ui/apollo/package.json +4 -0
- package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.d.ts +2 -0
- package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +77 -0
- package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +58 -0
- package/admin-ui/components/package.json +4 -0
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.d.ts +2 -0
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +35 -0
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +23 -0
- package/admin-ui/context/package.json +4 -0
- package/admin-ui/image/dist/nixxie-cms-core-admin-ui-image.cjs.d.ts +3 -0
- package/admin-ui/image/dist/nixxie-cms-core-admin-ui-image.cjs.js +18 -0
- package/admin-ui/image/dist/nixxie-cms-core-admin-ui-image.esm.js +2 -0
- package/admin-ui/image/package.json +4 -0
- package/admin-ui/router/dist/nixxie-cms-core-admin-ui-router.cjs.d.ts +2 -0
- package/admin-ui/router/dist/nixxie-cms-core-admin-ui-router.cjs.js +34 -0
- package/admin-ui/router/dist/nixxie-cms-core-admin-ui-router.esm.js +12 -0
- package/admin-ui/router/package.json +4 -0
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.cjs.d.ts +2 -0
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.cjs.js +45 -0
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.esm.js +22 -0
- package/admin-ui/utils/package.json +4 -0
- package/bin/cli.js +3 -0
- package/context/dist/nixxie-cms-core-context.cjs.d.ts +2 -0
- package/context/dist/nixxie-cms-core-context.cjs.js +31 -0
- package/context/dist/nixxie-cms-core-context.esm.js +23 -0
- package/context/package.json +4 -0
- package/dist/CreateItemDialog-33335548.esm.js +55 -0
- package/dist/CreateItemDialog-56cf59b7.cjs.js +57 -0
- package/dist/Errors-575adfa3.cjs.js +147 -0
- package/dist/Errors-bf24759e.esm.js +143 -0
- package/dist/Field-47f85161.esm.js +278 -0
- package/dist/Field-ed8d7627.cjs.js +287 -0
- package/dist/Fields-956d9a14.esm.js +203 -0
- package/dist/Fields-e2c28056.cjs.js +206 -0
- package/dist/GraphQLErrorNotice-cd74180d.cjs.js +57 -0
- package/dist/GraphQLErrorNotice-d9f0931b.esm.js +55 -0
- package/dist/NullableFieldWrapper-6ea48af3.esm.js +71 -0
- package/dist/NullableFieldWrapper-daa0a080.cjs.js +74 -0
- package/dist/PageContainer-27c27f10.cjs.js +1144 -0
- package/dist/PageContainer-7db73317.esm.js +1129 -0
- package/dist/actionData-64d4c37a.esm.js +28 -0
- package/dist/actionData-7858738d.cjs.js +32 -0
- package/dist/admin-meta-14c60fec.esm.js +210 -0
- package/dist/admin-meta-18d0c276.cjs.js +217 -0
- package/dist/admin-meta-graphql-6f7f5331.esm.js +142 -0
- package/dist/admin-meta-graphql-c8f926e9.cjs.js +144 -0
- package/dist/common-1a350e11.cjs.js +324 -0
- package/dist/common-29fc82e6.esm.js +315 -0
- package/dist/context-3132c3ed.esm.js +419 -0
- package/dist/context-e7a45152.cjs.js +432 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts +6 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts +10 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts +6 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts +2 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts +6 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts +12 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts +7 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +1 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts +6 -0
- package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +1 -0
- package/dist/declarations/src/access.d.ts +12 -0
- package/dist/declarations/src/access.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/apollo.d.ts +8 -0
- package/dist/declarations/src/admin-ui/apollo.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/CellContainer.d.ts +5 -0
- package/dist/declarations/src/admin-ui/components/CellContainer.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/CreateItemDialog.d.ts +5 -0
- package/dist/declarations/src/admin-ui/components/CreateItemDialog.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/Errors.d.ts +28 -0
- package/dist/declarations/src/admin-ui/components/Errors.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/GraphQLErrorNotice.d.ts +6 -0
- package/dist/declarations/src/admin-ui/components/GraphQLErrorNotice.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/InlineCode.d.ts +3 -0
- package/dist/declarations/src/admin-ui/components/InlineCode.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/Logo.d.ts +2 -0
- package/dist/declarations/src/admin-ui/components/Logo.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts +22 -0
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/NullableFieldWrapper.d.ts +33 -0
- package/dist/declarations/src/admin-ui/components/NullableFieldWrapper.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/PageContainer.d.ts +10 -0
- package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/components/index.d.ts +11 -0
- package/dist/declarations/src/admin-ui/components/index.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/context.d.ts +50 -0
- package/dist/declarations/src/admin-ui/context.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/image.d.ts +3 -0
- package/dist/declarations/src/admin-ui/image.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/router.d.ts +15 -0
- package/dist/declarations/src/admin-ui/router.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts +16 -0
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/utils/filters.d.ts +10 -0
- package/dist/declarations/src/admin-ui/utils/filters.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/utils/index.d.ts +8 -0
- package/dist/declarations/src/admin-ui/utils/index.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts +24 -0
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -0
- package/dist/declarations/src/admin-ui/utils/utils.d.ts +8 -0
- package/dist/declarations/src/admin-ui/utils/utils.d.ts.map +1 -0
- package/dist/declarations/src/artifacts.d.ts +14 -0
- package/dist/declarations/src/artifacts.d.ts.map +1 -0
- package/dist/declarations/src/context.d.ts +2 -0
- package/dist/declarations/src/context.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/enum-filter.d.ts +27 -0
- package/dist/declarations/src/fields/filters/enum-filter.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/index.d.ts +2 -0
- package/dist/declarations/src/fields/filters/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/internal.d.ts +21 -0
- package/dist/declarations/src/fields/filters/internal.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/providers/mysql.d.ts +182 -0
- package/dist/declarations/src/fields/filters/providers/mysql.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/providers/postgresql.d.ts +182 -0
- package/dist/declarations/src/fields/filters/providers/postgresql.d.ts.map +1 -0
- package/dist/declarations/src/fields/filters/providers/sqlite.d.ts +179 -0
- package/dist/declarations/src/fields/filters/providers/sqlite.d.ts.map +1 -0
- package/dist/declarations/src/fields/index.d.ts +35 -0
- package/dist/declarations/src/fields/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/bigInt/index.d.ts +20 -0
- package/dist/declarations/src/fields/types/bigInt/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts +24 -0
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/bytes/index.d.ts +70 -0
- package/dist/declarations/src/fields/types/bytes/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts +24 -0
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts +15 -0
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/calendarDay/views/index.d.ts +18 -0
- package/dist/declarations/src/fields/types/calendarDay/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/checkbox/index.d.ts +11 -0
- package/dist/declarations/src/fields/types/checkbox/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/checkbox/views/index.d.ts +9 -0
- package/dist/declarations/src/fields/types/checkbox/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/decimal/index.d.ts +20 -0
- package/dist/declarations/src/fields/types/decimal/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts +22 -0
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/file/index.d.ts +34 -0
- package/dist/declarations/src/fields/types/file/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/file/views/Field.d.ts +17 -0
- package/dist/declarations/src/fields/types/file/views/Field.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/file/views/index.d.ts +29 -0
- package/dist/declarations/src/fields/types/file/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/float/index.d.ts +18 -0
- package/dist/declarations/src/fields/types/float/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/float/views/index.d.ts +22 -0
- package/dist/declarations/src/fields/types/float/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/image/index.d.ts +34 -0
- package/dist/declarations/src/fields/types/image/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/image/utils.d.ts +2 -0
- package/dist/declarations/src/fields/types/image/utils.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/image/views/Field.d.ts +4 -0
- package/dist/declarations/src/fields/types/image/views/Field.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/image/views/index.d.ts +49 -0
- package/dist/declarations/src/fields/types/image/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/integer/index.d.ts +20 -0
- package/dist/declarations/src/fields/types/integer/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/integer/views/index.d.ts +23 -0
- package/dist/declarations/src/fields/types/integer/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/json/index.d.ts +25 -0
- package/dist/declarations/src/fields/types/json/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/json/views/index.d.ts +9 -0
- package/dist/declarations/src/fields/types/json/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/multiselect/index.d.ts +50 -0
- package/dist/declarations/src/fields/types/multiselect/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts +26 -0
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/password/index.d.ts +49 -0
- package/dist/declarations/src/fields/types/password/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/password/views/index.d.ts +47 -0
- package/dist/declarations/src/fields/types/password/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/relationship/index.d.ts +113 -0
- package/dist/declarations/src/fields/types/relationship/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts +26 -0
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts +24 -0
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts +27 -0
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts +39 -0
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/select/index.d.ts +42 -0
- package/dist/declarations/src/fields/types/select/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/select/views/index.d.ts +32 -0
- package/dist/declarations/src/fields/types/select/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/text/index.d.ts +58 -0
- package/dist/declarations/src/fields/types/text/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/text/views/index.d.ts +36 -0
- package/dist/declarations/src/fields/types/text/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/timestamp/index.d.ts +19 -0
- package/dist/declarations/src/fields/types/timestamp/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/timestamp/views/index.d.ts +14 -0
- package/dist/declarations/src/fields/types/timestamp/views/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/timestamp/views/utils.d.ts +14 -0
- package/dist/declarations/src/fields/types/timestamp/views/utils.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/virtual/index.d.ts +40 -0
- package/dist/declarations/src/fields/types/virtual/index.d.ts.map +1 -0
- package/dist/declarations/src/fields/types/virtual/views/index.d.ts +7 -0
- package/dist/declarations/src/fields/types/virtual/views/index.d.ts.map +1 -0
- package/dist/declarations/src/graphql-ts.d.ts +5 -0
- package/dist/declarations/src/graphql-ts.d.ts.map +1 -0
- package/dist/declarations/src/helpers.d.ts +121 -0
- package/dist/declarations/src/helpers.d.ts.map +1 -0
- package/dist/declarations/src/index.d.ts +6 -0
- package/dist/declarations/src/index.d.ts.map +1 -0
- package/dist/declarations/src/lib/admin-meta.d.ts +71 -0
- package/dist/declarations/src/lib/admin-meta.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/access-control.d.ts +39 -0
- package/dist/declarations/src/lib/core/access-control.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/initialise-lists.d.ts +131 -0
- package/dist/declarations/src/lib/core/initialise-lists.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/resolve-relationships.d.ts +30 -0
- package/dist/declarations/src/lib/core/resolve-relationships.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/where-inputs.d.ts +15 -0
- package/dist/declarations/src/lib/core/where-inputs.d.ts.map +1 -0
- package/dist/declarations/src/lib/express.d.ts +10 -0
- package/dist/declarations/src/lib/express.d.ts.map +1 -0
- package/dist/declarations/src/lib/migrations.d.ts +13 -0
- package/dist/declarations/src/lib/migrations.d.ts.map +1 -0
- package/dist/declarations/src/lib/system.d.ts +35 -0
- package/dist/declarations/src/lib/system.d.ts.map +1 -0
- package/dist/declarations/src/schema.d.ts +40 -0
- package/dist/declarations/src/schema.d.ts.map +1 -0
- package/dist/declarations/src/scripts/cli.d.ts +11 -0
- package/dist/declarations/src/scripts/cli.d.ts.map +1 -0
- package/dist/declarations/src/scripts/index.d.ts +2 -0
- package/dist/declarations/src/scripts/index.d.ts.map +1 -0
- package/dist/declarations/src/scripts/utils.d.ts +7 -0
- package/dist/declarations/src/scripts/utils.d.ts.map +1 -0
- package/dist/declarations/src/session.d.ts +86 -0
- package/dist/declarations/src/session.d.ts.map +1 -0
- package/dist/declarations/src/testing.d.ts +2 -0
- package/dist/declarations/src/testing.d.ts.map +1 -0
- package/dist/declarations/src/types/admin-meta.d.ts +190 -0
- package/dist/declarations/src/types/admin-meta.d.ts.map +1 -0
- package/dist/declarations/src/types/config/access-control.d.ts +108 -0
- package/dist/declarations/src/types/config/access-control.d.ts.map +1 -0
- package/dist/declarations/src/types/config/fields.d.ts +67 -0
- package/dist/declarations/src/types/config/fields.d.ts.map +1 -0
- package/dist/declarations/src/types/config/hooks.d.ts +441 -0
- package/dist/declarations/src/types/config/hooks.d.ts.map +1 -0
- package/dist/declarations/src/types/config/index.d.ts +283 -0
- package/dist/declarations/src/types/config/index.d.ts.map +1 -0
- package/dist/declarations/src/types/config/lists.d.ts +430 -0
- package/dist/declarations/src/types/config/lists.d.ts.map +1 -0
- package/dist/declarations/src/types/context.d.ts +458 -0
- package/dist/declarations/src/types/context.d.ts.map +1 -0
- package/dist/declarations/src/types/core.d.ts +9 -0
- package/dist/declarations/src/types/core.d.ts.map +1 -0
- package/dist/declarations/src/types/index.d.ts +9 -0
- package/dist/declarations/src/types/index.d.ts.map +1 -0
- package/dist/declarations/src/types/next-fields.d.ts +308 -0
- package/dist/declarations/src/types/next-fields.d.ts.map +1 -0
- package/dist/declarations/src/types/prisma.d.ts +13 -0
- package/dist/declarations/src/types/prisma.d.ts.map +1 -0
- package/dist/declarations/src/types/schema/g.d.ts +7 -0
- package/dist/declarations/src/types/schema/g.d.ts.map +1 -0
- package/dist/declarations/src/types/schema/gWithContext.d.ts +12 -0
- package/dist/declarations/src/types/schema/gWithContext.d.ts.map +1 -0
- package/dist/declarations/src/types/schema/index.d.ts +4 -0
- package/dist/declarations/src/types/schema/index.d.ts.map +1 -0
- package/dist/declarations/src/types/schema/legacy-alias.d.ts +28 -0
- package/dist/declarations/src/types/schema/scalars.d.ts +22 -0
- package/dist/declarations/src/types/schema/scalars.d.ts.map +1 -0
- package/dist/declarations/src/types/session.d.ts +28 -0
- package/dist/declarations/src/types/session.d.ts.map +1 -0
- package/dist/declarations/src/types/type-info.d.ts +35 -0
- package/dist/declarations/src/types/type-info.d.ts.map +1 -0
- package/dist/declarations/src/types/utils.d.ts +78 -0
- package/dist/declarations/src/types/utils.d.ts.map +1 -0
- package/dist/declarations/types/dist/nixxie-cms-core-types.cjs.d.ts +2 -0
- package/dist/express-6743b918.esm.js +476 -0
- package/dist/express-e9ed9a7d.cjs.js +495 -0
- package/dist/filters-8c8616f9.esm.js +89 -0
- package/dist/filters-b3e5eb50.cjs.js +96 -0
- package/dist/index-24b78415.esm.js +419 -0
- package/dist/index-ac01583b.cjs.js +425 -0
- package/dist/migrations-996e66a0.esm.js +76 -0
- package/dist/migrations-ab2e0fd4.cjs.js +78 -0
- package/dist/next-fields-49c025ef.cjs.js +251 -0
- package/dist/next-fields-9bf04ed8.esm.js +241 -0
- package/dist/nixxie-cms-core.cjs.d.ts +2 -0
- package/dist/nixxie-cms-core.cjs.js +522 -0
- package/dist/nixxie-cms-core.esm.js +504 -0
- package/dist/non-null-graphql-17b83ddc.cjs.js +72 -0
- package/dist/non-null-graphql-5315718c.esm.js +67 -0
- package/dist/pick-5fe45878.cjs.js +71 -0
- package/dist/pick-b7ef3115.esm.js +68 -0
- package/dist/resolve-hooks-17aafd37.esm.js +2026 -0
- package/dist/resolve-hooks-66fe8a8e.cjs.js +2043 -0
- package/dist/system-48c5f6df.cjs.js +4283 -0
- package/dist/system-dfec2f0a.esm.js +4273 -0
- package/dist/useCreateItem-1be4987e.cjs.js +160 -0
- package/dist/useCreateItem-1f94d252.esm.js +157 -0
- package/dist/useFilter-0b5a1ee6.esm.js +118 -0
- package/dist/useFilter-1a4e6900.cjs.js +120 -0
- package/dist/utils-0cc426c8.esm.js +19 -0
- package/dist/utils-1b632a8f.cjs.js +21 -0
- package/dist/utils-230cddb1.cjs.js +150 -0
- package/dist/utils-5e1d4d28.esm.js +138 -0
- package/dist/utils-b031e11c.cjs.js +49 -0
- package/dist/utils-e74e3527.cjs.js +87 -0
- package/dist/utils-ef2cd0f4.esm.js +80 -0
- package/dist/utils-f9556354.esm.js +41 -0
- package/fields/dist/nixxie-cms-core-fields.cjs.d.ts +2 -0
- package/fields/dist/nixxie-cms-core-fields.cjs.js +1808 -0
- package/fields/dist/nixxie-cms-core-fields.esm.js +1785 -0
- package/fields/package.json +4 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.cjs.d.ts +2 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.cjs.js +258 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.esm.js +253 -0
- package/fields/types/bigInt/views/package.json +4 -0
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.d.ts +2 -0
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +221 -0
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +216 -0
- package/fields/types/bytes/package.json +4 -0
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.d.ts +2 -0
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +239 -0
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +234 -0
- package/fields/types/bytes/views/package.json +4 -0
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.cjs.d.ts +2 -0
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.cjs.js +147 -0
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.esm.js +141 -0
- package/fields/types/calendarDay/views/package.json +4 -0
- package/fields/types/checkbox/views/dist/nixxie-cms-core-fields-types-checkbox-views.cjs.d.ts +2 -0
- package/fields/types/checkbox/views/dist/nixxie-cms-core-fields-types-checkbox-views.cjs.js +126 -0
- package/fields/types/checkbox/views/dist/nixxie-cms-core-fields-types-checkbox-views.esm.js +120 -0
- package/fields/types/checkbox/views/package.json +4 -0
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.cjs.d.ts +2 -0
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.cjs.js +248 -0
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.esm.js +239 -0
- package/fields/types/decimal/views/package.json +4 -0
- package/fields/types/file/utils/package.json +4 -0
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.cjs.d.ts +2 -0
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.cjs.js +86 -0
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.esm.js +81 -0
- package/fields/types/file/views/package.json +4 -0
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.cjs.d.ts +2 -0
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.cjs.js +237 -0
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.esm.js +232 -0
- package/fields/types/float/views/package.json +4 -0
- package/fields/types/image/utils/dist/nixxie-cms-core-fields-types-image-utils.cjs.d.ts +2 -0
- package/fields/types/image/utils/dist/nixxie-cms-core-fields-types-image-utils.cjs.js +7 -0
- package/fields/types/image/utils/dist/nixxie-cms-core-fields-types-image-utils.esm.js +3 -0
- package/fields/types/image/utils/package.json +4 -0
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.cjs.d.ts +2 -0
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.cjs.js +361 -0
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.esm.js +354 -0
- package/fields/types/image/views/package.json +4 -0
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.cjs.d.ts +2 -0
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.cjs.js +254 -0
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.esm.js +249 -0
- package/fields/types/integer/views/package.json +4 -0
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.cjs.d.ts +2 -0
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.cjs.js +83 -0
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.esm.js +77 -0
- package/fields/types/json/views/package.json +4 -0
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.d.ts +2 -0
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +147 -0
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +141 -0
- package/fields/types/multiselect/views/package.json +4 -0
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.d.ts +2 -0
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +206 -0
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +196 -0
- package/fields/types/password/package.json +4 -0
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.cjs.d.ts +2 -0
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.cjs.js +330 -0
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.esm.js +320 -0
- package/fields/types/password/views/package.json +4 -0
- package/fields/types/relationship/views/RelationshipSelect/package.json +4 -0
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.d.ts +2 -0
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +1213 -0
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +1201 -0
- package/fields/types/relationship/views/package.json +4 -0
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.d.ts +2 -0
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +422 -0
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +416 -0
- package/fields/types/select/views/package.json +4 -0
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.d.ts +2 -0
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +316 -0
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +311 -0
- package/fields/types/text/views/package.json +4 -0
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.cjs.d.ts +2 -0
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.cjs.js +285 -0
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.esm.js +279 -0
- package/fields/types/timestamp/views/package.json +4 -0
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.cjs.d.ts +2 -0
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.cjs.js +54 -0
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.esm.js +48 -0
- package/fields/types/virtual/views/package.json +4 -0
- package/graphql-ts/dist/nixxie-cms-core-graphql-ts.cjs.d.ts +2 -0
- package/graphql-ts/dist/nixxie-cms-core-graphql-ts.cjs.js +45 -0
- package/graphql-ts/dist/nixxie-cms-core-graphql-ts.esm.js +2 -0
- package/graphql-ts/package.json +4 -0
- package/package.json +339 -0
- package/schema/package.json +4 -0
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.d.ts +2 -0
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +1607 -0
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +1586 -0
- package/scripts/cli/package.json +4 -0
- package/scripts/dist/nixxie-cms-core-scripts.cjs.d.ts +2 -0
- package/scripts/dist/nixxie-cms-core-scripts.cjs.js +73 -0
- package/scripts/dist/nixxie-cms-core-scripts.esm.js +71 -0
- package/scripts/package.json +4 -0
- package/session/dist/nixxie-cms-core-session.cjs.d.ts +2 -0
- package/session/dist/nixxie-cms-core-session.cjs.js +157 -0
- package/session/dist/nixxie-cms-core-session.esm.js +129 -0
- package/session/package.json +4 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx +167 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx +22 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.tsx +71 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.tsx +333 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/common.tsx +358 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +483 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FilterAdd.tsx +221 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/PaginationControls.tsx +170 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/Tag.tsx +72 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +1006 -0
- package/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.tsx +24 -0
- package/src/___internal-do-not-use-will-break-in-patch/artifacts.ts +5 -0
- package/src/access.ts +25 -0
- package/src/admin-ui/admin-meta-graphql.ts +168 -0
- package/src/admin-ui/apollo.tsx +35 -0
- package/src/admin-ui/components/CellContainer.tsx +6 -0
- package/src/admin-ui/components/CommandPalette.tsx +431 -0
- package/src/admin-ui/components/Container.tsx +14 -0
- package/src/admin-ui/components/CreateButtonLink.tsx +46 -0
- package/src/admin-ui/components/CreateItemDialog.tsx +56 -0
- package/src/admin-ui/components/EmptyState.tsx +52 -0
- package/src/admin-ui/components/Errors.tsx +130 -0
- package/src/admin-ui/components/GraphQLErrorNotice.tsx +78 -0
- package/src/admin-ui/components/InlineCode.tsx +17 -0
- package/src/admin-ui/components/Logo.tsx +70 -0
- package/src/admin-ui/components/Navigation.tsx +385 -0
- package/src/admin-ui/components/NullableFieldWrapper.tsx +72 -0
- package/src/admin-ui/components/PageContainer.tsx +310 -0
- package/src/admin-ui/components/WelcomeDialog.tsx +119 -0
- package/src/admin-ui/components/index.ts +23 -0
- package/src/admin-ui/context.tsx +338 -0
- package/src/admin-ui/image.tsx +2 -0
- package/src/admin-ui/index.tsx +1 -0
- package/src/admin-ui/router.tsx +24 -0
- package/src/admin-ui/system/generateAdminUI.ts +155 -0
- package/src/admin-ui/system/index.ts +1 -0
- package/src/admin-ui/templates/app.ts +60 -0
- package/src/admin-ui/templates/create-item.ts +5 -0
- package/src/admin-ui/templates/home.ts +2 -0
- package/src/admin-ui/templates/index.ts +53 -0
- package/src/admin-ui/templates/item.tsx +5 -0
- package/src/admin-ui/templates/list.tsx +5 -0
- package/src/admin-ui/templates/next-config.ts +16 -0
- package/src/admin-ui/templates/no-access.ts +7 -0
- package/src/admin-ui/utils/Fields.tsx +241 -0
- package/src/admin-ui/utils/actionData.ts +36 -0
- package/src/admin-ui/utils/filters.ts +148 -0
- package/src/admin-ui/utils/index.ts +10 -0
- package/src/admin-ui/utils/pick.ts +12 -0
- package/src/admin-ui/utils/useCreateItem.ts +171 -0
- package/src/admin-ui/utils/usePreventNavigation.tsx +31 -0
- package/src/admin-ui/utils/utils.tsx +127 -0
- package/src/artifacts.ts +110 -0
- package/src/context.ts +1 -0
- package/src/fields/filters/enum-filter.ts +77 -0
- package/src/fields/filters/index.ts +1 -0
- package/src/fields/filters/internal.ts +89 -0
- package/src/fields/filters/providers/mysql.ts +450 -0
- package/src/fields/filters/providers/postgresql.ts +448 -0
- package/src/fields/filters/providers/sqlite.ts +442 -0
- package/src/fields/index.ts +34 -0
- package/src/fields/non-null-graphql.ts +115 -0
- package/src/fields/resolve-hooks.ts +61 -0
- package/src/fields/types/bigInt/index.ts +181 -0
- package/src/fields/types/bigInt/views/index.tsx +254 -0
- package/src/fields/types/bytes/index.ts +275 -0
- package/src/fields/types/bytes/views/index.tsx +190 -0
- package/src/fields/types/calendarDay/index.ts +194 -0
- package/src/fields/types/calendarDay/views/index.tsx +144 -0
- package/src/fields/types/checkbox/index.ts +76 -0
- package/src/fields/types/checkbox/views/index.tsx +97 -0
- package/src/fields/types/decimal/index.ts +182 -0
- package/src/fields/types/decimal/views/index.tsx +215 -0
- package/src/fields/types/file/index.ts +168 -0
- package/src/fields/types/file/views/Field.tsx +300 -0
- package/src/fields/types/file/views/index.tsx +74 -0
- package/src/fields/types/float/index.ts +133 -0
- package/src/fields/types/float/views/index.tsx +215 -0
- package/src/fields/types/image/index.ts +244 -0
- package/src/fields/types/image/internal-utils.ts +58 -0
- package/src/fields/types/image/utils.ts +1 -0
- package/src/fields/types/image/views/Field.tsx +295 -0
- package/src/fields/types/image/views/index.tsx +92 -0
- package/src/fields/types/integer/index.ts +156 -0
- package/src/fields/types/integer/views/index.tsx +255 -0
- package/src/fields/types/json/index.ts +77 -0
- package/src/fields/types/json/views/index.tsx +76 -0
- package/src/fields/types/multiselect/index.ts +212 -0
- package/src/fields/types/multiselect/views/index.tsx +151 -0
- package/src/fields/types/password/index.ts +241 -0
- package/src/fields/types/password/views/index.tsx +342 -0
- package/src/fields/types/relationship/index.ts +381 -0
- package/src/fields/types/relationship/views/ComboboxMany.tsx +110 -0
- package/src/fields/types/relationship/views/ComboboxSingle.tsx +115 -0
- package/src/fields/types/relationship/views/ContextualActions.tsx +139 -0
- package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -0
- package/src/fields/types/relationship/views/index.tsx +492 -0
- package/src/fields/types/relationship/views/types.ts +46 -0
- package/src/fields/types/relationship/views/useApolloQuery.ts +185 -0
- package/src/fields/types/relationship/views/useFilter.tsx +109 -0
- package/src/fields/types/select/index.ts +226 -0
- package/src/fields/types/select/views/SegmentedControl.tsx +83 -0
- package/src/fields/types/select/views/index.tsx +318 -0
- package/src/fields/types/text/index.ts +207 -0
- package/src/fields/types/text/views/index.tsx +273 -0
- package/src/fields/types/timestamp/index.ts +116 -0
- package/src/fields/types/timestamp/views/__tests__/index.tsx +68 -0
- package/src/fields/types/timestamp/views/__tests__/utils.tsx +16 -0
- package/src/fields/types/timestamp/views/index.tsx +262 -0
- package/src/fields/types/timestamp/views/utils.ts +22 -0
- package/src/fields/types/virtual/index.ts +108 -0
- package/src/fields/types/virtual/views/index.tsx +53 -0
- package/src/graphql-ts.ts +32 -0
- package/src/helpers.ts +316 -0
- package/src/index.ts +20 -0
- package/src/lib/admin-meta-graphql.ts +407 -0
- package/src/lib/admin-meta.ts +369 -0
- package/src/lib/coerceAndValidateForGraphQLInput.ts +29 -0
- package/src/lib/context/api.ts +99 -0
- package/src/lib/context/createContext.ts +161 -0
- package/src/lib/context/graphql.ts +300 -0
- package/src/lib/core/access-control.ts +434 -0
- package/src/lib/core/field-assertions.ts +118 -0
- package/src/lib/core/filter-order-access.ts +48 -0
- package/src/lib/core/graphql-errors.ts +76 -0
- package/src/lib/core/hooks.ts +111 -0
- package/src/lib/core/initialise-lists.ts +1097 -0
- package/src/lib/core/mutations/index.ts +917 -0
- package/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts +145 -0
- package/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts +71 -0
- package/src/lib/core/prisma-schema-printer.ts +256 -0
- package/src/lib/core/queries/index.ts +66 -0
- package/src/lib/core/queries/output-field.ts +178 -0
- package/src/lib/core/queries/resolvers.ts +258 -0
- package/src/lib/core/resolve-relationships.ts +303 -0
- package/src/lib/core/utils.ts +56 -0
- package/src/lib/core/where-inputs.ts +130 -0
- package/src/lib/express.ts +109 -0
- package/src/lib/graphql.ts +83 -0
- package/src/lib/id-field.ts +214 -0
- package/src/lib/middleware.ts +68 -0
- package/src/lib/migrations.ts +90 -0
- package/src/lib/otel.ts +43 -0
- package/src/lib/prompts.ts +29 -0
- package/src/lib/system.ts +207 -0
- package/src/lib/telemetry.ts +342 -0
- package/src/lib/typescript-schema-printer.ts +227 -0
- package/src/lib/utils.ts +21 -0
- package/src/pkg-dir.ts +6 -0
- package/src/schema.ts +233 -0
- package/src/scripts/build.ts +64 -0
- package/src/scripts/cli.ts +124 -0
- package/src/scripts/dev.ts +452 -0
- package/src/scripts/esbuild.ts +120 -0
- package/src/scripts/index.ts +20 -0
- package/src/scripts/migrate.ts +214 -0
- package/src/scripts/prisma.ts +49 -0
- package/src/scripts/start.ts +76 -0
- package/src/scripts/telemetry.ts +37 -0
- package/src/scripts/utils.ts +22 -0
- package/src/session.ts +168 -0
- package/src/testing.ts +23 -0
- package/src/types/admin-meta.ts +218 -0
- package/src/types/config/access-control.ts +186 -0
- package/src/types/config/fields.ts +96 -0
- package/src/types/config/hooks.ts +529 -0
- package/src/types/config/index.ts +333 -0
- package/src/types/config/lists.ts +565 -0
- package/src/types/context.ts +530 -0
- package/src/types/core.ts +16 -0
- package/src/types/index.ts +8 -0
- package/src/types/next-fields.ts +499 -0
- package/src/types/prisma.ts +16 -0
- package/src/types/schema/g.ts +5 -0
- package/src/types/schema/gWithContext.ts +20 -0
- package/src/types/schema/index.ts +4 -0
- package/src/types/schema/legacy-alias.d.ts +28 -0
- package/src/types/schema/legacy-alias.js +1 -0
- package/src/types/schema/scalars.ts +220 -0
- package/src/types/session.ts +26 -0
- package/src/types/telemetry.ts +51 -0
- package/src/types/type-info.ts +38 -0
- package/src/types/type-tests.ts +21 -0
- package/src/types/utils.ts +108 -0
- package/static/admin-error.html +53 -0
- package/static/dev-loading.html +146 -0
- package/static/favicon.ico +0 -0
- package/static/favicon.svg +4 -0
- package/system/package.json +4 -0
- package/testing/dist/nixxie-cms-core-testing.cjs.d.ts +2 -0
- package/testing/dist/nixxie-cms-core-testing.cjs.js +29 -0
- package/testing/dist/nixxie-cms-core-testing.esm.js +21 -0
- package/testing/package.json +4 -0
- package/tests/conditional-filters.test.ts +326 -0
- package/tests/telemetry.test.ts +361 -0
- package/tsconfig.json +20 -0
- package/types/dist/nixxie-cms-core-types.cjs.d.ts +2 -0
- package/types/dist/nixxie-cms-core-types.cjs.js +29 -0
- package/types/dist/nixxie-cms-core-types.esm.js +9 -0
- package/types/package.json +4 -0
|
@@ -0,0 +1,4273 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { c as createAdminMeta } from './admin-meta-14c60fec.esm.js';
|
|
4
|
+
import { GraphQLScalarType, GraphQLObjectType, Kind, OperationTypeNode, GraphQLSchema, execute, astFromValue, GraphQLNonNull, GraphQLList, parse, validate as validate$1, print, graphql, assertInputObjectType, isInputObjectType, GraphQLString } from 'graphql';
|
|
5
|
+
import { GNonNull, GInputObjectType } from '@graphql-ts/schema';
|
|
6
|
+
import { u as userInputError, e as extensionError, b as accessReturnError, c as accessDeniedError, f as formatKeys, d as filterAccessError, l as limitsExceededError, g as expandVoidHooks, v as validationFailureError, r as resolverError, h as relationshipError } from './resolve-hooks-17aafd37.esm.js';
|
|
7
|
+
import { _ as __getNames } from './utils-ef2cd0f4.esm.js';
|
|
8
|
+
import { g, Q as QueryMode } from './next-fields-9bf04ed8.esm.js';
|
|
9
|
+
import '@graphql-ts/extend';
|
|
10
|
+
import { h as humanize } from './utils-0cc426c8.esm.js';
|
|
11
|
+
import { allowAll } from '../access/dist/nixxie-cms-core-access.esm.js';
|
|
12
|
+
import { getVariableValues } from 'graphql/execution/values';
|
|
13
|
+
import { g as getDBFieldKeyForFieldOnMultiField, w as weakMemoize, a as areArraysEqual, i as isRejected, b as isFulfilled, p as promiseAllRejectWithAllErrors } from './utils-f9556354.esm.js';
|
|
14
|
+
import 'pluralize';
|
|
15
|
+
import { maybeCacheControlFromInfo } from '@apollo/cache-control-types';
|
|
16
|
+
import DataLoader from 'dataloader';
|
|
17
|
+
import _classPrivateFieldInitSpec from '@babel/runtime/helpers/esm/classPrivateFieldInitSpec';
|
|
18
|
+
import _classPrivateFieldGet from '@babel/runtime/helpers/esm/classPrivateFieldGet2';
|
|
19
|
+
import _classPrivateFieldSet from '@babel/runtime/helpers/esm/classPrivateFieldSet2';
|
|
20
|
+
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
|
21
|
+
|
|
22
|
+
function getNamedOrListTypeNodeForType(type) {
|
|
23
|
+
if (type instanceof GraphQLList) {
|
|
24
|
+
return {
|
|
25
|
+
kind: Kind.LIST_TYPE,
|
|
26
|
+
type: getTypeNodeForType(type.ofType)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
kind: Kind.NAMED_TYPE,
|
|
31
|
+
name: {
|
|
32
|
+
kind: Kind.NAME,
|
|
33
|
+
value: type.name
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function getTypeNodeForType(type) {
|
|
38
|
+
if (type instanceof GraphQLNonNull) {
|
|
39
|
+
return {
|
|
40
|
+
kind: Kind.NON_NULL_TYPE,
|
|
41
|
+
type: getNamedOrListTypeNodeForType(type.ofType)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return getNamedOrListTypeNodeForType(type);
|
|
45
|
+
}
|
|
46
|
+
function getVariablesForGraphQLField(field) {
|
|
47
|
+
const variableDefinitions = field.args.map(arg => {
|
|
48
|
+
var _ref;
|
|
49
|
+
return {
|
|
50
|
+
kind: Kind.VARIABLE_DEFINITION,
|
|
51
|
+
type: getTypeNodeForType(arg.type),
|
|
52
|
+
variable: {
|
|
53
|
+
kind: Kind.VARIABLE,
|
|
54
|
+
name: {
|
|
55
|
+
kind: Kind.NAME,
|
|
56
|
+
value: arg.name
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
defaultValue: arg.defaultValue === undefined ? undefined : (_ref = astFromValue(arg.defaultValue, arg.type)) !== null && _ref !== void 0 ? _ref : undefined
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
const argumentNodes = field.args.map(arg => ({
|
|
63
|
+
kind: Kind.ARGUMENT,
|
|
64
|
+
name: {
|
|
65
|
+
kind: Kind.NAME,
|
|
66
|
+
value: arg.name
|
|
67
|
+
},
|
|
68
|
+
value: {
|
|
69
|
+
kind: Kind.VARIABLE,
|
|
70
|
+
name: {
|
|
71
|
+
kind: Kind.NAME,
|
|
72
|
+
value: arg.name
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
return {
|
|
77
|
+
variableDefinitions,
|
|
78
|
+
argumentNodes
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function getRootTypeName(type) {
|
|
82
|
+
if (type instanceof GraphQLNonNull) {
|
|
83
|
+
return getRootTypeName(type.ofType);
|
|
84
|
+
}
|
|
85
|
+
if (type instanceof GraphQLList) {
|
|
86
|
+
return getRootTypeName(type.ofType);
|
|
87
|
+
}
|
|
88
|
+
return type.name;
|
|
89
|
+
}
|
|
90
|
+
const rawField = 'raw';
|
|
91
|
+
const RawScalar = new GraphQLScalarType({
|
|
92
|
+
name: 'RawThingPlsDontRelyOnThisAnywhere'
|
|
93
|
+
});
|
|
94
|
+
const ReturnRawValueObjectType = new GraphQLObjectType({
|
|
95
|
+
name: 'ReturnRawValue',
|
|
96
|
+
fields: {
|
|
97
|
+
[rawField]: {
|
|
98
|
+
type: RawScalar,
|
|
99
|
+
resolve(source) {
|
|
100
|
+
return source;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
function argsToArgsConfig(args) {
|
|
106
|
+
return Object.fromEntries(args.map(arg => {
|
|
107
|
+
const argConfig = {
|
|
108
|
+
astNode: arg.astNode,
|
|
109
|
+
defaultValue: arg.defaultValue,
|
|
110
|
+
deprecationReason: arg.deprecationReason,
|
|
111
|
+
description: arg.description,
|
|
112
|
+
extensions: arg.extensions,
|
|
113
|
+
type: arg.type
|
|
114
|
+
};
|
|
115
|
+
return [arg.name, argConfig];
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
// note the GraphQLNonNull and GraphQLList constructors are incorrectly
|
|
119
|
+
// not generic over their inner type which is why we have to use as
|
|
120
|
+
// (the classes are generic but not the constructors)
|
|
121
|
+
function getTypeForField(originalType) {
|
|
122
|
+
if (originalType instanceof GraphQLNonNull) {
|
|
123
|
+
return new GraphQLNonNull(getTypeForField(originalType.ofType));
|
|
124
|
+
}
|
|
125
|
+
if (originalType instanceof GraphQLList) {
|
|
126
|
+
return new GraphQLList(getTypeForField(originalType.ofType));
|
|
127
|
+
}
|
|
128
|
+
return ReturnRawValueObjectType;
|
|
129
|
+
}
|
|
130
|
+
function getSourceGivenOutputType(originalType, value) {
|
|
131
|
+
if (originalType instanceof GraphQLNonNull) {
|
|
132
|
+
return getSourceGivenOutputType(originalType.ofType, value);
|
|
133
|
+
}
|
|
134
|
+
if (value === null) return null;
|
|
135
|
+
if (originalType instanceof GraphQLList) {
|
|
136
|
+
return value.map(x => getSourceGivenOutputType(originalType.ofType, x));
|
|
137
|
+
}
|
|
138
|
+
return value[rawField];
|
|
139
|
+
}
|
|
140
|
+
function makeContextDbFn(field) {
|
|
141
|
+
const {
|
|
142
|
+
argumentNodes,
|
|
143
|
+
variableDefinitions
|
|
144
|
+
} = getVariablesForGraphQLField(field);
|
|
145
|
+
const document = {
|
|
146
|
+
kind: Kind.DOCUMENT,
|
|
147
|
+
definitions: [{
|
|
148
|
+
kind: Kind.OPERATION_DEFINITION,
|
|
149
|
+
operation: OperationTypeNode.QUERY,
|
|
150
|
+
selectionSet: {
|
|
151
|
+
kind: Kind.SELECTION_SET,
|
|
152
|
+
selections: [{
|
|
153
|
+
kind: Kind.FIELD,
|
|
154
|
+
name: {
|
|
155
|
+
kind: Kind.NAME,
|
|
156
|
+
value: field.name
|
|
157
|
+
},
|
|
158
|
+
arguments: argumentNodes,
|
|
159
|
+
selectionSet: {
|
|
160
|
+
kind: Kind.SELECTION_SET,
|
|
161
|
+
selections: [{
|
|
162
|
+
kind: Kind.FIELD,
|
|
163
|
+
name: {
|
|
164
|
+
kind: Kind.NAME,
|
|
165
|
+
value: rawField
|
|
166
|
+
}
|
|
167
|
+
}]
|
|
168
|
+
}
|
|
169
|
+
}]
|
|
170
|
+
},
|
|
171
|
+
variableDefinitions
|
|
172
|
+
}]
|
|
173
|
+
};
|
|
174
|
+
const type = getTypeForField(field.type);
|
|
175
|
+
const fieldConfig = {
|
|
176
|
+
args: argsToArgsConfig(field.args),
|
|
177
|
+
astNode: undefined,
|
|
178
|
+
deprecationReason: field.deprecationReason,
|
|
179
|
+
description: field.description,
|
|
180
|
+
extensions: field.extensions,
|
|
181
|
+
resolve: field.resolve,
|
|
182
|
+
subscribe: field.subscribe,
|
|
183
|
+
type
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// we construct a schema as we need return a different type than the one in the base GraphQL schema
|
|
187
|
+
const schema = new GraphQLSchema({
|
|
188
|
+
query: new GraphQLObjectType({
|
|
189
|
+
name: 'Query',
|
|
190
|
+
fields: {
|
|
191
|
+
[field.name]: fieldConfig
|
|
192
|
+
}
|
|
193
|
+
}),
|
|
194
|
+
assumeValid: true
|
|
195
|
+
});
|
|
196
|
+
return async (args, context, rootValue = {}) => {
|
|
197
|
+
var _result$errors;
|
|
198
|
+
const result = await execute({
|
|
199
|
+
schema,
|
|
200
|
+
document,
|
|
201
|
+
contextValue: context,
|
|
202
|
+
variableValues: args,
|
|
203
|
+
rootValue
|
|
204
|
+
});
|
|
205
|
+
if ((_result$errors = result.errors) !== null && _result$errors !== void 0 && _result$errors.length) {
|
|
206
|
+
throw result.errors[0];
|
|
207
|
+
}
|
|
208
|
+
return getSourceGivenOutputType(type, result.data[field.name]);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function makeContextQueryFn(schema, operation, field) {
|
|
212
|
+
const {
|
|
213
|
+
argumentNodes,
|
|
214
|
+
variableDefinitions
|
|
215
|
+
} = getVariablesForGraphQLField(field);
|
|
216
|
+
const rootName = getRootTypeName(field.type);
|
|
217
|
+
const exec = async (args, query, context) => {
|
|
218
|
+
var _result$errors2;
|
|
219
|
+
const selectionSet = parse(`fragment x on ${rootName} {${query}}`).definitions[0].selectionSet;
|
|
220
|
+
const document = {
|
|
221
|
+
kind: Kind.DOCUMENT,
|
|
222
|
+
definitions: [{
|
|
223
|
+
kind: Kind.OPERATION_DEFINITION,
|
|
224
|
+
// OperationTypeNode is an ts enum where the values are 'query' | 'mutation' | 'subscription'
|
|
225
|
+
operation: operation,
|
|
226
|
+
selectionSet: {
|
|
227
|
+
kind: Kind.SELECTION_SET,
|
|
228
|
+
selections: [{
|
|
229
|
+
kind: Kind.FIELD,
|
|
230
|
+
name: {
|
|
231
|
+
kind: Kind.NAME,
|
|
232
|
+
value: field.name
|
|
233
|
+
},
|
|
234
|
+
arguments: argumentNodes,
|
|
235
|
+
selectionSet: selectionSet
|
|
236
|
+
}]
|
|
237
|
+
},
|
|
238
|
+
variableDefinitions
|
|
239
|
+
}]
|
|
240
|
+
};
|
|
241
|
+
const validationErrors = validate$1(schema, document);
|
|
242
|
+
if (validationErrors.length > 0) {
|
|
243
|
+
throw validationErrors[0];
|
|
244
|
+
}
|
|
245
|
+
const result = await execute({
|
|
246
|
+
schema,
|
|
247
|
+
document,
|
|
248
|
+
contextValue: context,
|
|
249
|
+
variableValues: Object.fromEntries(
|
|
250
|
+
// GraphQL for some reason decides to make undefined values in args
|
|
251
|
+
// skip defaulting for some reason
|
|
252
|
+
// this ofc doesn't technically fully fix it (bc nested things)
|
|
253
|
+
// but for the cases where we care, it does
|
|
254
|
+
Object.entries(args).filter(([, val]) => val !== undefined)),
|
|
255
|
+
rootValue: {}
|
|
256
|
+
});
|
|
257
|
+
if ((_result$errors2 = result.errors) !== null && _result$errors2 !== void 0 && _result$errors2.length) {
|
|
258
|
+
throw result.errors[0];
|
|
259
|
+
}
|
|
260
|
+
return result.data[field.name];
|
|
261
|
+
};
|
|
262
|
+
return (_args = {}, context) => {
|
|
263
|
+
const {
|
|
264
|
+
query,
|
|
265
|
+
...args
|
|
266
|
+
} = _args;
|
|
267
|
+
return exec(args, query !== null && query !== void 0 ? query : 'id', context);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function getQueryFactory(list, schema) {
|
|
272
|
+
const queryType = schema.getQueryType();
|
|
273
|
+
const mutationType = schema.getMutationType();
|
|
274
|
+
function f(operation, fieldName) {
|
|
275
|
+
const rootType = operation === 'query' ? queryType : mutationType;
|
|
276
|
+
const field = rootType.getFields()[fieldName];
|
|
277
|
+
if (field) return makeContextQueryFn(schema, operation, field);
|
|
278
|
+
|
|
279
|
+
// if omitted
|
|
280
|
+
return () => {
|
|
281
|
+
throw new Error(`This ${operation} is not supported by the GraphQL schema: ${fieldName}()`);
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const {
|
|
285
|
+
listQueryCountName,
|
|
286
|
+
whereInputName
|
|
287
|
+
} = list.graphql.names;
|
|
288
|
+
const fcache = {
|
|
289
|
+
findOne: f('query', list.graphql.names.itemQueryName),
|
|
290
|
+
findMany: f('query', list.graphql.names.listQueryName),
|
|
291
|
+
count: async (args = {}, context) => {
|
|
292
|
+
const {
|
|
293
|
+
where = {}
|
|
294
|
+
} = args;
|
|
295
|
+
const {
|
|
296
|
+
count
|
|
297
|
+
} = await context.graphql.run({
|
|
298
|
+
query: `query ($where: ${whereInputName}!) { count: ${listQueryCountName}(where: $where) }`,
|
|
299
|
+
variables: {
|
|
300
|
+
where
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
return count;
|
|
304
|
+
},
|
|
305
|
+
createOne: f('mutation', list.graphql.names.createMutationName),
|
|
306
|
+
createMany: f('mutation', list.graphql.names.createManyMutationName),
|
|
307
|
+
updateOne: f('mutation', list.graphql.names.updateMutationName),
|
|
308
|
+
updateMany: f('mutation', list.graphql.names.updateManyMutationName),
|
|
309
|
+
deleteOne: f('mutation', list.graphql.names.deleteMutationName),
|
|
310
|
+
deleteMany: f('mutation', list.graphql.names.deleteManyMutationName)
|
|
311
|
+
};
|
|
312
|
+
return context => {
|
|
313
|
+
return {
|
|
314
|
+
findOne: args => fcache.findOne(args, context),
|
|
315
|
+
findMany: args => fcache.findMany(args, context),
|
|
316
|
+
count: args => fcache.count(args, context),
|
|
317
|
+
createOne: args => fcache.createOne(args, context),
|
|
318
|
+
createMany: args => fcache.createMany(args, context),
|
|
319
|
+
updateOne: args => fcache.updateOne(args, context),
|
|
320
|
+
updateMany: args => fcache.updateMany(args, context),
|
|
321
|
+
deleteOne: args => fcache.deleteOne(args, context),
|
|
322
|
+
deleteMany: args => fcache.deleteMany(args, context)
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function getDbFactory(list, schema) {
|
|
327
|
+
const queryType = schema.getQueryType();
|
|
328
|
+
const mutationType = schema.getMutationType();
|
|
329
|
+
function f(operation, fieldName) {
|
|
330
|
+
const rootType = operation === 'query' ? queryType : mutationType;
|
|
331
|
+
const field = rootType.getFields()[fieldName];
|
|
332
|
+
if (field) return makeContextDbFn(field);
|
|
333
|
+
|
|
334
|
+
// if omitted
|
|
335
|
+
return () => {
|
|
336
|
+
throw new Error(`This ${operation} is not supported by the GraphQL schema: ${fieldName}()`);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const fcache = {
|
|
340
|
+
findOne: f('query', list.graphql.names.itemQueryName),
|
|
341
|
+
findMany: f('query', list.graphql.names.listQueryName),
|
|
342
|
+
count: f('query', list.graphql.names.listQueryCountName),
|
|
343
|
+
createOne: f('mutation', list.graphql.names.createMutationName),
|
|
344
|
+
createMany: f('mutation', list.graphql.names.createManyMutationName),
|
|
345
|
+
updateOne: f('mutation', list.graphql.names.updateMutationName),
|
|
346
|
+
updateMany: f('mutation', list.graphql.names.updateManyMutationName),
|
|
347
|
+
deleteOne: f('mutation', list.graphql.names.deleteMutationName),
|
|
348
|
+
deleteMany: f('mutation', list.graphql.names.deleteManyMutationName)
|
|
349
|
+
};
|
|
350
|
+
return context => {
|
|
351
|
+
return {
|
|
352
|
+
findOne: args => fcache.findOne(args, context),
|
|
353
|
+
findMany: args => fcache.findMany(args, context),
|
|
354
|
+
count: args => fcache.count(args, context),
|
|
355
|
+
createOne: args => fcache.createOne(args, context),
|
|
356
|
+
createMany: args => fcache.createMany(args, context),
|
|
357
|
+
updateOne: args => fcache.updateOne(args, context),
|
|
358
|
+
updateMany: args => fcache.updateMany(args, context),
|
|
359
|
+
deleteOne: args => fcache.deleteOne(args, context),
|
|
360
|
+
deleteMany: args => fcache.deleteMany(args, context)
|
|
361
|
+
};
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function createContext({
|
|
366
|
+
config,
|
|
367
|
+
lists,
|
|
368
|
+
graphQLSchemas,
|
|
369
|
+
prismaClient,
|
|
370
|
+
prismaTypes
|
|
371
|
+
}) {
|
|
372
|
+
const dbFactories = {};
|
|
373
|
+
for (const [listKey, list] of Object.entries(lists)) {
|
|
374
|
+
dbFactories[listKey] = getDbFactory(list, graphQLSchemas.public);
|
|
375
|
+
}
|
|
376
|
+
const dbFactoriesInternal = {};
|
|
377
|
+
for (const [listKey, list] of Object.entries(lists)) {
|
|
378
|
+
dbFactoriesInternal[listKey] = getDbFactory(list, graphQLSchemas.internal);
|
|
379
|
+
}
|
|
380
|
+
const queryFactories = {};
|
|
381
|
+
for (const [listKey, list] of Object.entries(lists)) {
|
|
382
|
+
queryFactories[listKey] = getQueryFactory(list, graphQLSchemas.public);
|
|
383
|
+
}
|
|
384
|
+
const queryFactoriesInternal = {};
|
|
385
|
+
for (const [listKey, list] of Object.entries(lists)) {
|
|
386
|
+
queryFactoriesInternal[listKey] = getQueryFactory(list, graphQLSchemas.internal);
|
|
387
|
+
}
|
|
388
|
+
const construct = ({
|
|
389
|
+
prisma,
|
|
390
|
+
req,
|
|
391
|
+
res,
|
|
392
|
+
session,
|
|
393
|
+
internal,
|
|
394
|
+
sudo
|
|
395
|
+
}) => {
|
|
396
|
+
var _config$email, _config$jobs, _config$cache, _config$audit, _config$webhooks, _config$rateLimit, _config$health;
|
|
397
|
+
const schema = internal ? graphQLSchemas.internal : graphQLSchemas.public;
|
|
398
|
+
const rawGraphQL = async ({
|
|
399
|
+
query,
|
|
400
|
+
variables
|
|
401
|
+
}) => {
|
|
402
|
+
const source = typeof query === 'string' ? query : print(query);
|
|
403
|
+
return await graphql({
|
|
404
|
+
schema,
|
|
405
|
+
source,
|
|
406
|
+
contextValue: context,
|
|
407
|
+
variableValues: variables
|
|
408
|
+
});
|
|
409
|
+
};
|
|
410
|
+
const runGraphQL = async ({
|
|
411
|
+
query,
|
|
412
|
+
variables
|
|
413
|
+
}) => {
|
|
414
|
+
var _result$errors;
|
|
415
|
+
const result = await rawGraphQL({
|
|
416
|
+
query,
|
|
417
|
+
variables
|
|
418
|
+
});
|
|
419
|
+
if ((_result$errors = result.errors) !== null && _result$errors !== void 0 && _result$errors.length) throw result.errors[0];
|
|
420
|
+
return result.data;
|
|
421
|
+
};
|
|
422
|
+
const context = {
|
|
423
|
+
prisma,
|
|
424
|
+
db: {},
|
|
425
|
+
query: {},
|
|
426
|
+
graphql: {
|
|
427
|
+
raw: rawGraphQL,
|
|
428
|
+
run: runGraphQL,
|
|
429
|
+
schema
|
|
430
|
+
},
|
|
431
|
+
services: {
|
|
432
|
+
email: (_config$email = config.email) !== null && _config$email !== void 0 ? _config$email : null,
|
|
433
|
+
jobs: (_config$jobs = config.jobs) !== null && _config$jobs !== void 0 ? _config$jobs : null,
|
|
434
|
+
cache: (_config$cache = config.cache) !== null && _config$cache !== void 0 ? _config$cache : null,
|
|
435
|
+
audit: (_config$audit = config.audit) !== null && _config$audit !== void 0 ? _config$audit : null,
|
|
436
|
+
webhooks: (_config$webhooks = config.webhooks) !== null && _config$webhooks !== void 0 ? _config$webhooks : null,
|
|
437
|
+
rateLimit: (_config$rateLimit = config.rateLimit) !== null && _config$rateLimit !== void 0 ? _config$rateLimit : null,
|
|
438
|
+
health: (_config$health = config.health) !== null && _config$health !== void 0 ? _config$health : null
|
|
439
|
+
},
|
|
440
|
+
transaction: async (f, opts) => {
|
|
441
|
+
return await prisma.$transaction(async prisma_ => {
|
|
442
|
+
const newContext = construct({
|
|
443
|
+
prisma: prisma_,
|
|
444
|
+
req,
|
|
445
|
+
res,
|
|
446
|
+
session,
|
|
447
|
+
internal,
|
|
448
|
+
sudo
|
|
449
|
+
});
|
|
450
|
+
return await f(newContext);
|
|
451
|
+
}, opts);
|
|
452
|
+
},
|
|
453
|
+
req,
|
|
454
|
+
res,
|
|
455
|
+
sessionStrategy: config.session,
|
|
456
|
+
...(session ? {
|
|
457
|
+
session
|
|
458
|
+
} : {}),
|
|
459
|
+
withRequest: async (newReq, newRes) => {
|
|
460
|
+
var _await$config$session, _config$session;
|
|
461
|
+
const newContext = construct({
|
|
462
|
+
prisma,
|
|
463
|
+
req: newReq,
|
|
464
|
+
res: newRes,
|
|
465
|
+
session,
|
|
466
|
+
internal,
|
|
467
|
+
sudo
|
|
468
|
+
});
|
|
469
|
+
return newContext.withSession((_await$config$session = await ((_config$session = config.session) === null || _config$session === void 0 ? void 0 : _config$session.get({
|
|
470
|
+
context: newContext
|
|
471
|
+
}))) !== null && _await$config$session !== void 0 ? _await$config$session : undefined);
|
|
472
|
+
},
|
|
473
|
+
withSession: session => {
|
|
474
|
+
return construct({
|
|
475
|
+
prisma,
|
|
476
|
+
req,
|
|
477
|
+
res,
|
|
478
|
+
session,
|
|
479
|
+
internal,
|
|
480
|
+
sudo
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
// privilege escalation
|
|
484
|
+
internal: () => construct({
|
|
485
|
+
prisma,
|
|
486
|
+
req,
|
|
487
|
+
res,
|
|
488
|
+
session,
|
|
489
|
+
internal: true,
|
|
490
|
+
sudo
|
|
491
|
+
}),
|
|
492
|
+
sudo: () => construct({
|
|
493
|
+
prisma,
|
|
494
|
+
req,
|
|
495
|
+
res,
|
|
496
|
+
session,
|
|
497
|
+
internal: true,
|
|
498
|
+
sudo: true
|
|
499
|
+
}),
|
|
500
|
+
__internal: {
|
|
501
|
+
sudo,
|
|
502
|
+
lists,
|
|
503
|
+
prisma: {
|
|
504
|
+
...prismaTypes
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
const _dbFactories = internal ? dbFactoriesInternal : dbFactories;
|
|
509
|
+
const _queryFactories = internal ? queryFactoriesInternal : queryFactories;
|
|
510
|
+
for (const listKey of Object.keys(lists)) {
|
|
511
|
+
context.db[listKey] = _dbFactories[listKey](context);
|
|
512
|
+
context.query[listKey] = _queryFactories[listKey](context);
|
|
513
|
+
}
|
|
514
|
+
return context;
|
|
515
|
+
};
|
|
516
|
+
return construct({
|
|
517
|
+
prisma: prismaClient,
|
|
518
|
+
internal: false,
|
|
519
|
+
sudo: false
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const argName = 'where';
|
|
524
|
+
function coerceAndValidateForGraphQLInput(schema, type, value) {
|
|
525
|
+
const variableDefintions = [{
|
|
526
|
+
kind: Kind.VARIABLE_DEFINITION,
|
|
527
|
+
type: getTypeNodeForType(type),
|
|
528
|
+
variable: {
|
|
529
|
+
kind: Kind.VARIABLE,
|
|
530
|
+
name: {
|
|
531
|
+
kind: Kind.NAME,
|
|
532
|
+
value: argName
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}];
|
|
536
|
+
const coercedVariableValues = getVariableValues(schema, variableDefintions, {
|
|
537
|
+
[argName]: value
|
|
538
|
+
});
|
|
539
|
+
if (coercedVariableValues.errors) {
|
|
540
|
+
return {
|
|
541
|
+
kind: 'error',
|
|
542
|
+
error: coercedVariableValues.errors[0]
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return {
|
|
546
|
+
kind: 'valid',
|
|
547
|
+
value: coercedVariableValues.coerced[argName]
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async function resolveUniqueWhereInput(inputFilter, list, context) {
|
|
552
|
+
const where = {};
|
|
553
|
+
for (const key in inputFilter) {
|
|
554
|
+
const value = inputFilter[key];
|
|
555
|
+
const resolver = list.fields[key].input.uniqueWhere.resolve;
|
|
556
|
+
if (resolver !== undefined) {
|
|
557
|
+
where[key] = await resolver(value, context);
|
|
558
|
+
} else {
|
|
559
|
+
where[key] = value;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return where;
|
|
563
|
+
}
|
|
564
|
+
async function resolveWhereInput(inputFilter, list, context) {
|
|
565
|
+
return {
|
|
566
|
+
AND: await Promise.all(Object.entries(inputFilter).map(async ([key, value]) => {
|
|
567
|
+
if (key === 'OR' || key === 'AND' || key === 'NOT') {
|
|
568
|
+
return {
|
|
569
|
+
[key]: await Promise.all(value.map(value => resolveWhereInput(value, list, context)))
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// we know if there are filters in the input object with the key of a field,
|
|
574
|
+
// the field must have defined a where input so this non null assertion is okay
|
|
575
|
+
const field = list.fields[key];
|
|
576
|
+
const {
|
|
577
|
+
dbField
|
|
578
|
+
} = field;
|
|
579
|
+
const resolve = field.input.where.resolve;
|
|
580
|
+
const ret = resolve ? await resolve(value, context, (() => {
|
|
581
|
+
if (dbField.kind !== 'relation') {
|
|
582
|
+
return undefined;
|
|
583
|
+
}
|
|
584
|
+
const foreignList = dbField.list;
|
|
585
|
+
const whereResolver = filter => resolveWhereInput(filter, list.lists[foreignList], context);
|
|
586
|
+
if (dbField.mode === 'many') {
|
|
587
|
+
return async () => {
|
|
588
|
+
if (value === null) {
|
|
589
|
+
throw userInputError('A many relation filter cannot be set to null');
|
|
590
|
+
}
|
|
591
|
+
return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, val]) => {
|
|
592
|
+
if (val === null) {
|
|
593
|
+
throw userInputError(`The key "${key}" in a many relation filter cannot be set to null`);
|
|
594
|
+
}
|
|
595
|
+
return [key, await whereResolver(val)];
|
|
596
|
+
})));
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
return value => {
|
|
600
|
+
if (value === null) return null;
|
|
601
|
+
return whereResolver(value);
|
|
602
|
+
};
|
|
603
|
+
})()) : value;
|
|
604
|
+
if (ret === null) {
|
|
605
|
+
if (dbField.kind === 'multi') {
|
|
606
|
+
// Note: no built-in field types support multi valued database fields *and* filtering.
|
|
607
|
+
// This code path is only relevent to custom fields which fit that criteria.
|
|
608
|
+
throw new Error('multi db fields cannot return null from where input resolvers');
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
[key]: null
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
return handleOperators(key, dbField, ret);
|
|
615
|
+
}))
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function handleOperators(fieldKey, dbField, {
|
|
619
|
+
AND,
|
|
620
|
+
OR,
|
|
621
|
+
NOT,
|
|
622
|
+
...rest
|
|
623
|
+
}) {
|
|
624
|
+
return {
|
|
625
|
+
AND: AND === null || AND === void 0 ? void 0 : AND.map(value => handleOperators(fieldKey, dbField, value)),
|
|
626
|
+
OR: OR === null || OR === void 0 ? void 0 : OR.map(value => handleOperators(fieldKey, dbField, value)),
|
|
627
|
+
NOT: NOT === null || NOT === void 0 ? void 0 : NOT.map(value => handleOperators(fieldKey, dbField, value)),
|
|
628
|
+
...nestWithAppropiateField(fieldKey, dbField, rest)
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
function nestWithAppropiateField(fieldKey, dbField, value) {
|
|
632
|
+
if (dbField.kind === 'multi') {
|
|
633
|
+
return Object.fromEntries(Object.entries(value).map(([key, val]) => [getDBFieldKeyForFieldOnMultiField(fieldKey, key), val]));
|
|
634
|
+
}
|
|
635
|
+
return {
|
|
636
|
+
[fieldKey]: value
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function cannotForItem(operation, list) {
|
|
641
|
+
if (operation === 'create') return `You cannot ${operation} that ${list.graphql.names.outputTypeName}`;
|
|
642
|
+
return `You cannot ${operation} that ${list.graphql.names.outputTypeName} - it may not exist`;
|
|
643
|
+
}
|
|
644
|
+
function cannotActionForItem(action, list) {
|
|
645
|
+
return `You cannot execute action "${action.actionKey}" for that ${list.graphql.names.outputTypeName}`;
|
|
646
|
+
}
|
|
647
|
+
function cannotForItemFields(operation, list, fieldsDenied) {
|
|
648
|
+
return `You cannot ${operation} that ${list.graphql.names.outputTypeName} - you cannot ${operation} the fields ${formatKeys(fieldsDenied)}`;
|
|
649
|
+
}
|
|
650
|
+
async function getOperationFieldAccess(item, list, fieldKey, context, operation) {
|
|
651
|
+
if (context.__internal.sudo) return true;
|
|
652
|
+
const {
|
|
653
|
+
listKey
|
|
654
|
+
} = list;
|
|
655
|
+
let result;
|
|
656
|
+
try {
|
|
657
|
+
result = await list.fields[fieldKey].access.read({
|
|
658
|
+
operation: 'read',
|
|
659
|
+
session: context.session,
|
|
660
|
+
listKey,
|
|
661
|
+
fieldKey,
|
|
662
|
+
context,
|
|
663
|
+
item
|
|
664
|
+
});
|
|
665
|
+
} catch (error) {
|
|
666
|
+
throw extensionError('Access control', [{
|
|
667
|
+
error,
|
|
668
|
+
tag: `${list.listKey}.${fieldKey}.access.${operation}`
|
|
669
|
+
}]);
|
|
670
|
+
}
|
|
671
|
+
if (typeof result !== 'boolean') {
|
|
672
|
+
throw accessReturnError([{
|
|
673
|
+
tag: `${listKey}.access.operation.${operation}`,
|
|
674
|
+
returned: typeof result
|
|
675
|
+
}]);
|
|
676
|
+
}
|
|
677
|
+
return result;
|
|
678
|
+
}
|
|
679
|
+
async function getOperationAccess(list, context, operation) {
|
|
680
|
+
if (context.__internal.sudo) return true;
|
|
681
|
+
const {
|
|
682
|
+
listKey
|
|
683
|
+
} = list;
|
|
684
|
+
let result;
|
|
685
|
+
try {
|
|
686
|
+
if (operation === 'query') {
|
|
687
|
+
result = await list.access.operation.query({
|
|
688
|
+
operation,
|
|
689
|
+
session: context.session,
|
|
690
|
+
listKey,
|
|
691
|
+
context
|
|
692
|
+
});
|
|
693
|
+
} else if (operation === 'create') {
|
|
694
|
+
result = await list.access.operation.create({
|
|
695
|
+
operation,
|
|
696
|
+
session: context.session,
|
|
697
|
+
listKey,
|
|
698
|
+
context
|
|
699
|
+
});
|
|
700
|
+
} else if (operation === 'update') {
|
|
701
|
+
result = await list.access.operation.update({
|
|
702
|
+
operation,
|
|
703
|
+
session: context.session,
|
|
704
|
+
listKey,
|
|
705
|
+
context
|
|
706
|
+
});
|
|
707
|
+
} else if (operation === 'delete') {
|
|
708
|
+
result = await list.access.operation.delete({
|
|
709
|
+
operation,
|
|
710
|
+
session: context.session,
|
|
711
|
+
listKey,
|
|
712
|
+
context
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
} catch (error) {
|
|
716
|
+
throw extensionError('Access control', [{
|
|
717
|
+
error,
|
|
718
|
+
tag: `${listKey}.access.operation.${operation}`
|
|
719
|
+
}]);
|
|
720
|
+
}
|
|
721
|
+
if (typeof result !== 'boolean') {
|
|
722
|
+
throw accessReturnError([{
|
|
723
|
+
tag: `${listKey}.access.operation.${operation}`,
|
|
724
|
+
returned: typeof result
|
|
725
|
+
}]);
|
|
726
|
+
}
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
async function getAccessFilters(list, context, operation) {
|
|
730
|
+
if (context.__internal.sudo) return true;
|
|
731
|
+
try {
|
|
732
|
+
let filters;
|
|
733
|
+
if (operation === 'query') {
|
|
734
|
+
filters = await list.access.filter.query({
|
|
735
|
+
operation,
|
|
736
|
+
session: context.session,
|
|
737
|
+
listKey: list.listKey,
|
|
738
|
+
context
|
|
739
|
+
});
|
|
740
|
+
} else if (operation === 'update') {
|
|
741
|
+
filters = await list.access.filter.update({
|
|
742
|
+
operation,
|
|
743
|
+
session: context.session,
|
|
744
|
+
listKey: list.listKey,
|
|
745
|
+
context
|
|
746
|
+
});
|
|
747
|
+
} else if (operation === 'delete') {
|
|
748
|
+
filters = await list.access.filter.delete({
|
|
749
|
+
operation,
|
|
750
|
+
session: context.session,
|
|
751
|
+
listKey: list.listKey,
|
|
752
|
+
context
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
if (typeof filters === 'boolean') return filters;
|
|
756
|
+
if (!filters) return false; // shouldn't happen, but, Typescript
|
|
757
|
+
|
|
758
|
+
const schema = context.sudo().graphql.schema;
|
|
759
|
+
const whereInput = assertInputObjectType(schema.getType(list.graphql.names.whereInputName));
|
|
760
|
+
const result = coerceAndValidateForGraphQLInput(schema, whereInput, filters);
|
|
761
|
+
if (result.kind === 'valid') return result.value;
|
|
762
|
+
throw result.error;
|
|
763
|
+
} catch (error) {
|
|
764
|
+
throw extensionError('Access control', [{
|
|
765
|
+
error,
|
|
766
|
+
tag: `${list.listKey}.access.filter.${operation}`
|
|
767
|
+
}]);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
async function enforceListLevelAccessControl(context, operation, list, inputData, item) {
|
|
771
|
+
if (context.__internal.sudo) return;
|
|
772
|
+
let accepted; // should be boolean, but dont trust, it might accidentally be a filter
|
|
773
|
+
try {
|
|
774
|
+
// apply access.item.* controls
|
|
775
|
+
if (operation === 'create') {
|
|
776
|
+
const itemAccessControl = list.access.item[operation];
|
|
777
|
+
accepted = await itemAccessControl({
|
|
778
|
+
operation,
|
|
779
|
+
session: context.session,
|
|
780
|
+
listKey: list.listKey,
|
|
781
|
+
context,
|
|
782
|
+
inputData
|
|
783
|
+
});
|
|
784
|
+
} else if (operation === 'update' && item !== undefined) {
|
|
785
|
+
const itemAccessControl = list.access.item[operation];
|
|
786
|
+
accepted = await itemAccessControl({
|
|
787
|
+
operation,
|
|
788
|
+
session: context.session,
|
|
789
|
+
listKey: list.listKey,
|
|
790
|
+
context,
|
|
791
|
+
item,
|
|
792
|
+
inputData
|
|
793
|
+
});
|
|
794
|
+
} else if (operation === 'delete' && item !== undefined) {
|
|
795
|
+
const itemAccessControl = list.access.item[operation];
|
|
796
|
+
accepted = await itemAccessControl({
|
|
797
|
+
operation,
|
|
798
|
+
session: context.session,
|
|
799
|
+
listKey: list.listKey,
|
|
800
|
+
context,
|
|
801
|
+
item
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
} catch (error) {
|
|
805
|
+
throw extensionError('Access control', [{
|
|
806
|
+
error,
|
|
807
|
+
tag: `${list.listKey}.access.item.${operation}`
|
|
808
|
+
}]);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// short circuit the safe path
|
|
812
|
+
if (accepted === true) return;
|
|
813
|
+
if (typeof accepted !== 'boolean') {
|
|
814
|
+
throw accessReturnError([{
|
|
815
|
+
tag: `${list.listKey}.access.item.${operation}`,
|
|
816
|
+
returned: typeof accepted
|
|
817
|
+
}]);
|
|
818
|
+
}
|
|
819
|
+
throw accessDeniedError(cannotForItem(operation, list));
|
|
820
|
+
}
|
|
821
|
+
async function enforceFieldLevelAccessControl(context, operation, list, inputData, item) {
|
|
822
|
+
if (context.__internal.sudo) return;
|
|
823
|
+
const nonBooleans = [];
|
|
824
|
+
const fieldsDenied = [];
|
|
825
|
+
const accessErrors = [];
|
|
826
|
+
await Promise.allSettled(Object.keys(inputData).map(async fieldKey => {
|
|
827
|
+
let accepted; // should be boolean, but dont trust
|
|
828
|
+
try {
|
|
829
|
+
// apply fields.[fieldKey].access.* controls
|
|
830
|
+
if (operation === 'create') {
|
|
831
|
+
const fieldAccessControl = list.fields[fieldKey].access[operation];
|
|
832
|
+
accepted = await fieldAccessControl({
|
|
833
|
+
operation,
|
|
834
|
+
session: context.session,
|
|
835
|
+
listKey: list.listKey,
|
|
836
|
+
fieldKey,
|
|
837
|
+
context,
|
|
838
|
+
inputData: inputData // FIXME
|
|
839
|
+
});
|
|
840
|
+
} else if (operation === 'update' && item !== undefined) {
|
|
841
|
+
const fieldAccessControl = list.fields[fieldKey].access[operation];
|
|
842
|
+
accepted = await fieldAccessControl({
|
|
843
|
+
operation,
|
|
844
|
+
session: context.session,
|
|
845
|
+
listKey: list.listKey,
|
|
846
|
+
fieldKey,
|
|
847
|
+
context,
|
|
848
|
+
item,
|
|
849
|
+
inputData
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
} catch (error) {
|
|
853
|
+
accessErrors.push({
|
|
854
|
+
error,
|
|
855
|
+
tag: `${list.listKey}.${fieldKey}.access.${operation}`
|
|
856
|
+
});
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// short circuit the safe path
|
|
861
|
+
if (accepted === true) return;
|
|
862
|
+
fieldsDenied.push(fieldKey);
|
|
863
|
+
|
|
864
|
+
// wrong type?
|
|
865
|
+
if (typeof accepted !== 'boolean') {
|
|
866
|
+
nonBooleans.push({
|
|
867
|
+
tag: `${list.listKey}.${fieldKey}.access.${operation}`,
|
|
868
|
+
returned: typeof accepted
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
}));
|
|
872
|
+
if (nonBooleans.length) {
|
|
873
|
+
throw accessReturnError(nonBooleans);
|
|
874
|
+
}
|
|
875
|
+
if (accessErrors.length) {
|
|
876
|
+
throw extensionError('Access control', accessErrors);
|
|
877
|
+
}
|
|
878
|
+
if (fieldsDenied.length) {
|
|
879
|
+
throw accessDeniedError(cannotForItemFields(operation, list, fieldsDenied));
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function parseFieldAccessControl(access) {
|
|
883
|
+
var _access$read, _access$create, _access$update;
|
|
884
|
+
if (typeof access === 'function') {
|
|
885
|
+
return {
|
|
886
|
+
read: access,
|
|
887
|
+
create: access,
|
|
888
|
+
update: access
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
read: (_access$read = access === null || access === void 0 ? void 0 : access.read) !== null && _access$read !== void 0 ? _access$read : allowAll,
|
|
893
|
+
create: (_access$create = access === null || access === void 0 ? void 0 : access.create) !== null && _access$create !== void 0 ? _access$create : allowAll,
|
|
894
|
+
update: (_access$update = access === null || access === void 0 ? void 0 : access.update) !== null && _access$update !== void 0 ? _access$update : allowAll
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
function parseListAccessControl(access) {
|
|
898
|
+
var _filter$query, _filter$update, _filter$delete, _item$create, _item$update, _item$delete;
|
|
899
|
+
if (typeof access === 'function') {
|
|
900
|
+
return {
|
|
901
|
+
operation: {
|
|
902
|
+
query: access,
|
|
903
|
+
create: access,
|
|
904
|
+
update: access,
|
|
905
|
+
delete: access
|
|
906
|
+
},
|
|
907
|
+
filter: {
|
|
908
|
+
query: allowAll,
|
|
909
|
+
update: allowAll,
|
|
910
|
+
delete: allowAll
|
|
911
|
+
},
|
|
912
|
+
item: {
|
|
913
|
+
create: allowAll,
|
|
914
|
+
update: allowAll,
|
|
915
|
+
delete: allowAll
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
let {
|
|
920
|
+
operation,
|
|
921
|
+
filter,
|
|
922
|
+
item
|
|
923
|
+
} = access;
|
|
924
|
+
if (typeof operation === 'function') {
|
|
925
|
+
operation = {
|
|
926
|
+
query: operation,
|
|
927
|
+
create: operation,
|
|
928
|
+
update: operation,
|
|
929
|
+
delete: operation
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
return {
|
|
933
|
+
operation: {
|
|
934
|
+
query: operation.query,
|
|
935
|
+
create: operation.create,
|
|
936
|
+
update: operation.update,
|
|
937
|
+
delete: operation.delete
|
|
938
|
+
},
|
|
939
|
+
filter: {
|
|
940
|
+
query: (_filter$query = filter === null || filter === void 0 ? void 0 : filter.query) !== null && _filter$query !== void 0 ? _filter$query : allowAll,
|
|
941
|
+
// create: not supported
|
|
942
|
+
update: (_filter$update = filter === null || filter === void 0 ? void 0 : filter.update) !== null && _filter$update !== void 0 ? _filter$update : allowAll,
|
|
943
|
+
delete: (_filter$delete = filter === null || filter === void 0 ? void 0 : filter.delete) !== null && _filter$delete !== void 0 ? _filter$delete : allowAll
|
|
944
|
+
},
|
|
945
|
+
item: {
|
|
946
|
+
// query: not supported
|
|
947
|
+
create: (_item$create = item === null || item === void 0 ? void 0 : item.create) !== null && _item$create !== void 0 ? _item$create : allowAll,
|
|
948
|
+
update: (_item$update = item === null || item === void 0 ? void 0 : item.update) !== null && _item$update !== void 0 ? _item$update : allowAll,
|
|
949
|
+
delete: (_item$delete = item === null || item === void 0 ? void 0 : item.delete) !== null && _item$delete !== void 0 ? _item$delete : allowAll
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
async function checkUniqueItemExists(uniqueInput, foreignList, context, operation) {
|
|
954
|
+
// Validate and resolve the input filter
|
|
955
|
+
const uniqueWhere = await resolveUniqueWhereInput(uniqueInput, foreignList, context);
|
|
956
|
+
|
|
957
|
+
// Check whether the item exists (from this users POV).
|
|
958
|
+
try {
|
|
959
|
+
const item = await context.db[foreignList.listKey].findOne({
|
|
960
|
+
where: uniqueInput
|
|
961
|
+
});
|
|
962
|
+
if (item !== null) return uniqueWhere;
|
|
963
|
+
} catch (err) {}
|
|
964
|
+
throw accessDeniedError(cannotForItem(operation, foreignList));
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function assertFieldsValid(list) {
|
|
968
|
+
assertNoConflictingExtraOutputFields(list);
|
|
969
|
+
assertIdFieldGraphQLTypesCorrect(list);
|
|
970
|
+
assertNoFieldKeysThatConflictWithFilterCombinators(list);
|
|
971
|
+
assertUniqueWhereInputsValid(list);
|
|
972
|
+
assertFieldsIsNonNullAllowed(list);
|
|
973
|
+
}
|
|
974
|
+
function assertFieldsIsNonNullAllowed(list) {
|
|
975
|
+
for (const [fieldKey, field] of Object.entries(list.fields)) {
|
|
976
|
+
if (field.access.read !== allowAll) {
|
|
977
|
+
if (field.graphql.isNonNull.read) {
|
|
978
|
+
throw new Error(`The field at ${list.listKey}.${fieldKey} sets graphql.isNonNull.read: true, and has 'read' field access control, this is not allowed.\n` + `Either disable graphql.read.isNonNull, or disable 'read' field access control.`);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function assertUniqueWhereInputsValid(list) {
|
|
984
|
+
for (const [fieldKey, {
|
|
985
|
+
dbField,
|
|
986
|
+
input
|
|
987
|
+
}] of Object.entries(list.fields)) {
|
|
988
|
+
if (input !== null && input !== void 0 && input.uniqueWhere) {
|
|
989
|
+
if (dbField.kind !== 'scalar' && dbField.kind !== 'enum' && dbField.kind !== 'relation') {
|
|
990
|
+
throw new Error(`Only scalar db fields can provide a uniqueWhere input currently but the field at ${list.listKey}.${fieldKey} specifies a uniqueWhere input`);
|
|
991
|
+
}
|
|
992
|
+
if (dbField.kind !== 'relation' && dbField.index !== 'unique' && fieldKey !== 'id') {
|
|
993
|
+
throw new Error(`Fields must have a unique index or be the idField to specify a uniqueWhere input but the field at ${list.listKey}.${fieldKey} specifies a uniqueWhere input without a unique index`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function assertNoFieldKeysThatConflictWithFilterCombinators(list) {
|
|
999
|
+
for (const fieldKey of Object.keys(list.fields)) {
|
|
1000
|
+
if (fieldKey === 'AND' || fieldKey === 'OR' || fieldKey === 'NOT') {
|
|
1001
|
+
throw new Error(`Fields cannot be named ${fieldKey} but there is a field named ${fieldKey} on ${list.listKey}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function assertNoConflictingExtraOutputFields(list) {
|
|
1006
|
+
const fieldKeys = new Set(Object.keys(list.fields));
|
|
1007
|
+
const alreadyFoundFields = {};
|
|
1008
|
+
for (const [fieldKey, field] of Object.entries(list.fields)) {
|
|
1009
|
+
if (field.extraOutputFields) {
|
|
1010
|
+
for (const outputTypeFieldName of Object.keys(field.extraOutputFields)) {
|
|
1011
|
+
// note that this and the case handled below are fundamentally the same thing but i want different errors for each of them
|
|
1012
|
+
if (fieldKeys.has(outputTypeFieldName)) {
|
|
1013
|
+
throw new Error(`The field ${fieldKey} on the ${list.listKey} list defines an extra GraphQL output field named ${outputTypeFieldName} which conflicts with the Nixxie field type named ${outputTypeFieldName} on the same list`);
|
|
1014
|
+
}
|
|
1015
|
+
const alreadyFoundField = alreadyFoundFields[outputTypeFieldName];
|
|
1016
|
+
if (alreadyFoundField !== undefined) {
|
|
1017
|
+
throw new Error(`The field ${fieldKey} on the ${list.listKey} list defines an extra GraphQL output field named ${outputTypeFieldName} which conflicts with the Nixxie field type named ${alreadyFoundField} which also defines an extra GraphQL output field named ${outputTypeFieldName}`);
|
|
1018
|
+
}
|
|
1019
|
+
alreadyFoundFields[outputTypeFieldName] = fieldKey;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
function assertIdFieldGraphQLTypesCorrect(list) {
|
|
1025
|
+
var _idField$input;
|
|
1026
|
+
const idField = list.fields.id;
|
|
1027
|
+
if (((_idField$input = idField.input) === null || _idField$input === void 0 ? void 0 : _idField$input.uniqueWhere) === undefined) {
|
|
1028
|
+
throw new Error(`The idField on a list must define a uniqueWhere GraphQL input with the ID GraphQL scalar type but the idField for ${list.listKey} does not define one`);
|
|
1029
|
+
}
|
|
1030
|
+
if (idField.input.uniqueWhere.arg.type !== g.ID) {
|
|
1031
|
+
throw new Error(`The idField on a list must define a uniqueWhere GraphQL input with the ID GraphQL scalar type but the idField for ${list.listKey} defines the type ${idField.input.uniqueWhere.arg.type.toString()}`);
|
|
1032
|
+
}
|
|
1033
|
+
// we may want to loosen these constraints in the future
|
|
1034
|
+
if (idField.input.create !== undefined) {
|
|
1035
|
+
throw new Error(`The idField on a list must not define a create GraphQL input but the idField for ${list.listKey} does define one`);
|
|
1036
|
+
}
|
|
1037
|
+
if (idField.input.update !== undefined) {
|
|
1038
|
+
throw new Error(`The idField on a list must not define an update GraphQL input but the idField for ${list.listKey} does define one`);
|
|
1039
|
+
}
|
|
1040
|
+
if (idField.graphql.isEnabled.read === false) {
|
|
1041
|
+
throw new Error(`The idField on a list must not have graphql.isEnabled.read be set to false but ${list.listKey} does`);
|
|
1042
|
+
}
|
|
1043
|
+
if (!(idField.output.type instanceof GNonNull) || idField.output.type.ofType !== g.ID) {
|
|
1044
|
+
throw new Error(`The idField on a list must define a GraphQL output field with a non-nullable ID GraphQL scalar type but the idField for ${list.listKey} defines the type ${idField.output.type.toString()}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
async function checkFilterOrderAccess(things, context, operation) {
|
|
1049
|
+
const func = operation === 'filter' ? 'isFilterable' : 'isOrderable';
|
|
1050
|
+
const failures = [];
|
|
1051
|
+
const returnTypeErrors = [];
|
|
1052
|
+
const accessErrors = [];
|
|
1053
|
+
for (const {
|
|
1054
|
+
fieldKey,
|
|
1055
|
+
list
|
|
1056
|
+
} of things) {
|
|
1057
|
+
const field = list.fields[fieldKey];
|
|
1058
|
+
const rule = field.graphql.isEnabled[operation];
|
|
1059
|
+
if (!rule) throw new Error('Assert failed');
|
|
1060
|
+
if (typeof rule === 'function') {
|
|
1061
|
+
let result;
|
|
1062
|
+
try {
|
|
1063
|
+
result = await rule({
|
|
1064
|
+
context,
|
|
1065
|
+
session: context.session,
|
|
1066
|
+
listKey: list.listKey,
|
|
1067
|
+
fieldKey
|
|
1068
|
+
});
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
accessErrors.push({
|
|
1071
|
+
error,
|
|
1072
|
+
tag: `${list.listKey}.${fieldKey}.${func}`
|
|
1073
|
+
});
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
const resultType = typeof result;
|
|
1077
|
+
|
|
1078
|
+
// It's important that we don't cast objects to truthy values, as there's a strong chance that the user
|
|
1079
|
+
// has made a mistake.
|
|
1080
|
+
if (resultType !== 'boolean') {
|
|
1081
|
+
returnTypeErrors.push({
|
|
1082
|
+
tag: `${list.listKey}.${fieldKey}.${func}`,
|
|
1083
|
+
returned: resultType
|
|
1084
|
+
});
|
|
1085
|
+
} else if (!result) {
|
|
1086
|
+
failures.push(`${list.listKey}.${fieldKey}`);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (accessErrors.length) {
|
|
1091
|
+
throw extensionError(func, accessErrors);
|
|
1092
|
+
}
|
|
1093
|
+
if (returnTypeErrors.length) {
|
|
1094
|
+
throw accessReturnError(returnTypeErrors);
|
|
1095
|
+
}
|
|
1096
|
+
if (failures.length) {
|
|
1097
|
+
throw filterAccessError({
|
|
1098
|
+
operation,
|
|
1099
|
+
fieldKeys: failures
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// we want to put the value we get back from the field's unique where resolver into an equals
|
|
1105
|
+
// rather than directly passing the value as the filter (even though Prisma supports that), we use equals
|
|
1106
|
+
// because we want to disallow fields from providing an arbitrary filter
|
|
1107
|
+
function mapUniqueWhereToWhere(uniqueWhere, list) {
|
|
1108
|
+
const where = {};
|
|
1109
|
+
for (const key in uniqueWhere) {
|
|
1110
|
+
if (list.fields[key].dbField.kind === 'relation') {
|
|
1111
|
+
const foreignList = list.lists[list.fields[key].dbField.list];
|
|
1112
|
+
where[key] = mapUniqueWhereToWhere(uniqueWhere[key], foreignList);
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
where[key] = {
|
|
1116
|
+
equals: uniqueWhere[key]
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
return where;
|
|
1120
|
+
}
|
|
1121
|
+
function* traverse(list, inputFilter) {
|
|
1122
|
+
for (const fieldKey in inputFilter) {
|
|
1123
|
+
const value = inputFilter[fieldKey];
|
|
1124
|
+
if (fieldKey === 'OR' || fieldKey === 'AND' || fieldKey === 'NOT') {
|
|
1125
|
+
for (const condition of value) {
|
|
1126
|
+
yield* traverse(list, condition);
|
|
1127
|
+
}
|
|
1128
|
+
} else if (fieldKey === 'some' || fieldKey === 'none' || fieldKey === 'every') {
|
|
1129
|
+
yield* traverse(list, value);
|
|
1130
|
+
} else {
|
|
1131
|
+
yield {
|
|
1132
|
+
fieldKey,
|
|
1133
|
+
list
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
// if it's a relationship, check the nested filters.
|
|
1137
|
+
const field = list.fields[fieldKey];
|
|
1138
|
+
if (field.dbField.kind === 'relation' && value !== null) {
|
|
1139
|
+
const foreignList = list.lists[field.dbField.list];
|
|
1140
|
+
yield* traverse(foreignList, value);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
async function accessControlledFilter(list, context, resolvedWhere, accessFilters) {
|
|
1146
|
+
// Merge the filter access control
|
|
1147
|
+
if (typeof accessFilters === 'object') {
|
|
1148
|
+
resolvedWhere = {
|
|
1149
|
+
AND: [resolvedWhere, await resolveWhereInput(accessFilters, list, context)]
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
return resolvedWhere;
|
|
1153
|
+
}
|
|
1154
|
+
async function findOne(args, list, context, info) {
|
|
1155
|
+
// check operation permission to pass into single operation
|
|
1156
|
+
const operationAccess = await getOperationAccess(list, context, 'query');
|
|
1157
|
+
if (!operationAccess) return null;
|
|
1158
|
+
const accessFilters = await getAccessFilters(list, context, 'query');
|
|
1159
|
+
if (accessFilters === false) return null;
|
|
1160
|
+
|
|
1161
|
+
// validate and resolve the input filter
|
|
1162
|
+
const uniqueWhere = await resolveUniqueWhereInput(args.where, list, context);
|
|
1163
|
+
const resolvedWhere = mapUniqueWhereToWhere(uniqueWhere, list);
|
|
1164
|
+
|
|
1165
|
+
// findOne requires at least one filter
|
|
1166
|
+
if (Object.keys(resolvedWhere).length === 0) return null;
|
|
1167
|
+
|
|
1168
|
+
// check filter access
|
|
1169
|
+
await checkFilterOrderAccess([...traverse(list, args.where)], context, 'filter');
|
|
1170
|
+
|
|
1171
|
+
// apply access control
|
|
1172
|
+
const filter = await accessControlledFilter(list, context, resolvedWhere, accessFilters);
|
|
1173
|
+
const result = await context.prisma[list.listKey].findFirst({
|
|
1174
|
+
where: filter
|
|
1175
|
+
});
|
|
1176
|
+
if (list.cacheHint) {
|
|
1177
|
+
var _maybeCacheControlFro, _info$operation$name;
|
|
1178
|
+
(_maybeCacheControlFro = maybeCacheControlFromInfo(info)) === null || _maybeCacheControlFro === void 0 || _maybeCacheControlFro.setCacheHint(list.cacheHint({
|
|
1179
|
+
results: result ? [result] : [],
|
|
1180
|
+
operationName: (_info$operation$name = info.operation.name) === null || _info$operation$name === void 0 ? void 0 : _info$operation$name.value,
|
|
1181
|
+
meta: false
|
|
1182
|
+
}));
|
|
1183
|
+
}
|
|
1184
|
+
return result;
|
|
1185
|
+
}
|
|
1186
|
+
async function findMany({
|
|
1187
|
+
where,
|
|
1188
|
+
take,
|
|
1189
|
+
skip,
|
|
1190
|
+
orderBy: rawOrderBy,
|
|
1191
|
+
cursor
|
|
1192
|
+
}, list, context, info, extraFilter) {
|
|
1193
|
+
var _list$graphql$types$f;
|
|
1194
|
+
const maxTake = (_list$graphql$types$f = list.graphql.types.findManyArgs.take.defaultValue) !== null && _list$graphql$types$f !== void 0 ? _list$graphql$types$f : Infinity;
|
|
1195
|
+
if ((take !== null && take !== void 0 ? take : Infinity) > maxTake) {
|
|
1196
|
+
throw limitsExceededError({
|
|
1197
|
+
list: list.listKey,
|
|
1198
|
+
type: 'maxTake',
|
|
1199
|
+
limit: maxTake
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// check operation permission to pass into single operation
|
|
1204
|
+
const operationAccess = await getOperationAccess(list, context, 'query');
|
|
1205
|
+
if (!operationAccess) return [];
|
|
1206
|
+
const accessFilters = await getAccessFilters(list, context, 'query');
|
|
1207
|
+
if (accessFilters === false) return [];
|
|
1208
|
+
|
|
1209
|
+
// validate and resolve the input filter
|
|
1210
|
+
const resolvedWhere = await resolveWhereInput(where, list, context);
|
|
1211
|
+
|
|
1212
|
+
// check filter access (TODO: why isn't this using resolvedWhere)
|
|
1213
|
+
await checkFilterOrderAccess([...traverse(list, where)], context, 'filter');
|
|
1214
|
+
|
|
1215
|
+
// check filter access for cursor
|
|
1216
|
+
if (cursor) {
|
|
1217
|
+
await checkFilterOrderAccess([...traverse(list, cursor)], context, 'filter');
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// WARNING: this checks .isOrderable
|
|
1221
|
+
const orderBy = await resolveOrderBy(rawOrderBy, list, context);
|
|
1222
|
+
|
|
1223
|
+
// apply access control
|
|
1224
|
+
const filter = await accessControlledFilter(list, context, resolvedWhere, accessFilters);
|
|
1225
|
+
const results = await context.prisma[list.listKey].findMany({
|
|
1226
|
+
where: extraFilter === undefined ? filter : {
|
|
1227
|
+
AND: [filter, extraFilter]
|
|
1228
|
+
},
|
|
1229
|
+
orderBy,
|
|
1230
|
+
take: take !== null && take !== void 0 ? take : undefined,
|
|
1231
|
+
skip,
|
|
1232
|
+
cursor: cursor !== null && cursor !== void 0 ? cursor : undefined
|
|
1233
|
+
});
|
|
1234
|
+
if (list.cacheHint) {
|
|
1235
|
+
var _maybeCacheControlFro2, _info$operation$name2;
|
|
1236
|
+
(_maybeCacheControlFro2 = maybeCacheControlFromInfo(info)) === null || _maybeCacheControlFro2 === void 0 || _maybeCacheControlFro2.setCacheHint(list.cacheHint({
|
|
1237
|
+
results,
|
|
1238
|
+
operationName: (_info$operation$name2 = info.operation.name) === null || _info$operation$name2 === void 0 ? void 0 : _info$operation$name2.value,
|
|
1239
|
+
meta: false
|
|
1240
|
+
}));
|
|
1241
|
+
}
|
|
1242
|
+
return results;
|
|
1243
|
+
}
|
|
1244
|
+
async function resolveOrderBy(orderBy, list, context) {
|
|
1245
|
+
// Check input format. FIXME: Group all errors
|
|
1246
|
+
orderBy.forEach(orderBySelection => {
|
|
1247
|
+
const keys = Object.keys(orderBySelection);
|
|
1248
|
+
if (keys.length !== 1) {
|
|
1249
|
+
throw userInputError(`Only a single key must be passed to ${list.graphql.types.orderBy.name}`);
|
|
1250
|
+
}
|
|
1251
|
+
const fieldKey = keys[0];
|
|
1252
|
+
const value = orderBySelection[fieldKey];
|
|
1253
|
+
if (value === null) {
|
|
1254
|
+
throw userInputError('null cannot be passed as an order direction');
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
// Check orderBy access
|
|
1259
|
+
const orderByKeys = orderBy.map(orderBySelection => ({
|
|
1260
|
+
fieldKey: Object.keys(orderBySelection)[0],
|
|
1261
|
+
list
|
|
1262
|
+
}));
|
|
1263
|
+
await checkFilterOrderAccess(orderByKeys, context, 'orderBy');
|
|
1264
|
+
return await Promise.all(orderBy.map(async orderBySelection => {
|
|
1265
|
+
const keys = Object.keys(orderBySelection);
|
|
1266
|
+
const fieldKey = keys[0];
|
|
1267
|
+
const value = orderBySelection[fieldKey];
|
|
1268
|
+
const field = list.fields[fieldKey];
|
|
1269
|
+
const resolve = field.input.orderBy.resolve;
|
|
1270
|
+
const resolvedValue = resolve ? await resolve(value, context) : value;
|
|
1271
|
+
if (field.dbField.kind === 'multi') {
|
|
1272
|
+
// Note: no built-in field types support multi valued database fields *and* orderBy.
|
|
1273
|
+
// This code path is only relevent to custom fields which fit that criteria.
|
|
1274
|
+
const keys = Object.keys(resolvedValue);
|
|
1275
|
+
if (keys.length !== 1) {
|
|
1276
|
+
throw new Error(`Only a single key must be returned from an orderBy input resolver for a multi db field`);
|
|
1277
|
+
}
|
|
1278
|
+
const innerKey = keys[0];
|
|
1279
|
+
return {
|
|
1280
|
+
[getDBFieldKeyForFieldOnMultiField(fieldKey, innerKey)]: resolvedValue[innerKey]
|
|
1281
|
+
};
|
|
1282
|
+
} else {
|
|
1283
|
+
return {
|
|
1284
|
+
[fieldKey]: resolvedValue
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
}));
|
|
1288
|
+
}
|
|
1289
|
+
async function count({
|
|
1290
|
+
where
|
|
1291
|
+
}, list, context, info, extraFilter) {
|
|
1292
|
+
const operationAccess = await getOperationAccess(list, context, 'query');
|
|
1293
|
+
if (!operationAccess) return 0;
|
|
1294
|
+
const accessFilters = await getAccessFilters(list, context, 'query');
|
|
1295
|
+
if (accessFilters === false) return 0;
|
|
1296
|
+
const resolvedWhere = await resolveWhereInput(where, list, context);
|
|
1297
|
+
|
|
1298
|
+
// check filter access (TODO: why isn't this using resolvedWhere)
|
|
1299
|
+
await checkFilterOrderAccess([...traverse(list, where)], context, 'filter');
|
|
1300
|
+
const filter = await accessControlledFilter(list, context, resolvedWhere, accessFilters);
|
|
1301
|
+
const count = await context.prisma[list.listKey].count({
|
|
1302
|
+
where: extraFilter === undefined ? filter : {
|
|
1303
|
+
AND: [filter, extraFilter]
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
if (list.cacheHint) {
|
|
1307
|
+
var _maybeCacheControlFro3, _info$operation$name3;
|
|
1308
|
+
(_maybeCacheControlFro3 = maybeCacheControlFromInfo(info)) === null || _maybeCacheControlFro3 === void 0 || _maybeCacheControlFro3.setCacheHint(list.cacheHint({
|
|
1309
|
+
results: count,
|
|
1310
|
+
operationName: (_info$operation$name3 = info.operation.name) === null || _info$operation$name3 === void 0 ? void 0 : _info$operation$name3.value,
|
|
1311
|
+
meta: true
|
|
1312
|
+
}));
|
|
1313
|
+
}
|
|
1314
|
+
return count;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
function getRelationVal(dbField, id, foreignList, context, info, fk) {
|
|
1318
|
+
const oppositeDbField = foreignList.resolvedDbFields[dbField.field];
|
|
1319
|
+
if (oppositeDbField.kind !== 'relation') throw new Error('failed assert');
|
|
1320
|
+
if (dbField.mode === 'many') {
|
|
1321
|
+
const relationFilter = {
|
|
1322
|
+
[dbField.field]: oppositeDbField.mode === 'many' ? {
|
|
1323
|
+
some: {
|
|
1324
|
+
id
|
|
1325
|
+
}
|
|
1326
|
+
} : {
|
|
1327
|
+
id
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
return {
|
|
1331
|
+
findMany: async args => findMany(args, foreignList, context, info, relationFilter),
|
|
1332
|
+
count: async ({
|
|
1333
|
+
where
|
|
1334
|
+
}) => count({
|
|
1335
|
+
where
|
|
1336
|
+
}, foreignList, context, info, relationFilter)
|
|
1337
|
+
};
|
|
1338
|
+
} else {
|
|
1339
|
+
return async () => {
|
|
1340
|
+
if (fk === null) {
|
|
1341
|
+
// If the foreign key is explicitly null, there's no need to anything else,
|
|
1342
|
+
// since we know the related item doesn't exist.
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
1345
|
+
// for one-to-many relationships, the one side always owns the foreign key
|
|
1346
|
+
// so that means we have the id for the related item and we're fetching it by _its_ id.
|
|
1347
|
+
// for the a one-to-one relationship though, the id might be on the related item
|
|
1348
|
+
// so we need to fetch the related item by the id of the current item on the foreign key field
|
|
1349
|
+
const currentItemOwnsForeignKey = fk !== undefined;
|
|
1350
|
+
return fetchRelatedItem(context)(foreignList)(currentItemOwnsForeignKey ? 'id' : `${dbField.field}Id`)(currentItemOwnsForeignKey ? fk : id);
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function memoize(cb) {
|
|
1355
|
+
const cache = new Map();
|
|
1356
|
+
return arg => {
|
|
1357
|
+
if (!cache.has(arg)) {
|
|
1358
|
+
const result = cb(arg);
|
|
1359
|
+
cache.set(arg, result);
|
|
1360
|
+
}
|
|
1361
|
+
return cache.get(arg);
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
const fetchRelatedItem = weakMemoize(context => weakMemoize(foreignList => memoize(idFieldKey => {
|
|
1365
|
+
const relatedItemLoader = new DataLoader(keys => fetchRelatedItems(context, foreignList, idFieldKey, keys), {
|
|
1366
|
+
cache: false
|
|
1367
|
+
});
|
|
1368
|
+
return id => relatedItemLoader.load(id);
|
|
1369
|
+
})));
|
|
1370
|
+
async function fetchRelatedItems(context, foreignList, idFieldKey, toFetch) {
|
|
1371
|
+
const operationAccess = await getOperationAccess(foreignList, context, 'query');
|
|
1372
|
+
if (!operationAccess) {
|
|
1373
|
+
return toFetch.map(() => undefined);
|
|
1374
|
+
}
|
|
1375
|
+
const accessFilters = await getAccessFilters(foreignList, context, 'query');
|
|
1376
|
+
if (accessFilters === false) {
|
|
1377
|
+
return toFetch.map(() => undefined);
|
|
1378
|
+
}
|
|
1379
|
+
const toFetchUnique = Array.from(new Set(toFetch));
|
|
1380
|
+
const resolvedWhere = await accessControlledFilter(foreignList, context, {
|
|
1381
|
+
[idFieldKey]: {
|
|
1382
|
+
in: toFetchUnique
|
|
1383
|
+
}
|
|
1384
|
+
}, accessFilters);
|
|
1385
|
+
const results = await context.prisma[foreignList.listKey].findMany({
|
|
1386
|
+
where: resolvedWhere
|
|
1387
|
+
});
|
|
1388
|
+
const resultsById = new Map(results.map(x => [x[idFieldKey], x]));
|
|
1389
|
+
return toFetch.map(id => resultsById.get(id));
|
|
1390
|
+
}
|
|
1391
|
+
function getValueForDBField(item, dbField, id, fieldPath, context, lists, info) {
|
|
1392
|
+
if (dbField.kind === 'multi') {
|
|
1393
|
+
return Object.fromEntries(Object.keys(dbField.fields).map(innerDBFieldKey => {
|
|
1394
|
+
const keyOnDbValue = getDBFieldKeyForFieldOnMultiField(fieldPath, innerDBFieldKey);
|
|
1395
|
+
return [innerDBFieldKey, item[keyOnDbValue]];
|
|
1396
|
+
}));
|
|
1397
|
+
}
|
|
1398
|
+
if (dbField.kind === 'relation') {
|
|
1399
|
+
// If we're holding a foreign key value, let's take advantage of that.
|
|
1400
|
+
let fk;
|
|
1401
|
+
if (dbField.mode === 'one' && dbField.foreignIdField.kind !== 'none') {
|
|
1402
|
+
fk = item[`${fieldPath}Id`];
|
|
1403
|
+
}
|
|
1404
|
+
return getRelationVal(dbField, id, lists[dbField.list], context, info, fk);
|
|
1405
|
+
} else {
|
|
1406
|
+
return item[fieldPath];
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
function outputTypeField(output, dbField, cacheHint, access, listKey, fieldKey, lists) {
|
|
1410
|
+
const list = lists[listKey];
|
|
1411
|
+
return g.field({
|
|
1412
|
+
type: output.type,
|
|
1413
|
+
deprecationReason: output.deprecationReason,
|
|
1414
|
+
description: output.description,
|
|
1415
|
+
args: output.args,
|
|
1416
|
+
extensions: output.extensions,
|
|
1417
|
+
async resolve(item, args, context, info) {
|
|
1418
|
+
const id = item.id;
|
|
1419
|
+
const fieldAccess = await getOperationFieldAccess(item, list, fieldKey, context, 'read');
|
|
1420
|
+
if (!fieldAccess) return null;
|
|
1421
|
+
|
|
1422
|
+
// only static cache hints are supported at the field level until a use-case makes it clear what parameters a dynamic hint would take
|
|
1423
|
+
if (cacheHint && info) {
|
|
1424
|
+
var _maybeCacheControlFro;
|
|
1425
|
+
(_maybeCacheControlFro = maybeCacheControlFromInfo(info)) === null || _maybeCacheControlFro === void 0 || _maybeCacheControlFro.setCacheHint(cacheHint);
|
|
1426
|
+
}
|
|
1427
|
+
const value = getValueForDBField(item, dbField, id, fieldKey, context, lists, info);
|
|
1428
|
+
if (output.resolve) {
|
|
1429
|
+
return output.resolve({
|
|
1430
|
+
value,
|
|
1431
|
+
item: item
|
|
1432
|
+
}, args, context, info);
|
|
1433
|
+
} else {
|
|
1434
|
+
return value;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// note: all nixxie fields correspond to a field here
|
|
1441
|
+
// not all fields here correspond to nixxie fields(the implicit side of one-sided relation fields)
|
|
1442
|
+
|
|
1443
|
+
function sortRelationships(left, right) {
|
|
1444
|
+
if (left.field.mode === 'one' && right.field.mode === 'one') {
|
|
1445
|
+
if (left.field.foreignKey !== undefined && right.field.foreignKey !== undefined) {
|
|
1446
|
+
throw new Error(`You can only set db.foreignKey on one side of a one to one relationship, but foreignKey is set on both ${left.listKey}.${left.fieldPath} and ${right.listKey}.${right.fieldPath}`);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
// return the field that specifies the foreignKey first
|
|
1450
|
+
if (left.field.foreignKey) return [left, right];
|
|
1451
|
+
if (right.field.foreignKey) return [right, left];
|
|
1452
|
+
} else if (left.field.mode === 'one' || right.field.mode === 'one') {
|
|
1453
|
+
// many relationships will never have a foreign key, so return the one relationship first
|
|
1454
|
+
const rels = left.field.mode === 'one' ? [left, right] : [right, left];
|
|
1455
|
+
// we're only doing this for rels[1] because:
|
|
1456
|
+
// - rels[1] is the many side
|
|
1457
|
+
// - for the one side, TypeScript will already disallow relationName
|
|
1458
|
+
if (rels[1].field.relationName !== undefined) throw new Error(`You can only set db.relationName on one side of a many to many relationship, but db.relationName is set on ${rels[1].listKey}.${rels[1].fieldPath} which is the many side of a many to one relationship with ${rels[0].listKey}.${rels[0].fieldPath}`);
|
|
1459
|
+
return rels;
|
|
1460
|
+
}
|
|
1461
|
+
if (left.field.mode === 'many' && right.field.mode === 'many' && (left.field.relationName !== undefined || right.field.relationName !== undefined)) {
|
|
1462
|
+
if (left.field.relationName !== undefined && right.field.relationName !== undefined) {
|
|
1463
|
+
throw new Error(`You can only set db.relationName on one side of a many to many relationship, but db.relationName is set on both ${left.listKey}.${left.fieldPath} and ${right.listKey}.${right.fieldPath}`);
|
|
1464
|
+
}
|
|
1465
|
+
return left.field.relationName !== undefined ? [left, right] : [right, left];
|
|
1466
|
+
}
|
|
1467
|
+
const order = left.listKey.localeCompare(right.listKey);
|
|
1468
|
+
if (order > 0) return [right, left]; // left comes after right, so swap them
|
|
1469
|
+
if (order === 0) {
|
|
1470
|
+
// self referential list, so check the paths.
|
|
1471
|
+
if (left.fieldPath.localeCompare(right.fieldPath) > 0) {
|
|
1472
|
+
return [right, left];
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
return [left, right];
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// what's going on here:
|
|
1479
|
+
// - validating all the relationships
|
|
1480
|
+
// - for relationships involving to-one: deciding which side owns the foreign key
|
|
1481
|
+
// - turning one-sided relationships into two-sided relationships so that elsewhere in Nixxie,
|
|
1482
|
+
// you only have to reason about two-sided relationships
|
|
1483
|
+
// (note that this means that there are "fields" in the returned ListsWithResolvedRelations
|
|
1484
|
+
// which are not actually proper Nixxie fields, they are just a db field and nothing else)
|
|
1485
|
+
function resolveRelationships(lists) {
|
|
1486
|
+
const alreadyResolvedTwoSidedRelationships = new Set();
|
|
1487
|
+
const resolvedLists = Object.fromEntries(Object.keys(lists).map(listKey => [listKey, {}]));
|
|
1488
|
+
for (const [listKey, fields] of Object.entries(lists)) {
|
|
1489
|
+
const resolvedList = resolvedLists[listKey];
|
|
1490
|
+
for (const [fieldPath, {
|
|
1491
|
+
dbField: field
|
|
1492
|
+
}] of Object.entries(fields.fields)) {
|
|
1493
|
+
if (field.kind !== 'relation') {
|
|
1494
|
+
resolvedList[fieldPath] = field;
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
const foreignUnresolvedList = lists[field.list];
|
|
1498
|
+
if (!foreignUnresolvedList) {
|
|
1499
|
+
throw new Error(`The relationship field at ${listKey}.${fieldPath} points to the list ${listKey} which does not exist`);
|
|
1500
|
+
}
|
|
1501
|
+
if (foreignUnresolvedList.isSingleton) {
|
|
1502
|
+
throw new Error(`The relationship field at ${listKey}.${fieldPath} points to a singleton list, ${listKey}, which is not allowed`);
|
|
1503
|
+
}
|
|
1504
|
+
if (field.field) {
|
|
1505
|
+
var _foreignUnresolvedLis, _leftRel$field$foreig2;
|
|
1506
|
+
const localRef = `${listKey}.${fieldPath}`;
|
|
1507
|
+
const foreignRef = `${field.list}.${field.field}`;
|
|
1508
|
+
if (alreadyResolvedTwoSidedRelationships.has(localRef)) continue;
|
|
1509
|
+
alreadyResolvedTwoSidedRelationships.add(foreignRef);
|
|
1510
|
+
const foreignField = (_foreignUnresolvedLis = foreignUnresolvedList.fields[field.field]) === null || _foreignUnresolvedLis === void 0 ? void 0 : _foreignUnresolvedLis.dbField;
|
|
1511
|
+
if (!foreignField) throw new Error(`${localRef} points to ${foreignRef}, but ${foreignRef} doesn't exist`);
|
|
1512
|
+
if (foreignField.kind !== 'relation') {
|
|
1513
|
+
throw new Error(`${localRef} points to ${foreignRef}, but ${foreignRef} is not a relationship field`);
|
|
1514
|
+
}
|
|
1515
|
+
const actualRef = foreignField.field ? `${foreignField.list}.${foreignField.field}` : foreignField.list;
|
|
1516
|
+
if (actualRef !== localRef) {
|
|
1517
|
+
throw new Error(`${localRef} expects ${foreignRef} to be a two way relationship, but ${foreignRef} points to ${actualRef}`);
|
|
1518
|
+
}
|
|
1519
|
+
const [leftRel, rightRel] = sortRelationships({
|
|
1520
|
+
listKey,
|
|
1521
|
+
fieldPath,
|
|
1522
|
+
field
|
|
1523
|
+
}, {
|
|
1524
|
+
listKey: field.list,
|
|
1525
|
+
fieldPath: field.field,
|
|
1526
|
+
field: foreignField
|
|
1527
|
+
});
|
|
1528
|
+
if (leftRel.field.mode === 'one' && rightRel.field.mode === 'one') {
|
|
1529
|
+
var _leftRel$field$foreig;
|
|
1530
|
+
const relationName = `${leftRel.listKey}_${leftRel.fieldPath}`;
|
|
1531
|
+
resolvedLists[leftRel.listKey][leftRel.fieldPath] = {
|
|
1532
|
+
kind: 'relation',
|
|
1533
|
+
mode: 'one',
|
|
1534
|
+
field: rightRel.fieldPath,
|
|
1535
|
+
list: rightRel.listKey,
|
|
1536
|
+
extendPrismaSchema: leftRel.field.extendPrismaSchema,
|
|
1537
|
+
foreignIdField: {
|
|
1538
|
+
kind: 'owned-unique',
|
|
1539
|
+
map: typeof leftRel.field.foreignKey === 'object' ? (_leftRel$field$foreig = leftRel.field.foreignKey) === null || _leftRel$field$foreig === void 0 ? void 0 : _leftRel$field$foreig.map : leftRel.fieldPath
|
|
1540
|
+
},
|
|
1541
|
+
relationName
|
|
1542
|
+
};
|
|
1543
|
+
resolvedLists[rightRel.listKey][rightRel.fieldPath] = {
|
|
1544
|
+
kind: 'relation',
|
|
1545
|
+
mode: 'one',
|
|
1546
|
+
field: leftRel.fieldPath,
|
|
1547
|
+
list: leftRel.listKey,
|
|
1548
|
+
extendPrismaSchema: rightRel.field.extendPrismaSchema,
|
|
1549
|
+
foreignIdField: {
|
|
1550
|
+
kind: 'none'
|
|
1551
|
+
},
|
|
1552
|
+
relationName
|
|
1553
|
+
};
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
if (leftRel.field.mode === 'many' && rightRel.field.mode === 'many') {
|
|
1557
|
+
var _leftRel$field$relati;
|
|
1558
|
+
const relationName = (_leftRel$field$relati = leftRel.field.relationName) !== null && _leftRel$field$relati !== void 0 ? _leftRel$field$relati : `${leftRel.listKey}_${leftRel.fieldPath}`;
|
|
1559
|
+
resolvedLists[leftRel.listKey][leftRel.fieldPath] = {
|
|
1560
|
+
kind: 'relation',
|
|
1561
|
+
mode: 'many',
|
|
1562
|
+
extendPrismaSchema: leftRel.field.extendPrismaSchema,
|
|
1563
|
+
field: rightRel.fieldPath,
|
|
1564
|
+
list: rightRel.listKey,
|
|
1565
|
+
relationName
|
|
1566
|
+
};
|
|
1567
|
+
resolvedLists[rightRel.listKey][rightRel.fieldPath] = {
|
|
1568
|
+
kind: 'relation',
|
|
1569
|
+
mode: 'many',
|
|
1570
|
+
extendPrismaSchema: rightRel.field.extendPrismaSchema,
|
|
1571
|
+
field: leftRel.fieldPath,
|
|
1572
|
+
list: leftRel.listKey,
|
|
1573
|
+
relationName
|
|
1574
|
+
};
|
|
1575
|
+
continue;
|
|
1576
|
+
}
|
|
1577
|
+
const relationName = `${leftRel.listKey}_${leftRel.fieldPath}`;
|
|
1578
|
+
resolvedLists[leftRel.listKey][leftRel.fieldPath] = {
|
|
1579
|
+
kind: 'relation',
|
|
1580
|
+
mode: 'one',
|
|
1581
|
+
field: rightRel.fieldPath,
|
|
1582
|
+
extendPrismaSchema: leftRel.field.extendPrismaSchema,
|
|
1583
|
+
list: rightRel.listKey,
|
|
1584
|
+
foreignIdField: {
|
|
1585
|
+
kind: 'owned',
|
|
1586
|
+
map: typeof leftRel.field.foreignKey === 'object' ? (_leftRel$field$foreig2 = leftRel.field.foreignKey) === null || _leftRel$field$foreig2 === void 0 ? void 0 : _leftRel$field$foreig2.map : leftRel.fieldPath
|
|
1587
|
+
},
|
|
1588
|
+
relationName
|
|
1589
|
+
};
|
|
1590
|
+
resolvedLists[rightRel.listKey][rightRel.fieldPath] = {
|
|
1591
|
+
kind: 'relation',
|
|
1592
|
+
mode: 'many',
|
|
1593
|
+
extendPrismaSchema: rightRel.field.extendPrismaSchema,
|
|
1594
|
+
field: leftRel.fieldPath,
|
|
1595
|
+
list: leftRel.listKey,
|
|
1596
|
+
relationName
|
|
1597
|
+
};
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
const foreignFieldPath = `from_${listKey}_${fieldPath}`;
|
|
1601
|
+
if (foreignUnresolvedList.fields[foreignFieldPath]) {
|
|
1602
|
+
throw new Error(`The relationship field at ${listKey}.${fieldPath} points to the list ${field.list}, Nixxie needs to a create a relationship field at ${field.list}.${foreignFieldPath} to support the relationship at ${listKey}.${fieldPath} but ${field.list} already has a field named ${foreignFieldPath}`);
|
|
1603
|
+
}
|
|
1604
|
+
if (field.mode === 'many') {
|
|
1605
|
+
var _field$relationName;
|
|
1606
|
+
const relationName = (_field$relationName = field.relationName) !== null && _field$relationName !== void 0 ? _field$relationName : `${listKey}_${fieldPath}`;
|
|
1607
|
+
resolvedLists[field.list][foreignFieldPath] = {
|
|
1608
|
+
kind: 'relation',
|
|
1609
|
+
mode: 'many',
|
|
1610
|
+
extendPrismaSchema: field.extendPrismaSchema,
|
|
1611
|
+
list: listKey,
|
|
1612
|
+
field: fieldPath,
|
|
1613
|
+
relationName
|
|
1614
|
+
};
|
|
1615
|
+
resolvedList[fieldPath] = {
|
|
1616
|
+
kind: 'relation',
|
|
1617
|
+
mode: 'many',
|
|
1618
|
+
extendPrismaSchema: field.extendPrismaSchema,
|
|
1619
|
+
list: field.list,
|
|
1620
|
+
field: foreignFieldPath,
|
|
1621
|
+
relationName
|
|
1622
|
+
};
|
|
1623
|
+
} else {
|
|
1624
|
+
var _field$foreignKey;
|
|
1625
|
+
const relationName = `${listKey}_${fieldPath}`;
|
|
1626
|
+
resolvedLists[field.list][foreignFieldPath] = {
|
|
1627
|
+
kind: 'relation',
|
|
1628
|
+
mode: 'many',
|
|
1629
|
+
extendPrismaSchema: field.extendPrismaSchema,
|
|
1630
|
+
list: listKey,
|
|
1631
|
+
field: fieldPath,
|
|
1632
|
+
relationName
|
|
1633
|
+
};
|
|
1634
|
+
resolvedList[fieldPath] = {
|
|
1635
|
+
kind: 'relation',
|
|
1636
|
+
list: field.list,
|
|
1637
|
+
extendPrismaSchema: field.extendPrismaSchema,
|
|
1638
|
+
field: foreignFieldPath,
|
|
1639
|
+
foreignIdField: {
|
|
1640
|
+
kind: 'owned',
|
|
1641
|
+
map: typeof field.foreignKey === 'object' ? (_field$foreignKey = field.foreignKey) === null || _field$foreignKey === void 0 ? void 0 : _field$foreignKey.map : fieldPath
|
|
1642
|
+
},
|
|
1643
|
+
relationName,
|
|
1644
|
+
mode: 'one'
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// the way we resolve the relationships means that the relationships will be in a
|
|
1651
|
+
// different order than the order the user specified in their config
|
|
1652
|
+
// doesn't really change the behaviour of anything but it means that the order of the fields in the prisma schema will be
|
|
1653
|
+
// the same as the user provided
|
|
1654
|
+
return Object.fromEntries(Object.entries(resolvedLists).map(([listKey, outOfOrderDbFields]) => {
|
|
1655
|
+
// this adds the fields based on the order that the user passed in
|
|
1656
|
+
// (except it will not add the opposites to one-sided relations)
|
|
1657
|
+
const resolvedDbFields = Object.fromEntries(Object.keys(lists[listKey].fields).map(fieldKey => [fieldKey, outOfOrderDbFields[fieldKey]]));
|
|
1658
|
+
// then we add the opposites to one-sided relations
|
|
1659
|
+
Object.assign(resolvedDbFields, outOfOrderDbFields);
|
|
1660
|
+
return [listKey, resolvedDbFields];
|
|
1661
|
+
}));
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
function printGraphQLType(type) {
|
|
1665
|
+
if (type instanceof GraphQLNonNull) return `${printGraphQLType(type.ofType)}!`;
|
|
1666
|
+
if (type instanceof GraphQLList) return `[${printGraphQLType(type.ofType)}]`;
|
|
1667
|
+
return type.name;
|
|
1668
|
+
}
|
|
1669
|
+
function getArgSources(action) {
|
|
1670
|
+
var _action$args;
|
|
1671
|
+
return Object.fromEntries(Object.entries((_action$args = action.args) !== null && _action$args !== void 0 ? _action$args : {}).flatMap(([arg, value]) => {
|
|
1672
|
+
var _value$ui;
|
|
1673
|
+
const field = (_value$ui = value.ui) === null || _value$ui === void 0 || (_value$ui = _value$ui.source) === null || _value$ui === void 0 ? void 0 : _value$ui.itemField;
|
|
1674
|
+
if (!field) return [];
|
|
1675
|
+
return [[arg, {
|
|
1676
|
+
itemField: field
|
|
1677
|
+
}]];
|
|
1678
|
+
}));
|
|
1679
|
+
}
|
|
1680
|
+
function throwIfNotAFilter(x, listKey, fieldKey) {
|
|
1681
|
+
if (['boolean', 'undefined', 'function'].includes(typeof x)) return;
|
|
1682
|
+
throw new Error(`Configuration option '${listKey}.${fieldKey}' must be either a boolean value or a function. Received '${x}'.`);
|
|
1683
|
+
}
|
|
1684
|
+
// TODO: move to defaultLists?
|
|
1685
|
+
function getIsEnabled(listKey, listConfig) {
|
|
1686
|
+
var _listConfig$graphql$o;
|
|
1687
|
+
const omit = (_listConfig$graphql$o = listConfig.graphql.omit) !== null && _listConfig$graphql$o !== void 0 ? _listConfig$graphql$o : false;
|
|
1688
|
+
const {
|
|
1689
|
+
defaultIsFilterable,
|
|
1690
|
+
defaultIsOrderable
|
|
1691
|
+
} = listConfig;
|
|
1692
|
+
throwIfNotAFilter(defaultIsFilterable, listKey, 'defaultIsFilterable');
|
|
1693
|
+
throwIfNotAFilter(defaultIsOrderable, listKey, 'defaultIsOrderable');
|
|
1694
|
+
if (typeof omit === 'boolean') {
|
|
1695
|
+
const notOmit = !omit;
|
|
1696
|
+
return {
|
|
1697
|
+
type: notOmit,
|
|
1698
|
+
query: notOmit,
|
|
1699
|
+
create: notOmit,
|
|
1700
|
+
update: notOmit,
|
|
1701
|
+
delete: notOmit,
|
|
1702
|
+
filter: notOmit ? defaultIsFilterable : false,
|
|
1703
|
+
orderBy: notOmit ? defaultIsOrderable : false
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
return {
|
|
1707
|
+
type: true,
|
|
1708
|
+
query: !omit.query,
|
|
1709
|
+
create: !omit.create,
|
|
1710
|
+
update: !omit.update,
|
|
1711
|
+
delete: !omit.delete,
|
|
1712
|
+
filter: defaultIsFilterable,
|
|
1713
|
+
orderBy: defaultIsOrderable
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
function getIsEnabledField(f, listKey, list, lists) {
|
|
1717
|
+
var _f$graphql$omit, _f$graphql;
|
|
1718
|
+
const omit = (_f$graphql$omit = (_f$graphql = f.graphql) === null || _f$graphql === void 0 ? void 0 : _f$graphql.omit) !== null && _f$graphql$omit !== void 0 ? _f$graphql$omit : false;
|
|
1719
|
+
const {
|
|
1720
|
+
isFilterable = list.graphql.isEnabled.filter,
|
|
1721
|
+
isOrderable = list.graphql.isEnabled.orderBy
|
|
1722
|
+
} = f;
|
|
1723
|
+
|
|
1724
|
+
// TODO: check types in initConfig
|
|
1725
|
+
throwIfNotAFilter(isFilterable, listKey, 'isFilterable');
|
|
1726
|
+
throwIfNotAFilter(isOrderable, listKey, 'isOrderable');
|
|
1727
|
+
if (f.dbField.kind === 'relation') {
|
|
1728
|
+
if (!lists[f.dbField.list].graphql.isEnabled.type) {
|
|
1729
|
+
return {
|
|
1730
|
+
type: false,
|
|
1731
|
+
read: false,
|
|
1732
|
+
create: false,
|
|
1733
|
+
update: false,
|
|
1734
|
+
filter: false,
|
|
1735
|
+
orderBy: false
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
if (typeof omit === 'boolean') {
|
|
1740
|
+
const notOmit = !omit;
|
|
1741
|
+
return {
|
|
1742
|
+
type: notOmit,
|
|
1743
|
+
read: notOmit,
|
|
1744
|
+
create: notOmit,
|
|
1745
|
+
update: notOmit,
|
|
1746
|
+
filter: notOmit ? isFilterable : false,
|
|
1747
|
+
orderBy: notOmit ? isOrderable : false
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
return {
|
|
1751
|
+
type: true,
|
|
1752
|
+
read: !omit.read,
|
|
1753
|
+
create: !omit.create,
|
|
1754
|
+
update: !omit.update,
|
|
1755
|
+
filter: !omit.read ? isFilterable : false,
|
|
1756
|
+
// prevent filtering if read is false
|
|
1757
|
+
orderBy: !omit.read ? isOrderable : false // prevent ordering if read is false
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
function defaultListHooksResolveInput({
|
|
1761
|
+
resolvedData
|
|
1762
|
+
}) {
|
|
1763
|
+
return resolvedData;
|
|
1764
|
+
}
|
|
1765
|
+
function parseListHooks(hooks) {
|
|
1766
|
+
var _hooks$resolveInput$c, _hooks$resolveInput, _hooks$resolveInput$u, _hooks$resolveInput2;
|
|
1767
|
+
return {
|
|
1768
|
+
resolveInput: {
|
|
1769
|
+
create: typeof hooks.resolveInput === 'function' ? hooks.resolveInput : (_hooks$resolveInput$c = (_hooks$resolveInput = hooks.resolveInput) === null || _hooks$resolveInput === void 0 ? void 0 : _hooks$resolveInput.create) !== null && _hooks$resolveInput$c !== void 0 ? _hooks$resolveInput$c : defaultListHooksResolveInput,
|
|
1770
|
+
update: typeof hooks.resolveInput === 'function' ? hooks.resolveInput : (_hooks$resolveInput$u = (_hooks$resolveInput2 = hooks.resolveInput) === null || _hooks$resolveInput2 === void 0 ? void 0 : _hooks$resolveInput2.update) !== null && _hooks$resolveInput$u !== void 0 ? _hooks$resolveInput$u : defaultListHooksResolveInput
|
|
1771
|
+
},
|
|
1772
|
+
validate: expandVoidHooks(hooks.validate),
|
|
1773
|
+
beforeOperation: expandVoidHooks(hooks.beforeOperation),
|
|
1774
|
+
afterOperation: expandVoidHooks(hooks.afterOperation)
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
function defaultFieldHooksResolveInput({
|
|
1778
|
+
resolvedData,
|
|
1779
|
+
fieldKey
|
|
1780
|
+
}) {
|
|
1781
|
+
return resolvedData[fieldKey];
|
|
1782
|
+
}
|
|
1783
|
+
function parseFieldHooks(hooks) {
|
|
1784
|
+
var _hooks$resolveInput$c2, _hooks$resolveInput3, _hooks$resolveInput$u2, _hooks$resolveInput4;
|
|
1785
|
+
return {
|
|
1786
|
+
resolveInput: {
|
|
1787
|
+
create: typeof hooks.resolveInput === 'function' ? hooks.resolveInput : (_hooks$resolveInput$c2 = (_hooks$resolveInput3 = hooks.resolveInput) === null || _hooks$resolveInput3 === void 0 ? void 0 : _hooks$resolveInput3.create) !== null && _hooks$resolveInput$c2 !== void 0 ? _hooks$resolveInput$c2 : defaultFieldHooksResolveInput,
|
|
1788
|
+
update: typeof hooks.resolveInput === 'function' ? hooks.resolveInput : (_hooks$resolveInput$u2 = (_hooks$resolveInput4 = hooks.resolveInput) === null || _hooks$resolveInput4 === void 0 ? void 0 : _hooks$resolveInput4.update) !== null && _hooks$resolveInput$u2 !== void 0 ? _hooks$resolveInput$u2 : defaultFieldHooksResolveInput
|
|
1789
|
+
},
|
|
1790
|
+
validate: expandVoidHooks(hooks.validate),
|
|
1791
|
+
beforeOperation: expandVoidHooks(hooks.beforeOperation),
|
|
1792
|
+
afterOperation: expandVoidHooks(hooks.afterOperation)
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
function getListsWithInitialisedFields(config, listsRef) {
|
|
1796
|
+
const {
|
|
1797
|
+
lists: listsConfig,
|
|
1798
|
+
db: {
|
|
1799
|
+
provider
|
|
1800
|
+
}
|
|
1801
|
+
} = config;
|
|
1802
|
+
const intermediateLists = Object.fromEntries(Object.values(config.lists).map(listConfig => [listConfig.listKey, {
|
|
1803
|
+
graphql: {
|
|
1804
|
+
isEnabled: getIsEnabled(listConfig.listKey, listConfig)
|
|
1805
|
+
}
|
|
1806
|
+
}]));
|
|
1807
|
+
const listGraphqlTypes = {};
|
|
1808
|
+
for (const listConfig of Object.values(listsConfig)) {
|
|
1809
|
+
var _listConfig$graphql;
|
|
1810
|
+
const {
|
|
1811
|
+
listKey
|
|
1812
|
+
} = listConfig;
|
|
1813
|
+
const {
|
|
1814
|
+
graphql: {
|
|
1815
|
+
names
|
|
1816
|
+
}
|
|
1817
|
+
} = __getNames(listKey, listConfig);
|
|
1818
|
+
const output = g.object()({
|
|
1819
|
+
name: names.outputTypeName,
|
|
1820
|
+
fields: () => {
|
|
1821
|
+
const {
|
|
1822
|
+
fields
|
|
1823
|
+
} = listsRef[listKey];
|
|
1824
|
+
return {
|
|
1825
|
+
...Object.fromEntries(Object.entries(fields).flatMap(([fieldPath, field]) => {
|
|
1826
|
+
if (!field.output || !field.graphql.isEnabled.read || field.dbField.kind === 'relation' && !intermediateLists[field.dbField.list].graphql.isEnabled.query) {
|
|
1827
|
+
return [];
|
|
1828
|
+
}
|
|
1829
|
+
const outputFieldRoot = graphqlForOutputField(field);
|
|
1830
|
+
return [[fieldPath, outputFieldRoot], ...Object.entries(field.extraOutputFields || {})].map(([outputTypeFieldName, outputField]) => {
|
|
1831
|
+
var _field$graphql;
|
|
1832
|
+
return [outputTypeFieldName, outputTypeField(outputField, field.dbField, (_field$graphql = field.graphql) === null || _field$graphql === void 0 ? void 0 : _field$graphql.cacheHint, field.access.read, listKey, fieldPath, listsRef)];
|
|
1833
|
+
});
|
|
1834
|
+
}))
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
});
|
|
1838
|
+
const uniqueWhere = g.inputObject({
|
|
1839
|
+
name: names.whereUniqueInputName,
|
|
1840
|
+
fields: () => {
|
|
1841
|
+
const {
|
|
1842
|
+
fields
|
|
1843
|
+
} = listsRef[listKey];
|
|
1844
|
+
return {
|
|
1845
|
+
...Object.fromEntries(Object.entries(fields).flatMap(([key, field]) => {
|
|
1846
|
+
var _field$input;
|
|
1847
|
+
if (!((_field$input = field.input) !== null && _field$input !== void 0 && (_field$input = _field$input.uniqueWhere) !== null && _field$input !== void 0 && _field$input.arg) || !field.graphql.isEnabled.read || !field.graphql.isEnabled.filter) {
|
|
1848
|
+
return [];
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
// only 1-to-1 relationships can have a uniqueWhere filter on relations
|
|
1852
|
+
if (field.dbField.kind === 'relation') {
|
|
1853
|
+
const remoteField = listsRef[field.dbField.list].resolvedDbFields[field.dbField.field];
|
|
1854
|
+
if (field.dbField.mode === 'one' && remoteField.kind === 'relation' && remoteField.mode === 'one') {
|
|
1855
|
+
return [[key, field.input.uniqueWhere.arg]];
|
|
1856
|
+
}
|
|
1857
|
+
return [];
|
|
1858
|
+
}
|
|
1859
|
+
return [[key, field.input.uniqueWhere.arg]];
|
|
1860
|
+
})),
|
|
1861
|
+
// this is exactly what the id field will add
|
|
1862
|
+
// but this does it more explicitly so that typescript understands
|
|
1863
|
+
id: g.arg({
|
|
1864
|
+
type: g.ID
|
|
1865
|
+
})
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
const where = g.inputObject({
|
|
1870
|
+
name: names.whereInputName,
|
|
1871
|
+
fields: () => {
|
|
1872
|
+
const {
|
|
1873
|
+
fields
|
|
1874
|
+
} = listsRef[listKey];
|
|
1875
|
+
return Object.assign({
|
|
1876
|
+
AND: g.arg({
|
|
1877
|
+
type: g.list(g.nonNull(where))
|
|
1878
|
+
}),
|
|
1879
|
+
OR: g.arg({
|
|
1880
|
+
type: g.list(g.nonNull(where))
|
|
1881
|
+
}),
|
|
1882
|
+
NOT: g.arg({
|
|
1883
|
+
type: g.list(g.nonNull(where))
|
|
1884
|
+
})
|
|
1885
|
+
}, ...Object.entries(fields).map(([fieldKey, field]) => {
|
|
1886
|
+
var _field$input2, _field$input3;
|
|
1887
|
+
return ((_field$input2 = field.input) === null || _field$input2 === void 0 || (_field$input2 = _field$input2.where) === null || _field$input2 === void 0 ? void 0 : _field$input2.arg) && field.graphql.isEnabled.read && field.graphql.isEnabled.filter && {
|
|
1888
|
+
[fieldKey]: (_field$input3 = field.input) === null || _field$input3 === void 0 || (_field$input3 = _field$input3.where) === null || _field$input3 === void 0 ? void 0 : _field$input3.arg
|
|
1889
|
+
};
|
|
1890
|
+
}));
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
const create = g.inputObject({
|
|
1894
|
+
name: names.createInputName,
|
|
1895
|
+
fields: () => {
|
|
1896
|
+
const {
|
|
1897
|
+
fields
|
|
1898
|
+
} = listsRef[listKey];
|
|
1899
|
+
const ret = {};
|
|
1900
|
+
for (const key in fields) {
|
|
1901
|
+
const arg = graphqlArgForInputField(fields[key], 'create', listsRef);
|
|
1902
|
+
if (!arg) continue;
|
|
1903
|
+
ret[key] = arg;
|
|
1904
|
+
}
|
|
1905
|
+
return ret;
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
const update = g.inputObject({
|
|
1909
|
+
name: names.updateInputName,
|
|
1910
|
+
fields: () => {
|
|
1911
|
+
const {
|
|
1912
|
+
fields
|
|
1913
|
+
} = listsRef[listKey];
|
|
1914
|
+
const ret = {};
|
|
1915
|
+
for (const key in fields) {
|
|
1916
|
+
const arg = graphqlArgForInputField(fields[key], 'update', listsRef);
|
|
1917
|
+
if (!arg) continue;
|
|
1918
|
+
ret[key] = arg;
|
|
1919
|
+
}
|
|
1920
|
+
return ret;
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
const orderBy = g.inputObject({
|
|
1924
|
+
name: names.listOrderName,
|
|
1925
|
+
fields: () => {
|
|
1926
|
+
const {
|
|
1927
|
+
fields
|
|
1928
|
+
} = listsRef[listKey];
|
|
1929
|
+
return Object.fromEntries(Object.entries(fields).flatMap(([key, field]) => {
|
|
1930
|
+
var _field$input4;
|
|
1931
|
+
if (!((_field$input4 = field.input) !== null && _field$input4 !== void 0 && (_field$input4 = _field$input4.orderBy) !== null && _field$input4 !== void 0 && _field$input4.arg) || !field.graphql.isEnabled.read || !field.graphql.isEnabled.orderBy) {
|
|
1932
|
+
return [];
|
|
1933
|
+
}
|
|
1934
|
+
return [[key, field.input.orderBy.arg]];
|
|
1935
|
+
}));
|
|
1936
|
+
}
|
|
1937
|
+
});
|
|
1938
|
+
let take = g.arg({
|
|
1939
|
+
type: g.Int
|
|
1940
|
+
});
|
|
1941
|
+
if (((_listConfig$graphql = listConfig.graphql) === null || _listConfig$graphql === void 0 ? void 0 : _listConfig$graphql.maxTake) !== undefined) {
|
|
1942
|
+
take = g.arg({
|
|
1943
|
+
type: g.nonNull(g.Int),
|
|
1944
|
+
// WARNING: used by queries/resolvers.ts to enforce the limit
|
|
1945
|
+
defaultValue: listConfig.graphql.maxTake
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
const findManyArgs = {
|
|
1949
|
+
where: g.arg({
|
|
1950
|
+
type: g.nonNull(where),
|
|
1951
|
+
defaultValue: listConfig.isSingleton ? {
|
|
1952
|
+
id: {
|
|
1953
|
+
equals: '1'
|
|
1954
|
+
}
|
|
1955
|
+
} : {}
|
|
1956
|
+
}),
|
|
1957
|
+
orderBy: g.arg({
|
|
1958
|
+
type: g.nonNull(g.list(g.nonNull(orderBy))),
|
|
1959
|
+
defaultValue: []
|
|
1960
|
+
}),
|
|
1961
|
+
take,
|
|
1962
|
+
skip: g.arg({
|
|
1963
|
+
type: g.nonNull(g.Int),
|
|
1964
|
+
defaultValue: 0
|
|
1965
|
+
}),
|
|
1966
|
+
cursor: g.arg({
|
|
1967
|
+
type: uniqueWhere
|
|
1968
|
+
})
|
|
1969
|
+
};
|
|
1970
|
+
const relateToOneForCreate = g.inputObject({
|
|
1971
|
+
name: names.relateToOneForCreateInputName,
|
|
1972
|
+
fields: () => {
|
|
1973
|
+
const listRef = listsRef[listKey];
|
|
1974
|
+
return {
|
|
1975
|
+
...(listRef.graphql.isEnabled.create && {
|
|
1976
|
+
create: g.arg({
|
|
1977
|
+
type: listRef.graphql.types.create
|
|
1978
|
+
})
|
|
1979
|
+
}),
|
|
1980
|
+
connect: g.arg({
|
|
1981
|
+
type: listRef.graphql.types.uniqueWhere
|
|
1982
|
+
})
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1986
|
+
const relateToOneForUpdate = g.inputObject({
|
|
1987
|
+
name: names.relateToOneForUpdateInputName,
|
|
1988
|
+
fields: () => {
|
|
1989
|
+
const listRef = listsRef[listKey];
|
|
1990
|
+
return {
|
|
1991
|
+
...(listRef.graphql.isEnabled.create && {
|
|
1992
|
+
create: g.arg({
|
|
1993
|
+
type: listRef.graphql.types.create
|
|
1994
|
+
})
|
|
1995
|
+
}),
|
|
1996
|
+
connect: g.arg({
|
|
1997
|
+
type: listRef.graphql.types.uniqueWhere
|
|
1998
|
+
}),
|
|
1999
|
+
disconnect: g.arg({
|
|
2000
|
+
type: g.Boolean
|
|
2001
|
+
})
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
});
|
|
2005
|
+
const relateToManyForCreate = g.inputObject({
|
|
2006
|
+
name: names.relateToManyForCreateInputName,
|
|
2007
|
+
fields: () => {
|
|
2008
|
+
const listRef = listsRef[listKey];
|
|
2009
|
+
return {
|
|
2010
|
+
...(listRef.graphql.isEnabled.create && {
|
|
2011
|
+
create: g.arg({
|
|
2012
|
+
type: g.list(g.nonNull(listRef.graphql.types.create))
|
|
2013
|
+
})
|
|
2014
|
+
}),
|
|
2015
|
+
connect: g.arg({
|
|
2016
|
+
type: g.list(g.nonNull(listRef.graphql.types.uniqueWhere))
|
|
2017
|
+
}),
|
|
2018
|
+
set: g.arg({
|
|
2019
|
+
type: g.list(g.nonNull(listRef.graphql.types.uniqueWhere))
|
|
2020
|
+
})
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
});
|
|
2024
|
+
const relateToManyForUpdate = g.inputObject({
|
|
2025
|
+
name: names.relateToManyForUpdateInputName,
|
|
2026
|
+
fields: () => {
|
|
2027
|
+
const listRef = listsRef[listKey];
|
|
2028
|
+
return {
|
|
2029
|
+
// WARNING: the order of these fields reflects the order of mutations
|
|
2030
|
+
disconnect: g.arg({
|
|
2031
|
+
type: g.list(g.nonNull(listRef.graphql.types.uniqueWhere))
|
|
2032
|
+
}),
|
|
2033
|
+
set: g.arg({
|
|
2034
|
+
type: g.list(g.nonNull(listRef.graphql.types.uniqueWhere))
|
|
2035
|
+
}),
|
|
2036
|
+
...(listRef.graphql.isEnabled.create && {
|
|
2037
|
+
create: g.arg({
|
|
2038
|
+
type: g.list(g.nonNull(listRef.graphql.types.create))
|
|
2039
|
+
})
|
|
2040
|
+
}),
|
|
2041
|
+
connect: g.arg({
|
|
2042
|
+
type: g.list(g.nonNull(listRef.graphql.types.uniqueWhere))
|
|
2043
|
+
})
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
listGraphqlTypes[listKey] = {
|
|
2048
|
+
types: {
|
|
2049
|
+
output,
|
|
2050
|
+
uniqueWhere,
|
|
2051
|
+
where,
|
|
2052
|
+
create,
|
|
2053
|
+
orderBy,
|
|
2054
|
+
update,
|
|
2055
|
+
findManyArgs,
|
|
2056
|
+
relateTo: {
|
|
2057
|
+
one: {
|
|
2058
|
+
create: relateToOneForCreate,
|
|
2059
|
+
update: relateToOneForUpdate
|
|
2060
|
+
},
|
|
2061
|
+
many: {
|
|
2062
|
+
where: g.inputObject({
|
|
2063
|
+
name: `${listKey}ManyRelationFilter`,
|
|
2064
|
+
fields: {
|
|
2065
|
+
every: g.arg({
|
|
2066
|
+
type: where
|
|
2067
|
+
}),
|
|
2068
|
+
some: g.arg({
|
|
2069
|
+
type: where
|
|
2070
|
+
}),
|
|
2071
|
+
none: g.arg({
|
|
2072
|
+
type: where
|
|
2073
|
+
})
|
|
2074
|
+
}
|
|
2075
|
+
}),
|
|
2076
|
+
create: relateToManyForCreate,
|
|
2077
|
+
update: relateToManyForUpdate
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
const result = {};
|
|
2084
|
+
for (const listConfig of Object.values(listsConfig)) {
|
|
2085
|
+
var _listConfig$ui$labelF, _listConfig$ui$search, _listConfig$hooks, _listConfig$isSinglet;
|
|
2086
|
+
const {
|
|
2087
|
+
listKey
|
|
2088
|
+
} = listConfig;
|
|
2089
|
+
const intermediateList = intermediateLists[listKey];
|
|
2090
|
+
const resultFields = {};
|
|
2091
|
+
const groups = [];
|
|
2092
|
+
const fieldKeys = Object.keys(listConfig.fields);
|
|
2093
|
+
const fieldKeysToGroup = {};
|
|
2094
|
+
for (const [idx, [fieldKey, fieldFunc]] of Object.entries(listConfig.fields).entries()) {
|
|
2095
|
+
var _f$hooks, _f$graphql2, _f$graphql3, _f$graphql$isNonNull$, _f$graphql4, _f$graphql5, _f$graphql$isNonNull$2, _f$graphql6, _f$graphql7, _f$graphql$isNonNull$3, _f$graphql8, _f$ui, _f$ui$description, _f$ui2, _f$ui$views, _f$ui3, _f$ui$createView$isRe, _f$ui4, _ref, _ref2, _f$ui$createView$fiel, _f$ui5, _group$ui, _listConfig$ui$create, _f$ui$itemView$isRequ, _f$ui6, _f$ui$itemView$fieldP, _f$ui7, _ref3, _ref4, _f$ui$itemView$fieldM, _f$ui8, _group$ui2, _listConfig$ui$itemVi, _ref5, _ref6, _f$ui$itemView$fieldM2, _f$ui9, _group$ui3, _listConfig$ui$itemVi2, _ref7, _ref8, _f$ui$listView$fieldM, _f$ui0, _group$ui4, _listConfig$ui$listVi;
|
|
2096
|
+
if (fieldKey.startsWith('__group')) {
|
|
2097
|
+
const group__ = fieldFunc;
|
|
2098
|
+
if (typeof group__ === 'object' && group__ !== null && typeof group__.label === 'string' && (group__.description === null || typeof group__.description === 'string') && Array.isArray(group__.fields) && areArraysEqual(group__.fields, fieldKeys.slice(idx + 1, idx + 1 + group__.fields.length))) {
|
|
2099
|
+
groups.push(group__);
|
|
2100
|
+
for (const field of group__.fields) {
|
|
2101
|
+
fieldKeysToGroup[field] = group__;
|
|
2102
|
+
}
|
|
2103
|
+
continue;
|
|
2104
|
+
}
|
|
2105
|
+
throw new Error(`unexpected value for a group at ${listKey}.${fieldKey}`);
|
|
2106
|
+
}
|
|
2107
|
+
if (typeof fieldFunc !== 'function') {
|
|
2108
|
+
throw new Error(`The field at ${listKey}.${fieldKey} does not provide a function`);
|
|
2109
|
+
}
|
|
2110
|
+
const group = fieldKeysToGroup[fieldKey];
|
|
2111
|
+
const f = fieldFunc({
|
|
2112
|
+
provider,
|
|
2113
|
+
lists: listGraphqlTypes,
|
|
2114
|
+
listKey,
|
|
2115
|
+
fieldKey
|
|
2116
|
+
});
|
|
2117
|
+
const isEnabledField = getIsEnabledField(f, listKey, intermediateList, intermediateLists);
|
|
2118
|
+
resultFields[fieldKey] = {
|
|
2119
|
+
fieldKey,
|
|
2120
|
+
dbField: f.dbField,
|
|
2121
|
+
access: parseFieldAccessControl(f.access),
|
|
2122
|
+
hooks: parseFieldHooks((_f$hooks = f.hooks) !== null && _f$hooks !== void 0 ? _f$hooks : {}),
|
|
2123
|
+
graphql: {
|
|
2124
|
+
cacheHint: (_f$graphql2 = f.graphql) === null || _f$graphql2 === void 0 ? void 0 : _f$graphql2.cacheHint,
|
|
2125
|
+
isEnabled: isEnabledField,
|
|
2126
|
+
isNonNull: {
|
|
2127
|
+
read: typeof ((_f$graphql3 = f.graphql) === null || _f$graphql3 === void 0 ? void 0 : _f$graphql3.isNonNull) === 'boolean' ? f.graphql.isNonNull : (_f$graphql$isNonNull$ = (_f$graphql4 = f.graphql) === null || _f$graphql4 === void 0 || (_f$graphql4 = _f$graphql4.isNonNull) === null || _f$graphql4 === void 0 ? void 0 : _f$graphql4.read) !== null && _f$graphql$isNonNull$ !== void 0 ? _f$graphql$isNonNull$ : false,
|
|
2128
|
+
create: typeof ((_f$graphql5 = f.graphql) === null || _f$graphql5 === void 0 ? void 0 : _f$graphql5.isNonNull) === 'boolean' ? f.graphql.isNonNull : (_f$graphql$isNonNull$2 = (_f$graphql6 = f.graphql) === null || _f$graphql6 === void 0 || (_f$graphql6 = _f$graphql6.isNonNull) === null || _f$graphql6 === void 0 ? void 0 : _f$graphql6.create) !== null && _f$graphql$isNonNull$2 !== void 0 ? _f$graphql$isNonNull$2 : false,
|
|
2129
|
+
update: typeof ((_f$graphql7 = f.graphql) === null || _f$graphql7 === void 0 ? void 0 : _f$graphql7.isNonNull) === 'boolean' ? f.graphql.isNonNull : (_f$graphql$isNonNull$3 = (_f$graphql8 = f.graphql) === null || _f$graphql8 === void 0 || (_f$graphql8 = _f$graphql8.isNonNull) === null || _f$graphql8 === void 0 ? void 0 : _f$graphql8.update) !== null && _f$graphql$isNonNull$3 !== void 0 ? _f$graphql$isNonNull$3 : false
|
|
2130
|
+
}
|
|
2131
|
+
},
|
|
2132
|
+
ui: {
|
|
2133
|
+
label: ((_f$ui = f.ui) === null || _f$ui === void 0 ? void 0 : _f$ui.label) || humanize(fieldKey),
|
|
2134
|
+
description: (_f$ui$description = (_f$ui2 = f.ui) === null || _f$ui2 === void 0 ? void 0 : _f$ui2.description) !== null && _f$ui$description !== void 0 ? _f$ui$description : '',
|
|
2135
|
+
views: (_f$ui$views = (_f$ui3 = f.ui) === null || _f$ui3 === void 0 ? void 0 : _f$ui3.views) !== null && _f$ui$views !== void 0 ? _f$ui$views : null,
|
|
2136
|
+
createView: {
|
|
2137
|
+
isRequired: (_f$ui$createView$isRe = (_f$ui4 = f.ui) === null || _f$ui4 === void 0 || (_f$ui4 = _f$ui4.createView) === null || _f$ui4 === void 0 ? void 0 : _f$ui4.isRequired) !== null && _f$ui$createView$isRe !== void 0 ? _f$ui$createView$isRe : false,
|
|
2138
|
+
fieldMode: isEnabledField.create ? (_ref = (_ref2 = (_f$ui$createView$fiel = (_f$ui5 = f.ui) === null || _f$ui5 === void 0 || (_f$ui5 = _f$ui5.createView) === null || _f$ui5 === void 0 ? void 0 : _f$ui5.fieldMode) !== null && _f$ui$createView$fiel !== void 0 ? _f$ui$createView$fiel : group === null || group === void 0 || (_group$ui = group.ui) === null || _group$ui === void 0 || (_group$ui = _group$ui.createView) === null || _group$ui === void 0 ? void 0 : _group$ui.defaultFieldMode) !== null && _ref2 !== void 0 ? _ref2 : (_listConfig$ui$create = listConfig.ui.createView) === null || _listConfig$ui$create === void 0 ? void 0 : _listConfig$ui$create.defaultFieldMode) !== null && _ref !== void 0 ? _ref : 'edit' : 'hidden'
|
|
2139
|
+
},
|
|
2140
|
+
itemView: {
|
|
2141
|
+
isRequired: (_f$ui$itemView$isRequ = (_f$ui6 = f.ui) === null || _f$ui6 === void 0 || (_f$ui6 = _f$ui6.itemView) === null || _f$ui6 === void 0 ? void 0 : _f$ui6.isRequired) !== null && _f$ui$itemView$isRequ !== void 0 ? _f$ui$itemView$isRequ : false,
|
|
2142
|
+
fieldPosition: (_f$ui$itemView$fieldP = (_f$ui7 = f.ui) === null || _f$ui7 === void 0 || (_f$ui7 = _f$ui7.itemView) === null || _f$ui7 === void 0 ? void 0 : _f$ui7.fieldPosition) !== null && _f$ui$itemView$fieldP !== void 0 ? _f$ui$itemView$fieldP : 'form',
|
|
2143
|
+
fieldMode: isEnabledField.update ? (_ref3 = (_ref4 = (_f$ui$itemView$fieldM = (_f$ui8 = f.ui) === null || _f$ui8 === void 0 || (_f$ui8 = _f$ui8.itemView) === null || _f$ui8 === void 0 ? void 0 : _f$ui8.fieldMode) !== null && _f$ui$itemView$fieldM !== void 0 ? _f$ui$itemView$fieldM : group === null || group === void 0 || (_group$ui2 = group.ui) === null || _group$ui2 === void 0 || (_group$ui2 = _group$ui2.itemView) === null || _group$ui2 === void 0 ? void 0 : _group$ui2.defaultFieldMode) !== null && _ref4 !== void 0 ? _ref4 : (_listConfig$ui$itemVi = listConfig.ui.itemView) === null || _listConfig$ui$itemVi === void 0 ? void 0 : _listConfig$ui$itemVi.defaultFieldMode) !== null && _ref3 !== void 0 ? _ref3 : 'edit' : isEnabledField.read ? (_ref5 = (_ref6 = (_f$ui$itemView$fieldM2 = (_f$ui9 = f.ui) === null || _f$ui9 === void 0 || (_f$ui9 = _f$ui9.itemView) === null || _f$ui9 === void 0 ? void 0 : _f$ui9.fieldMode) !== null && _f$ui$itemView$fieldM2 !== void 0 ? _f$ui$itemView$fieldM2 : group === null || group === void 0 || (_group$ui3 = group.ui) === null || _group$ui3 === void 0 || (_group$ui3 = _group$ui3.itemView) === null || _group$ui3 === void 0 ? void 0 : _group$ui3.defaultFieldMode) !== null && _ref6 !== void 0 ? _ref6 : (_listConfig$ui$itemVi2 = listConfig.ui.itemView) === null || _listConfig$ui$itemVi2 === void 0 ? void 0 : _listConfig$ui$itemVi2.defaultFieldMode) !== null && _ref5 !== void 0 ? _ref5 : 'read' : 'hidden'
|
|
2144
|
+
},
|
|
2145
|
+
listView: {
|
|
2146
|
+
fieldMode: isEnabledField.read ? (_ref7 = (_ref8 = (_f$ui$listView$fieldM = (_f$ui0 = f.ui) === null || _f$ui0 === void 0 || (_f$ui0 = _f$ui0.listView) === null || _f$ui0 === void 0 ? void 0 : _f$ui0.fieldMode) !== null && _f$ui$listView$fieldM !== void 0 ? _f$ui$listView$fieldM : group === null || group === void 0 || (_group$ui4 = group.ui) === null || _group$ui4 === void 0 || (_group$ui4 = _group$ui4.listView) === null || _group$ui4 === void 0 ? void 0 : _group$ui4.defaultFieldMode) !== null && _ref8 !== void 0 ? _ref8 : (_listConfig$ui$listVi = listConfig.ui.listView) === null || _listConfig$ui$listVi === void 0 ? void 0 : _listConfig$ui$listVi.defaultFieldMode) !== null && _ref7 !== void 0 ? _ref7 : 'read' : 'hidden'
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
2149
|
+
// copy
|
|
2150
|
+
__ksTelemetryFieldTypeName: f.__ksTelemetryFieldTypeName,
|
|
2151
|
+
extraOutputFields: f.extraOutputFields,
|
|
2152
|
+
getAdminMeta: f.getAdminMeta,
|
|
2153
|
+
input: {
|
|
2154
|
+
...f.input
|
|
2155
|
+
},
|
|
2156
|
+
output: {
|
|
2157
|
+
...f.output
|
|
2158
|
+
},
|
|
2159
|
+
unreferencedConcreteInterfaceImplementations: f.unreferencedConcreteInterfaceImplementations,
|
|
2160
|
+
views: f.views
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// default labelField to `name`, `label`, or `title`; fallback to `id`
|
|
2165
|
+
const labelField = (_listConfig$ui$labelF = listConfig.ui.labelField) !== null && _listConfig$ui$labelF !== void 0 ? _listConfig$ui$labelF : listConfig.fields.label ? 'label' : listConfig.fields.name ? 'name' : listConfig.fields.title ? 'title' : 'id';
|
|
2166
|
+
const searchFields = new Set((_listConfig$ui$search = listConfig.ui.searchFields) !== null && _listConfig$ui$search !== void 0 ? _listConfig$ui$search : []);
|
|
2167
|
+
if (searchFields.has('id')) {
|
|
2168
|
+
throw new Error(`${listKey}.ui.searchFields cannot include 'id'`);
|
|
2169
|
+
}
|
|
2170
|
+
const names = __getNames(listKey, listConfig);
|
|
2171
|
+
result[listKey] = {
|
|
2172
|
+
access: parseListAccessControl(listConfig.access),
|
|
2173
|
+
fields: resultFields,
|
|
2174
|
+
groups,
|
|
2175
|
+
actions: [],
|
|
2176
|
+
graphql: {
|
|
2177
|
+
types: {
|
|
2178
|
+
...listGraphqlTypes[listKey].types
|
|
2179
|
+
},
|
|
2180
|
+
names: {
|
|
2181
|
+
...names.graphql.names
|
|
2182
|
+
},
|
|
2183
|
+
...intermediateList.graphql
|
|
2184
|
+
},
|
|
2185
|
+
prisma: {
|
|
2186
|
+
types: {
|
|
2187
|
+
...names.graphql.names
|
|
2188
|
+
},
|
|
2189
|
+
listKey: listKey[0].toLowerCase() + listKey.slice(1),
|
|
2190
|
+
mapping: listConfig.db.map,
|
|
2191
|
+
extendPrismaSchema: listConfig.db.extendPrismaSchema
|
|
2192
|
+
},
|
|
2193
|
+
ui: {
|
|
2194
|
+
labels: names.ui.labels,
|
|
2195
|
+
labelField,
|
|
2196
|
+
searchFields,
|
|
2197
|
+
searchableFields: new Map(),
|
|
2198
|
+
triviallySearchableFields: new Set()
|
|
2199
|
+
},
|
|
2200
|
+
hooks: parseListHooks((_listConfig$hooks = listConfig.hooks) !== null && _listConfig$hooks !== void 0 ? _listConfig$hooks : {}),
|
|
2201
|
+
listKey,
|
|
2202
|
+
cacheHint: (() => {
|
|
2203
|
+
const cacheHint = listConfig.graphql.cacheHint;
|
|
2204
|
+
if (typeof cacheHint === 'function') return cacheHint;
|
|
2205
|
+
if (cacheHint !== undefined) return () => cacheHint;
|
|
2206
|
+
return undefined;
|
|
2207
|
+
})(),
|
|
2208
|
+
isSingleton: (_listConfig$isSinglet = listConfig.isSingleton) !== null && _listConfig$isSinglet !== void 0 ? _listConfig$isSinglet : false
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
return result;
|
|
2212
|
+
}
|
|
2213
|
+
function introspectGraphQLTypes(lists) {
|
|
2214
|
+
const namesOfRelationInputs = new Set();
|
|
2215
|
+
for (const list of Object.values(lists)) {
|
|
2216
|
+
const {
|
|
2217
|
+
types
|
|
2218
|
+
} = list.graphql;
|
|
2219
|
+
namesOfRelationInputs.add(types.where.name);
|
|
2220
|
+
namesOfRelationInputs.add(types.relateTo.many.where.name);
|
|
2221
|
+
}
|
|
2222
|
+
for (const list of Object.values(lists)) {
|
|
2223
|
+
const {
|
|
2224
|
+
listKey,
|
|
2225
|
+
ui: {
|
|
2226
|
+
searchFields,
|
|
2227
|
+
searchableFields,
|
|
2228
|
+
triviallySearchableFields
|
|
2229
|
+
}
|
|
2230
|
+
} = list;
|
|
2231
|
+
if (searchFields.has('id')) {
|
|
2232
|
+
throw new Error(`The ui.searchFields option on the ${listKey} list includes 'id'. Lists can always be searched by an item's id so it must not be specified as a search field`);
|
|
2233
|
+
}
|
|
2234
|
+
const whereInputFields = list.graphql.types.where.getFields();
|
|
2235
|
+
for (const [fieldKey, field] of Object.entries(list.fields)) {
|
|
2236
|
+
var _whereInputFields$fie, _fieldFilterFields$co;
|
|
2237
|
+
const filterType = (_whereInputFields$fie = whereInputFields[fieldKey]) === null || _whereInputFields$fie === void 0 ? void 0 : _whereInputFields$fie.type;
|
|
2238
|
+
const fieldFilterFields = isInputObjectType(filterType) ? filterType.getFields() : undefined;
|
|
2239
|
+
const filterTypeName = isInputObjectType(filterType) ? filterType.name : undefined;
|
|
2240
|
+
if ((fieldFilterFields === null || fieldFilterFields === void 0 || (_fieldFilterFields$co = fieldFilterFields.contains) === null || _fieldFilterFields$co === void 0 ? void 0 : _fieldFilterFields$co.type) === GraphQLString) {
|
|
2241
|
+
var _fieldFilterFields$mo;
|
|
2242
|
+
searchableFields.set(fieldKey, (fieldFilterFields === null || fieldFilterFields === void 0 || (_fieldFilterFields$mo = fieldFilterFields.mode) === null || _fieldFilterFields$mo === void 0 ? void 0 : _fieldFilterFields$mo.type) === QueryMode ? 'insensitive' : 'default');
|
|
2243
|
+
triviallySearchableFields.add(fieldKey);
|
|
2244
|
+
} else if (field.dbField.kind === 'relation' && filterTypeName !== undefined && namesOfRelationInputs.has(filterTypeName)) {
|
|
2245
|
+
searchableFields.set(fieldKey, 'default');
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (searchFields.size === 0) {
|
|
2249
|
+
if (searchableFields.has(list.ui.labelField)) {
|
|
2250
|
+
searchFields.add(list.ui.labelField);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
function stripDefaultValue(thing) {
|
|
2256
|
+
return g.arg({
|
|
2257
|
+
...thing,
|
|
2258
|
+
defaultValue: undefined
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
function graphqlArgForInputField(field, operation, listsRef) {
|
|
2262
|
+
var _field$input5;
|
|
2263
|
+
const input = (_field$input5 = field.input) === null || _field$input5 === void 0 ? void 0 : _field$input5[operation];
|
|
2264
|
+
if (!(input !== null && input !== void 0 && input.arg) || !field.graphql.isEnabled[operation]) return;
|
|
2265
|
+
if (field.dbField.kind === 'relation') {
|
|
2266
|
+
if (!listsRef[field.dbField.list].graphql.isEnabled.type) return;
|
|
2267
|
+
}
|
|
2268
|
+
if (!field.graphql.isNonNull[operation]) return stripDefaultValue(input.arg);
|
|
2269
|
+
if (input.arg.type instanceof GNonNull) return input.arg;
|
|
2270
|
+
return g.arg({
|
|
2271
|
+
...input.arg,
|
|
2272
|
+
type: g.nonNull(input.arg.type)
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
function graphqlForOutputField(field) {
|
|
2276
|
+
const output = field.output;
|
|
2277
|
+
if (!output || !field.graphql.isEnabled.read) return output;
|
|
2278
|
+
if (!field.graphql.isNonNull.read) return output;
|
|
2279
|
+
if (output.type instanceof GNonNull) return output;
|
|
2280
|
+
return g.field({
|
|
2281
|
+
...output,
|
|
2282
|
+
type: g.nonNull(output.type)
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
function getInitialisedActionGraphql(list, listGraphqlNames, actionKey, action) {
|
|
2286
|
+
var _action$graphql$singu, _action$graphql, _action$graphql$plura, _action$graphql2, _action$args2;
|
|
2287
|
+
const graphqlNames = {
|
|
2288
|
+
one: (_action$graphql$singu = (_action$graphql = action.graphql) === null || _action$graphql === void 0 ? void 0 : _action$graphql.singular) !== null && _action$graphql$singu !== void 0 ? _action$graphql$singu : `${actionKey}${listGraphqlNames.singular}`,
|
|
2289
|
+
many: (_action$graphql$plura = (_action$graphql2 = action.graphql) === null || _action$graphql2 === void 0 ? void 0 : _action$graphql2.plural) !== null && _action$graphql$plura !== void 0 ? _action$graphql$plura : `${actionKey}${listGraphqlNames.plural}`
|
|
2290
|
+
};
|
|
2291
|
+
const argsName = `${graphqlNames.one[0].toUpperCase()}${graphqlNames.one.slice(1)}Args`;
|
|
2292
|
+
const argumentFields = Object.fromEntries(Object.entries((_action$args2 = action.args) !== null && _action$args2 !== void 0 ? _action$args2 : {}).map(([arg, value]) => [arg, value.graphql]));
|
|
2293
|
+
return {
|
|
2294
|
+
arguments: Object.entries(argumentFields).map(([name, arg]) => {
|
|
2295
|
+
var _getArgSources$name;
|
|
2296
|
+
return {
|
|
2297
|
+
name,
|
|
2298
|
+
type: printGraphQLType(arg.type),
|
|
2299
|
+
source: (_getArgSources$name = getArgSources(action)[name]) !== null && _getArgSources$name !== void 0 ? _getArgSources$name : null
|
|
2300
|
+
};
|
|
2301
|
+
}),
|
|
2302
|
+
names: {
|
|
2303
|
+
...graphqlNames,
|
|
2304
|
+
args: argsName
|
|
2305
|
+
},
|
|
2306
|
+
types: {
|
|
2307
|
+
arguments: argumentFields,
|
|
2308
|
+
args: g.inputObject({
|
|
2309
|
+
name: argsName,
|
|
2310
|
+
isOneOf: false,
|
|
2311
|
+
fields: {
|
|
2312
|
+
where: g.arg({
|
|
2313
|
+
type: g.nonNull(list.graphql.types.uniqueWhere)
|
|
2314
|
+
}),
|
|
2315
|
+
...argumentFields
|
|
2316
|
+
}
|
|
2317
|
+
})
|
|
2318
|
+
}
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
function initialiseLists(config) {
|
|
2322
|
+
const listsRef = {};
|
|
2323
|
+
let intermediateLists;
|
|
2324
|
+
|
|
2325
|
+
// step 1
|
|
2326
|
+
intermediateLists = getListsWithInitialisedFields(config, listsRef);
|
|
2327
|
+
|
|
2328
|
+
// step 2
|
|
2329
|
+
const resolvedDBFieldsForLists = resolveRelationships(intermediateLists);
|
|
2330
|
+
intermediateLists = Object.fromEntries(Object.values(intermediateLists).map(list => [list.listKey, {
|
|
2331
|
+
...list,
|
|
2332
|
+
resolvedDbFields: resolvedDBFieldsForLists[list.listKey]
|
|
2333
|
+
}]));
|
|
2334
|
+
|
|
2335
|
+
// step 3
|
|
2336
|
+
intermediateLists = Object.fromEntries(Object.values(intermediateLists).map(list => {
|
|
2337
|
+
const fields = {};
|
|
2338
|
+
for (const [fieldKey, field] of Object.entries(list.fields)) {
|
|
2339
|
+
fields[fieldKey] = {
|
|
2340
|
+
...field,
|
|
2341
|
+
dbField: list.resolvedDbFields[fieldKey]
|
|
2342
|
+
};
|
|
2343
|
+
}
|
|
2344
|
+
return [list.listKey, {
|
|
2345
|
+
...list,
|
|
2346
|
+
fields
|
|
2347
|
+
}];
|
|
2348
|
+
}));
|
|
2349
|
+
|
|
2350
|
+
// fixup the GraphQL refs
|
|
2351
|
+
for (const list of Object.values(intermediateLists)) {
|
|
2352
|
+
listsRef[list.listKey] = {
|
|
2353
|
+
...list,
|
|
2354
|
+
lists: listsRef
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
for (const list of Object.values(listsRef)) {
|
|
2358
|
+
var _listConfig$actions;
|
|
2359
|
+
const listConfig = config.lists[list.listKey];
|
|
2360
|
+
let hasAnEnabledCreateField = false;
|
|
2361
|
+
let hasAnEnabledUpdateField = false;
|
|
2362
|
+
for (const field of Object.values(list.fields)) {
|
|
2363
|
+
var _field$input6, _field$input7;
|
|
2364
|
+
if ((_field$input6 = field.input) !== null && _field$input6 !== void 0 && (_field$input6 = _field$input6.create) !== null && _field$input6 !== void 0 && _field$input6.arg && field.graphql.isEnabled.create) {
|
|
2365
|
+
hasAnEnabledCreateField = true;
|
|
2366
|
+
}
|
|
2367
|
+
if ((_field$input7 = field.input) !== null && _field$input7 !== void 0 && _field$input7.update && field.graphql.isEnabled.update) {
|
|
2368
|
+
hasAnEnabledUpdateField = true;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
if (!hasAnEnabledCreateField) {
|
|
2372
|
+
list.graphql.types.create = g.Empty;
|
|
2373
|
+
list.graphql.names.createInputName = 'Empty';
|
|
2374
|
+
}
|
|
2375
|
+
if (!hasAnEnabledUpdateField) {
|
|
2376
|
+
list.graphql.types.update = g.Empty;
|
|
2377
|
+
list.graphql.names.updateInputName = 'Empty';
|
|
2378
|
+
}
|
|
2379
|
+
list.actions = Object.entries((_listConfig$actions = listConfig.actions) !== null && _listConfig$actions !== void 0 ? _listConfig$actions : {}).map(([actionKey, action]) => {
|
|
2380
|
+
var _action$ui$icon, _action$ui$itemView$a, _action$ui$itemView, _action$ui$itemView$n, _action$ui$itemView2, _action$ui$itemView$h, _action$ui$itemView3, _action$ui$itemView$h2, _action$ui$itemView4, _action$ui$listView$a, _action$ui$listView;
|
|
2381
|
+
const {
|
|
2382
|
+
label
|
|
2383
|
+
} = action.ui;
|
|
2384
|
+
const graphql = getInitialisedActionGraphql(list, __getNames(list.listKey, listConfig).graphql, actionKey, action);
|
|
2385
|
+
return {
|
|
2386
|
+
...action,
|
|
2387
|
+
actionKey,
|
|
2388
|
+
graphql,
|
|
2389
|
+
otel: humanize(graphql.names.one, true).toLowerCase(),
|
|
2390
|
+
ui: {
|
|
2391
|
+
label,
|
|
2392
|
+
icon: (_action$ui$icon = action.ui.icon) !== null && _action$ui$icon !== void 0 ? _action$ui$icon : null,
|
|
2393
|
+
messages: {
|
|
2394
|
+
promptTitle: `{Label} {singular}`,
|
|
2395
|
+
promptTitleMany: `{Label} {count} {singular|plural}`,
|
|
2396
|
+
prompt: `Are you sure you want to {label} {singular} "{itemLabel}"?`,
|
|
2397
|
+
promptMany: `Are you sure you want to {label} {count} {singular|plural}?`,
|
|
2398
|
+
promptConfirmLabel: `Yes, {label} this {singular}`,
|
|
2399
|
+
promptConfirmLabelMany: `Yes, {label} {count} {singular|plural}`,
|
|
2400
|
+
fail: `Could not {label} {singular}`,
|
|
2401
|
+
failMany: `Could not {label} {countFail} {singular|plural}`,
|
|
2402
|
+
success: `Completed {label} action for {singular}`,
|
|
2403
|
+
successMany: `Completed {label} action for {countSuccess} {singular|plural}`,
|
|
2404
|
+
...action.ui.messages
|
|
2405
|
+
},
|
|
2406
|
+
itemView: {
|
|
2407
|
+
actionMode: (_action$ui$itemView$a = (_action$ui$itemView = action.ui.itemView) === null || _action$ui$itemView === void 0 ? void 0 : _action$ui$itemView.actionMode) !== null && _action$ui$itemView$a !== void 0 ? _action$ui$itemView$a : 'enabled',
|
|
2408
|
+
navigation: (_action$ui$itemView$n = (_action$ui$itemView2 = action.ui.itemView) === null || _action$ui$itemView2 === void 0 ? void 0 : _action$ui$itemView2.navigation) !== null && _action$ui$itemView$n !== void 0 ? _action$ui$itemView$n : 'follow',
|
|
2409
|
+
hidePrompt: (_action$ui$itemView$h = (_action$ui$itemView3 = action.ui.itemView) === null || _action$ui$itemView3 === void 0 ? void 0 : _action$ui$itemView3.hidePrompt) !== null && _action$ui$itemView$h !== void 0 ? _action$ui$itemView$h : false,
|
|
2410
|
+
hideToast: (_action$ui$itemView$h2 = (_action$ui$itemView4 = action.ui.itemView) === null || _action$ui$itemView4 === void 0 ? void 0 : _action$ui$itemView4.hideToast) !== null && _action$ui$itemView$h2 !== void 0 ? _action$ui$itemView$h2 : false
|
|
2411
|
+
},
|
|
2412
|
+
listView: {
|
|
2413
|
+
actionMode: (_action$ui$listView$a = (_action$ui$listView = action.ui.listView) === null || _action$ui$listView === void 0 ? void 0 : _action$ui$listView.actionMode) !== null && _action$ui$listView$a !== void 0 ? _action$ui$listView$a : 'enabled'
|
|
2414
|
+
},
|
|
2415
|
+
argSources: getArgSources(action)
|
|
2416
|
+
}
|
|
2417
|
+
};
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// error checking
|
|
2422
|
+
for (const list of Object.values(listsRef)) {
|
|
2423
|
+
assertFieldsValid(list);
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// do some introspection
|
|
2427
|
+
introspectGraphQLTypes(listsRef);
|
|
2428
|
+
return listsRef;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
const NixxieAdminUIFieldMeta = g.object()({
|
|
2432
|
+
name: 'NixxieAdminUIFieldMeta',
|
|
2433
|
+
fields: {
|
|
2434
|
+
key: g.field({
|
|
2435
|
+
type: g.nonNull(g.String)
|
|
2436
|
+
}),
|
|
2437
|
+
label: g.field({
|
|
2438
|
+
type: g.nonNull(g.String)
|
|
2439
|
+
}),
|
|
2440
|
+
description: g.field({
|
|
2441
|
+
type: g.String
|
|
2442
|
+
}),
|
|
2443
|
+
isOrderable: g.field({
|
|
2444
|
+
type: g.nonNull(g.Boolean)
|
|
2445
|
+
}),
|
|
2446
|
+
isFilterable: g.field({
|
|
2447
|
+
type: g.nonNull(g.Boolean)
|
|
2448
|
+
}),
|
|
2449
|
+
isNonNull: g.field({
|
|
2450
|
+
type: g.list(g.nonNull(g.enum({
|
|
2451
|
+
name: 'NixxieAdminUIFieldMetaIsNonNull',
|
|
2452
|
+
values: g.enumValues(['read', 'create', 'update'])
|
|
2453
|
+
})))
|
|
2454
|
+
}),
|
|
2455
|
+
fieldMeta: g.field({
|
|
2456
|
+
type: g.JSON
|
|
2457
|
+
}),
|
|
2458
|
+
viewsIndex: g.field({
|
|
2459
|
+
type: g.nonNull(g.Int)
|
|
2460
|
+
}),
|
|
2461
|
+
customViewsIndex: g.field({
|
|
2462
|
+
type: g.Int
|
|
2463
|
+
}),
|
|
2464
|
+
createView: g.field({
|
|
2465
|
+
type: g.nonNull(g.object()({
|
|
2466
|
+
name: 'NixxieAdminUIFieldMetaCreateView',
|
|
2467
|
+
fields: {
|
|
2468
|
+
fieldMode: g.field({
|
|
2469
|
+
type: g.nonNull(g.JSON)
|
|
2470
|
+
}),
|
|
2471
|
+
isRequired: g.field({
|
|
2472
|
+
type: g.nonNull(g.JSON)
|
|
2473
|
+
})
|
|
2474
|
+
}
|
|
2475
|
+
}))
|
|
2476
|
+
}),
|
|
2477
|
+
itemView: g.field({
|
|
2478
|
+
resolve: args => args,
|
|
2479
|
+
type: g.object()({
|
|
2480
|
+
name: 'NixxieAdminUIFieldMetaItemView',
|
|
2481
|
+
fields: {
|
|
2482
|
+
fieldMode: g.field({
|
|
2483
|
+
type: g.nonNull(g.JSON),
|
|
2484
|
+
async resolve({
|
|
2485
|
+
listKey,
|
|
2486
|
+
fieldKey,
|
|
2487
|
+
itemView,
|
|
2488
|
+
item,
|
|
2489
|
+
itemField
|
|
2490
|
+
}, _, context) {
|
|
2491
|
+
const {
|
|
2492
|
+
fieldMode
|
|
2493
|
+
} = itemView;
|
|
2494
|
+
if (typeof fieldMode !== 'function') return fieldMode;
|
|
2495
|
+
return fieldMode({
|
|
2496
|
+
session: context.session,
|
|
2497
|
+
context,
|
|
2498
|
+
listKey,
|
|
2499
|
+
fieldKey,
|
|
2500
|
+
item,
|
|
2501
|
+
itemField
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
}),
|
|
2505
|
+
fieldPosition: g.field({
|
|
2506
|
+
type: g.nonNull(g.enum({
|
|
2507
|
+
name: 'NixxieAdminUIFieldMetaItemViewFieldPosition',
|
|
2508
|
+
values: g.enumValues(['form', 'sidebar'])
|
|
2509
|
+
})),
|
|
2510
|
+
async resolve({
|
|
2511
|
+
listKey,
|
|
2512
|
+
fieldKey,
|
|
2513
|
+
itemView,
|
|
2514
|
+
item,
|
|
2515
|
+
itemField
|
|
2516
|
+
}, _, context) {
|
|
2517
|
+
const {
|
|
2518
|
+
fieldPosition
|
|
2519
|
+
} = itemView;
|
|
2520
|
+
if (typeof fieldPosition !== 'function') return fieldPosition;
|
|
2521
|
+
return fieldPosition({
|
|
2522
|
+
session: context.session,
|
|
2523
|
+
context,
|
|
2524
|
+
listKey,
|
|
2525
|
+
fieldKey,
|
|
2526
|
+
item,
|
|
2527
|
+
itemField
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
}),
|
|
2531
|
+
isRequired: g.field({
|
|
2532
|
+
type: g.nonNull(g.JSON),
|
|
2533
|
+
resolve({
|
|
2534
|
+
listKey,
|
|
2535
|
+
fieldKey,
|
|
2536
|
+
itemView,
|
|
2537
|
+
item,
|
|
2538
|
+
itemField
|
|
2539
|
+
}, _, context) {
|
|
2540
|
+
const {
|
|
2541
|
+
isRequired
|
|
2542
|
+
} = itemView;
|
|
2543
|
+
if (typeof isRequired !== 'function') return isRequired;
|
|
2544
|
+
return isRequired({
|
|
2545
|
+
session: context.session,
|
|
2546
|
+
context,
|
|
2547
|
+
listKey,
|
|
2548
|
+
fieldKey,
|
|
2549
|
+
item,
|
|
2550
|
+
itemField
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
})
|
|
2554
|
+
}
|
|
2555
|
+
})
|
|
2556
|
+
}),
|
|
2557
|
+
listView: g.field({
|
|
2558
|
+
type: g.nonNull(g.object()({
|
|
2559
|
+
name: 'NixxieAdminUIFieldMetaListView',
|
|
2560
|
+
fields: {
|
|
2561
|
+
fieldMode: g.field({
|
|
2562
|
+
type: g.nonNull(g.enum({
|
|
2563
|
+
name: 'NixxieAdminUIFieldMetaListViewFieldMode',
|
|
2564
|
+
values: g.enumValues(['read', 'hidden'])
|
|
2565
|
+
}))
|
|
2566
|
+
})
|
|
2567
|
+
}
|
|
2568
|
+
}))
|
|
2569
|
+
}),
|
|
2570
|
+
search: g.field({
|
|
2571
|
+
type: QueryMode
|
|
2572
|
+
})
|
|
2573
|
+
}
|
|
2574
|
+
});
|
|
2575
|
+
const NixxieAdminUIActionMeta = g.object()({
|
|
2576
|
+
name: 'NixxieAdminUIActionMeta',
|
|
2577
|
+
fields: {
|
|
2578
|
+
key: g.field({
|
|
2579
|
+
type: g.nonNull(g.String)
|
|
2580
|
+
}),
|
|
2581
|
+
label: g.field({
|
|
2582
|
+
type: g.nonNull(g.String)
|
|
2583
|
+
}),
|
|
2584
|
+
icon: g.field({
|
|
2585
|
+
type: g.String
|
|
2586
|
+
}),
|
|
2587
|
+
messages: g.field({
|
|
2588
|
+
type: g.nonNull(g.object()({
|
|
2589
|
+
name: 'NixxieAdminUIActionMetaMessages',
|
|
2590
|
+
fields: {
|
|
2591
|
+
promptTitle: g.field({
|
|
2592
|
+
type: g.nonNull(g.String)
|
|
2593
|
+
}),
|
|
2594
|
+
promptTitleMany: g.field({
|
|
2595
|
+
type: g.String
|
|
2596
|
+
}),
|
|
2597
|
+
prompt: g.field({
|
|
2598
|
+
type: g.nonNull(g.String)
|
|
2599
|
+
}),
|
|
2600
|
+
promptMany: g.field({
|
|
2601
|
+
type: g.String
|
|
2602
|
+
}),
|
|
2603
|
+
promptConfirmLabel: g.field({
|
|
2604
|
+
type: g.nonNull(g.String)
|
|
2605
|
+
}),
|
|
2606
|
+
promptConfirmLabelMany: g.field({
|
|
2607
|
+
type: g.String
|
|
2608
|
+
}),
|
|
2609
|
+
fail: g.field({
|
|
2610
|
+
type: g.nonNull(g.String)
|
|
2611
|
+
}),
|
|
2612
|
+
failMany: g.field({
|
|
2613
|
+
type: g.String
|
|
2614
|
+
}),
|
|
2615
|
+
success: g.field({
|
|
2616
|
+
type: g.nonNull(g.String)
|
|
2617
|
+
}),
|
|
2618
|
+
successMany: g.field({
|
|
2619
|
+
type: g.String
|
|
2620
|
+
})
|
|
2621
|
+
}
|
|
2622
|
+
}))
|
|
2623
|
+
}),
|
|
2624
|
+
graphql: g.field({
|
|
2625
|
+
type: g.object()({
|
|
2626
|
+
name: 'NixxieAdminUIActionMetaGraphQL',
|
|
2627
|
+
fields: {
|
|
2628
|
+
arguments: g.field({
|
|
2629
|
+
type: g.nonNull(g.list(g.nonNull(g.object()({
|
|
2630
|
+
name: 'NixxieAdminUIActionMetaGraphQLArgument',
|
|
2631
|
+
fields: {
|
|
2632
|
+
name: g.field({
|
|
2633
|
+
type: g.nonNull(g.String)
|
|
2634
|
+
}),
|
|
2635
|
+
type: g.field({
|
|
2636
|
+
type: g.nonNull(g.String)
|
|
2637
|
+
}),
|
|
2638
|
+
source: g.field({
|
|
2639
|
+
type: g.JSON
|
|
2640
|
+
})
|
|
2641
|
+
}
|
|
2642
|
+
}))))
|
|
2643
|
+
}),
|
|
2644
|
+
names: g.field({
|
|
2645
|
+
type: g.nonNull(g.object()({
|
|
2646
|
+
name: 'NixxieAdminUIActionMetaGraphQLNames',
|
|
2647
|
+
fields: {
|
|
2648
|
+
one: g.field({
|
|
2649
|
+
type: g.nonNull(g.String)
|
|
2650
|
+
}),
|
|
2651
|
+
many: g.field({
|
|
2652
|
+
type: g.String
|
|
2653
|
+
})
|
|
2654
|
+
}
|
|
2655
|
+
}))
|
|
2656
|
+
})
|
|
2657
|
+
}
|
|
2658
|
+
})
|
|
2659
|
+
}),
|
|
2660
|
+
itemView: g.field({
|
|
2661
|
+
resolve: args => args,
|
|
2662
|
+
type: g.object()({
|
|
2663
|
+
name: 'NixxieAdminUIActionMetaItemView',
|
|
2664
|
+
fields: {
|
|
2665
|
+
actionMode: g.field({
|
|
2666
|
+
type: g.nonNull(g.JSON),
|
|
2667
|
+
async resolve({
|
|
2668
|
+
listKey,
|
|
2669
|
+
key,
|
|
2670
|
+
itemView,
|
|
2671
|
+
item
|
|
2672
|
+
}, _, context) {
|
|
2673
|
+
const {
|
|
2674
|
+
actionMode
|
|
2675
|
+
} = itemView;
|
|
2676
|
+
if (typeof actionMode !== 'function') return actionMode;
|
|
2677
|
+
return actionMode({
|
|
2678
|
+
session: context.session,
|
|
2679
|
+
context,
|
|
2680
|
+
listKey,
|
|
2681
|
+
actionKey: key,
|
|
2682
|
+
item
|
|
2683
|
+
});
|
|
2684
|
+
}
|
|
2685
|
+
}),
|
|
2686
|
+
navigation: g.field({
|
|
2687
|
+
type: g.nonNull(g.enum({
|
|
2688
|
+
name: 'NixxieAdminUIActionMetaItemViewNavigation',
|
|
2689
|
+
values: g.enumValues(['follow', 'refetch', 'return'])
|
|
2690
|
+
})),
|
|
2691
|
+
resolve({
|
|
2692
|
+
itemView
|
|
2693
|
+
}) {
|
|
2694
|
+
return itemView.navigation;
|
|
2695
|
+
}
|
|
2696
|
+
}),
|
|
2697
|
+
hidePrompt: g.field({
|
|
2698
|
+
type: g.nonNull(g.Boolean),
|
|
2699
|
+
resolve({
|
|
2700
|
+
itemView
|
|
2701
|
+
}) {
|
|
2702
|
+
return itemView.hidePrompt;
|
|
2703
|
+
}
|
|
2704
|
+
}),
|
|
2705
|
+
hideToast: g.field({
|
|
2706
|
+
type: g.nonNull(g.Boolean),
|
|
2707
|
+
resolve({
|
|
2708
|
+
itemView
|
|
2709
|
+
}) {
|
|
2710
|
+
return itemView.hideToast;
|
|
2711
|
+
}
|
|
2712
|
+
})
|
|
2713
|
+
}
|
|
2714
|
+
})
|
|
2715
|
+
}),
|
|
2716
|
+
listView: g.field({
|
|
2717
|
+
type: g.nonNull(g.object()({
|
|
2718
|
+
name: 'NixxieAdminUIActionMetaListView',
|
|
2719
|
+
fields: {
|
|
2720
|
+
actionMode: g.field({
|
|
2721
|
+
type: g.nonNull(g.JSON)
|
|
2722
|
+
})
|
|
2723
|
+
}
|
|
2724
|
+
}))
|
|
2725
|
+
})
|
|
2726
|
+
}
|
|
2727
|
+
});
|
|
2728
|
+
const NixxieAdminUIFieldGroupMeta = g.object()({
|
|
2729
|
+
name: 'NixxieAdminUIFieldGroupMeta',
|
|
2730
|
+
fields: {
|
|
2731
|
+
label: g.field({
|
|
2732
|
+
type: g.nonNull(g.String)
|
|
2733
|
+
}),
|
|
2734
|
+
description: g.field({
|
|
2735
|
+
type: g.String
|
|
2736
|
+
}),
|
|
2737
|
+
fields: g.field({
|
|
2738
|
+
type: g.nonNull(g.list(g.nonNull(NixxieAdminUIFieldMeta)))
|
|
2739
|
+
})
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
const NixxieAdminUISort = g.object()({
|
|
2743
|
+
name: 'NixxieAdminUISort',
|
|
2744
|
+
fields: {
|
|
2745
|
+
field: g.field({
|
|
2746
|
+
type: g.nonNull(g.String)
|
|
2747
|
+
}),
|
|
2748
|
+
direction: g.field({
|
|
2749
|
+
type: g.nonNull(g.enum({
|
|
2750
|
+
name: 'NixxieAdminUISortDirection',
|
|
2751
|
+
values: g.enumValues(['ASC', 'DESC'])
|
|
2752
|
+
}))
|
|
2753
|
+
})
|
|
2754
|
+
}
|
|
2755
|
+
});
|
|
2756
|
+
const NixxieAdminUIGraphQL = g.object()({
|
|
2757
|
+
name: 'NixxieAdminUIGraphQL',
|
|
2758
|
+
fields: {
|
|
2759
|
+
names: g.field({
|
|
2760
|
+
type: g.nonNull(g.object()({
|
|
2761
|
+
name: 'NixxieAdminUIGraphQLNames',
|
|
2762
|
+
fields: {
|
|
2763
|
+
outputTypeName: g.field({
|
|
2764
|
+
type: g.nonNull(g.String)
|
|
2765
|
+
}),
|
|
2766
|
+
whereInputName: g.field({
|
|
2767
|
+
type: g.nonNull(g.String)
|
|
2768
|
+
}),
|
|
2769
|
+
whereUniqueInputName: g.field({
|
|
2770
|
+
type: g.nonNull(g.String)
|
|
2771
|
+
}),
|
|
2772
|
+
// create
|
|
2773
|
+
createInputName: g.field({
|
|
2774
|
+
type: g.nonNull(g.String)
|
|
2775
|
+
}),
|
|
2776
|
+
createMutationName: g.field({
|
|
2777
|
+
type: g.nonNull(g.String)
|
|
2778
|
+
}),
|
|
2779
|
+
createManyMutationName: g.field({
|
|
2780
|
+
type: g.nonNull(g.String)
|
|
2781
|
+
}),
|
|
2782
|
+
relateToOneForCreateInputName: g.field({
|
|
2783
|
+
type: g.nonNull(g.String)
|
|
2784
|
+
}),
|
|
2785
|
+
relateToManyForCreateInputName: g.field({
|
|
2786
|
+
type: g.nonNull(g.String)
|
|
2787
|
+
}),
|
|
2788
|
+
// read
|
|
2789
|
+
itemQueryName: g.field({
|
|
2790
|
+
type: g.nonNull(g.String)
|
|
2791
|
+
}),
|
|
2792
|
+
listOrderName: g.field({
|
|
2793
|
+
type: g.nonNull(g.String)
|
|
2794
|
+
}),
|
|
2795
|
+
listQueryCountName: g.field({
|
|
2796
|
+
type: g.nonNull(g.String)
|
|
2797
|
+
}),
|
|
2798
|
+
listQueryName: g.field({
|
|
2799
|
+
type: g.nonNull(g.String)
|
|
2800
|
+
}),
|
|
2801
|
+
// update
|
|
2802
|
+
updateInputName: g.field({
|
|
2803
|
+
type: g.nonNull(g.String)
|
|
2804
|
+
}),
|
|
2805
|
+
updateMutationName: g.field({
|
|
2806
|
+
type: g.nonNull(g.String)
|
|
2807
|
+
}),
|
|
2808
|
+
updateManyInputName: g.field({
|
|
2809
|
+
type: g.nonNull(g.String)
|
|
2810
|
+
}),
|
|
2811
|
+
updateManyMutationName: g.field({
|
|
2812
|
+
type: g.nonNull(g.String)
|
|
2813
|
+
}),
|
|
2814
|
+
relateToOneForUpdateInputName: g.field({
|
|
2815
|
+
type: g.nonNull(g.String)
|
|
2816
|
+
}),
|
|
2817
|
+
relateToManyForUpdateInputName: g.field({
|
|
2818
|
+
type: g.nonNull(g.String)
|
|
2819
|
+
}),
|
|
2820
|
+
// delete
|
|
2821
|
+
deleteMutationName: g.field({
|
|
2822
|
+
type: g.nonNull(g.String)
|
|
2823
|
+
}),
|
|
2824
|
+
deleteManyMutationName: g.field({
|
|
2825
|
+
type: g.nonNull(g.String)
|
|
2826
|
+
})
|
|
2827
|
+
}
|
|
2828
|
+
}))
|
|
2829
|
+
})
|
|
2830
|
+
}
|
|
2831
|
+
});
|
|
2832
|
+
const NixxieAdminUIListMeta = g.object()({
|
|
2833
|
+
name: 'NixxieAdminUIListMeta',
|
|
2834
|
+
fields: {
|
|
2835
|
+
key: g.field({
|
|
2836
|
+
type: g.nonNull(g.String)
|
|
2837
|
+
}),
|
|
2838
|
+
label: g.field({
|
|
2839
|
+
type: g.nonNull(g.String)
|
|
2840
|
+
}),
|
|
2841
|
+
singular: g.field({
|
|
2842
|
+
type: g.nonNull(g.String)
|
|
2843
|
+
}),
|
|
2844
|
+
plural: g.field({
|
|
2845
|
+
type: g.nonNull(g.String)
|
|
2846
|
+
}),
|
|
2847
|
+
path: g.field({
|
|
2848
|
+
type: g.nonNull(g.String)
|
|
2849
|
+
}),
|
|
2850
|
+
labelField: g.field({
|
|
2851
|
+
type: g.nonNull(g.String)
|
|
2852
|
+
}),
|
|
2853
|
+
fields: g.field({
|
|
2854
|
+
resolve: ({
|
|
2855
|
+
fields,
|
|
2856
|
+
item
|
|
2857
|
+
}) => {
|
|
2858
|
+
return fields.map(f => {
|
|
2859
|
+
var _item$f$key;
|
|
2860
|
+
return {
|
|
2861
|
+
...f,
|
|
2862
|
+
item,
|
|
2863
|
+
itemField: (_item$f$key = item === null || item === void 0 ? void 0 : item[f.key]) !== null && _item$f$key !== void 0 ? _item$f$key : null
|
|
2864
|
+
};
|
|
2865
|
+
});
|
|
2866
|
+
},
|
|
2867
|
+
type: g.nonNull(g.list(g.nonNull(NixxieAdminUIFieldMeta)))
|
|
2868
|
+
}),
|
|
2869
|
+
groups: g.field({
|
|
2870
|
+
type: g.nonNull(g.list(g.nonNull(NixxieAdminUIFieldGroupMeta)))
|
|
2871
|
+
}),
|
|
2872
|
+
actions: g.field({
|
|
2873
|
+
resolve: ({
|
|
2874
|
+
actions,
|
|
2875
|
+
item
|
|
2876
|
+
}) => actions.map(action => ({
|
|
2877
|
+
...action,
|
|
2878
|
+
item
|
|
2879
|
+
})),
|
|
2880
|
+
type: g.nonNull(g.list(g.nonNull(NixxieAdminUIActionMeta)))
|
|
2881
|
+
}),
|
|
2882
|
+
graphql: g.field({
|
|
2883
|
+
type: g.nonNull(NixxieAdminUIGraphQL)
|
|
2884
|
+
}),
|
|
2885
|
+
pageSize: g.field({
|
|
2886
|
+
type: g.nonNull(g.Int)
|
|
2887
|
+
}),
|
|
2888
|
+
initialColumns: g.field({
|
|
2889
|
+
type: g.nonNull(g.list(g.nonNull(g.String)))
|
|
2890
|
+
}),
|
|
2891
|
+
initialSearchFields: g.field({
|
|
2892
|
+
type: g.nonNull(g.list(g.nonNull(g.String)))
|
|
2893
|
+
}),
|
|
2894
|
+
initialSort: g.field({
|
|
2895
|
+
type: NixxieAdminUISort
|
|
2896
|
+
}),
|
|
2897
|
+
initialFilter: g.field({
|
|
2898
|
+
type: g.JSON
|
|
2899
|
+
}),
|
|
2900
|
+
isSingleton: g.field({
|
|
2901
|
+
type: g.nonNull(g.Boolean)
|
|
2902
|
+
}),
|
|
2903
|
+
hideNavigation: g.field({
|
|
2904
|
+
type: g.nonNull(g.Boolean)
|
|
2905
|
+
}),
|
|
2906
|
+
hideCreate: g.field({
|
|
2907
|
+
type: g.nonNull(g.Boolean)
|
|
2908
|
+
}),
|
|
2909
|
+
hideDelete: g.field({
|
|
2910
|
+
type: g.nonNull(g.Boolean)
|
|
2911
|
+
})
|
|
2912
|
+
}
|
|
2913
|
+
});
|
|
2914
|
+
const adminMeta = g.object()({
|
|
2915
|
+
name: 'NixxieAdminMeta',
|
|
2916
|
+
fields: {
|
|
2917
|
+
lists: g.field({
|
|
2918
|
+
type: g.nonNull(g.list(g.nonNull(NixxieAdminUIListMeta)))
|
|
2919
|
+
}),
|
|
2920
|
+
list: g.field({
|
|
2921
|
+
type: NixxieAdminUIListMeta,
|
|
2922
|
+
args: {
|
|
2923
|
+
key: g.arg({
|
|
2924
|
+
type: g.nonNull(g.String)
|
|
2925
|
+
}),
|
|
2926
|
+
itemId: g.arg({
|
|
2927
|
+
type: g.ID
|
|
2928
|
+
})
|
|
2929
|
+
},
|
|
2930
|
+
async resolve(source, {
|
|
2931
|
+
key,
|
|
2932
|
+
itemId
|
|
2933
|
+
}, context) {
|
|
2934
|
+
if (itemId === null || itemId === undefined) {
|
|
2935
|
+
return {
|
|
2936
|
+
...source.listsByKey[key],
|
|
2937
|
+
item: null
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
// WARNING: do not use sudo
|
|
2941
|
+
const item = await context.db[key].findOne({
|
|
2942
|
+
where: {
|
|
2943
|
+
id: itemId
|
|
2944
|
+
}
|
|
2945
|
+
});
|
|
2946
|
+
if (!item) {
|
|
2947
|
+
return {
|
|
2948
|
+
...source.listsByKey[key],
|
|
2949
|
+
item: null
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
return {
|
|
2953
|
+
...source.listsByKey[key],
|
|
2954
|
+
item
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
})
|
|
2958
|
+
}
|
|
2959
|
+
});
|
|
2960
|
+
const NixxieMeta = g.object()({
|
|
2961
|
+
name: 'NixxieMeta',
|
|
2962
|
+
fields: {
|
|
2963
|
+
adminMeta: g.field({
|
|
2964
|
+
type: g.nonNull(adminMeta),
|
|
2965
|
+
async resolve({
|
|
2966
|
+
adminMeta
|
|
2967
|
+
}, _, context) {
|
|
2968
|
+
if (context.__internal.sudo) return adminMeta;
|
|
2969
|
+
const isAllowed = await adminMeta.isAccessAllowed(context);
|
|
2970
|
+
if (isAllowed) return adminMeta;
|
|
2971
|
+
|
|
2972
|
+
// TODO: we need better errors
|
|
2973
|
+
throw new Error('Access denied');
|
|
2974
|
+
}
|
|
2975
|
+
})
|
|
2976
|
+
}
|
|
2977
|
+
});
|
|
2978
|
+
|
|
2979
|
+
const tracer = trace.getTracer('nixxie');
|
|
2980
|
+
async function withSpan(name, fn, attrs) {
|
|
2981
|
+
return tracer.startActiveSpan(name, {
|
|
2982
|
+
attributes: attrs
|
|
2983
|
+
}, async span => {
|
|
2984
|
+
try {
|
|
2985
|
+
const result = await fn(span);
|
|
2986
|
+
span.setStatus({
|
|
2987
|
+
code: SpanStatusCode.OK
|
|
2988
|
+
});
|
|
2989
|
+
return result;
|
|
2990
|
+
} catch (err) {
|
|
2991
|
+
span.recordException(err instanceof Error ? err : {
|
|
2992
|
+
message: String(err)
|
|
2993
|
+
});
|
|
2994
|
+
span.setStatus({
|
|
2995
|
+
code: SpanStatusCode.ERROR
|
|
2996
|
+
});
|
|
2997
|
+
throw err;
|
|
2998
|
+
} finally {
|
|
2999
|
+
span.end();
|
|
3000
|
+
}
|
|
3001
|
+
});
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
async function validate({
|
|
3005
|
+
list,
|
|
3006
|
+
hookArgs
|
|
3007
|
+
}) {
|
|
3008
|
+
const messages = [];
|
|
3009
|
+
const fieldsErrors = [];
|
|
3010
|
+
const {
|
|
3011
|
+
operation
|
|
3012
|
+
} = hookArgs;
|
|
3013
|
+
|
|
3014
|
+
// field validation hooks
|
|
3015
|
+
await Promise.all(Object.entries(list.fields).map(async ([fieldKey, field]) => {
|
|
3016
|
+
const addValidationError = msg => void messages.push(`${list.listKey}.${fieldKey}: ${msg}`);
|
|
3017
|
+
const hook = field.hooks.validate[operation];
|
|
3018
|
+
try {
|
|
3019
|
+
var _hookArgs$item, _hookArgs$inputData, _hookArgs$resolvedDat;
|
|
3020
|
+
await hook({
|
|
3021
|
+
...hookArgs,
|
|
3022
|
+
addValidationError,
|
|
3023
|
+
fieldKey,
|
|
3024
|
+
itemField: (_hookArgs$item = hookArgs.item) === null || _hookArgs$item === void 0 ? void 0 : _hookArgs$item[fieldKey],
|
|
3025
|
+
inputFieldData: (_hookArgs$inputData = hookArgs.inputData) === null || _hookArgs$inputData === void 0 ? void 0 : _hookArgs$inputData[fieldKey],
|
|
3026
|
+
resolvedFieldData: (_hookArgs$resolvedDat = hookArgs.resolvedData) === null || _hookArgs$resolvedDat === void 0 ? void 0 : _hookArgs$resolvedDat[fieldKey]
|
|
3027
|
+
}); // TODO: FIXME
|
|
3028
|
+
} catch (error) {
|
|
3029
|
+
fieldsErrors.push({
|
|
3030
|
+
error,
|
|
3031
|
+
tag: `${list.listKey}.${fieldKey}.hooks.validateInput`
|
|
3032
|
+
});
|
|
3033
|
+
}
|
|
3034
|
+
}));
|
|
3035
|
+
if (fieldsErrors.length) {
|
|
3036
|
+
throw extensionError('validateInput', fieldsErrors);
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
// list validation hooks
|
|
3040
|
+
{
|
|
3041
|
+
const addValidationError = msg => void messages.push(`${list.listKey}: ${msg}`);
|
|
3042
|
+
const hook = list.hooks.validate[operation];
|
|
3043
|
+
try {
|
|
3044
|
+
await hook({
|
|
3045
|
+
...hookArgs,
|
|
3046
|
+
addValidationError
|
|
3047
|
+
}); // TODO: FIXME
|
|
3048
|
+
} catch (error) {
|
|
3049
|
+
throw extensionError('validateInput', [{
|
|
3050
|
+
error,
|
|
3051
|
+
tag: `${list.listKey}.hooks.validateInput`
|
|
3052
|
+
}]);
|
|
3053
|
+
}
|
|
3054
|
+
if (messages.length) {
|
|
3055
|
+
throw validationFailureError(messages);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
async function runSideEffectOnlyHook(list, hookName, args) {
|
|
3060
|
+
const {
|
|
3061
|
+
operation
|
|
3062
|
+
} = args;
|
|
3063
|
+
let shouldRunFieldLevelHook;
|
|
3064
|
+
if (operation === 'delete') {
|
|
3065
|
+
// always run field hooks for delete operations
|
|
3066
|
+
shouldRunFieldLevelHook = () => true;
|
|
3067
|
+
} else {
|
|
3068
|
+
// only run field hooks on if the field was specified in the
|
|
3069
|
+
// original input for create and update operations.
|
|
3070
|
+
const inputDataKeys = new Set(Object.keys(args.inputData));
|
|
3071
|
+
shouldRunFieldLevelHook = fieldKey => inputDataKeys.has(fieldKey);
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
// field hooks
|
|
3075
|
+
const fieldsErrors = [];
|
|
3076
|
+
await Promise.all(Object.entries(list.fields).map(async ([fieldKey, field]) => {
|
|
3077
|
+
if (shouldRunFieldLevelHook(fieldKey)) {
|
|
3078
|
+
try {
|
|
3079
|
+
var _args$item, _args$inputData, _args$resolvedData, _originalItem;
|
|
3080
|
+
await field.hooks[hookName][operation]({
|
|
3081
|
+
...args,
|
|
3082
|
+
fieldKey,
|
|
3083
|
+
itemField: (_args$item = args.item) === null || _args$item === void 0 ? void 0 : _args$item[fieldKey],
|
|
3084
|
+
inputFieldData: (_args$inputData = args.inputData) === null || _args$inputData === void 0 ? void 0 : _args$inputData[fieldKey],
|
|
3085
|
+
resolvedFieldData: (_args$resolvedData = args.resolvedData) === null || _args$resolvedData === void 0 ? void 0 : _args$resolvedData[fieldKey],
|
|
3086
|
+
originalItemField: (_originalItem = args.originalItem) === null || _originalItem === void 0 ? void 0 : _originalItem[fieldKey]
|
|
3087
|
+
}); // TODO: FIXME any
|
|
3088
|
+
} catch (error) {
|
|
3089
|
+
fieldsErrors.push({
|
|
3090
|
+
error,
|
|
3091
|
+
tag: `${list.listKey}.${fieldKey}.hooks.${hookName}`
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
}));
|
|
3096
|
+
if (fieldsErrors.length) {
|
|
3097
|
+
throw extensionError(hookName, fieldsErrors);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
// list hooks
|
|
3101
|
+
try {
|
|
3102
|
+
await list.hooks[hookName][operation](args); // TODO: FIXME any
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
throw extensionError(hookName, [{
|
|
3105
|
+
error,
|
|
3106
|
+
tag: `${list.listKey}.hooks.${hookName}`
|
|
3107
|
+
}]);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
class RelationshipErrors extends Error {
|
|
3112
|
+
constructor(errors) {
|
|
3113
|
+
super('Multiple relationship errors');
|
|
3114
|
+
this.errors = errors;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
function getResolvedUniqueWheres(uniqueInputs, context, foreignList, operation) {
|
|
3118
|
+
return uniqueInputs.map(uniqueInput => checkUniqueItemExists(uniqueInput, foreignList, context, operation));
|
|
3119
|
+
}
|
|
3120
|
+
function resolveRelateToManyForCreateInput(nestedMutationState, context, foreignList, tag) {
|
|
3121
|
+
return async value => {
|
|
3122
|
+
var _value$connect, _value$set, _value$create;
|
|
3123
|
+
if (!Array.isArray(value.connect) && !Array.isArray(value.create) && !Array.isArray(value.set)) {
|
|
3124
|
+
throw userInputError(`You must provide at least one of "set", "connect" or "create" in to-many relationship inputs for "create" operations.`);
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
// Perform queries for the connections
|
|
3128
|
+
const connects = Promise.allSettled(getResolvedUniqueWheres((_value$connect = value.connect) !== null && _value$connect !== void 0 ? _value$connect : [], context, foreignList, 'connect'));
|
|
3129
|
+
const sets = Promise.allSettled(getResolvedUniqueWheres((_value$set = value.set) !== null && _value$set !== void 0 ? _value$set : [], context, foreignList, 'set'));
|
|
3130
|
+
|
|
3131
|
+
// Perform nested mutations for the creations
|
|
3132
|
+
const creates = Promise.allSettled(((_value$create = value.create) !== null && _value$create !== void 0 ? _value$create : []).map(x => nestedMutationState.create(x, foreignList)));
|
|
3133
|
+
|
|
3134
|
+
// Resolve items
|
|
3135
|
+
const [connectResult, createResult, setResult] = await Promise.all([connects, creates, sets]);
|
|
3136
|
+
|
|
3137
|
+
// Collect all the errors
|
|
3138
|
+
const errors = [...connectResult, ...createResult, ...setResult].filter(isRejected);
|
|
3139
|
+
if (errors.length) throw new RelationshipErrors(errors.map(x => ({
|
|
3140
|
+
error: x.reason,
|
|
3141
|
+
tag
|
|
3142
|
+
})));
|
|
3143
|
+
return {
|
|
3144
|
+
connect: [...setResult, ...connectResult, ...createResult].filter(isFulfilled).map(x => x.value)
|
|
3145
|
+
};
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
3148
|
+
function resolveRelateToManyForUpdateInput(nestedMutationState, context, foreignList, tag) {
|
|
3149
|
+
return async value => {
|
|
3150
|
+
var _value$connect2, _value$disconnect, _value$set2, _value$create2;
|
|
3151
|
+
if (!Array.isArray(value.connect) && !Array.isArray(value.create) && !Array.isArray(value.disconnect) && !Array.isArray(value.set)) {
|
|
3152
|
+
throw userInputError(`You must provide at least one of "set", "connect", "create" or "disconnect" in to-many relationship inputs for "update" operations.`);
|
|
3153
|
+
}
|
|
3154
|
+
if (value.set && value.disconnect) {
|
|
3155
|
+
throw userInputError(`The "set" and "disconnect" fields cannot both be provided to to-many relationship inputs for "update" operations.`);
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// Perform queries for the connections
|
|
3159
|
+
const connects = Promise.allSettled(getResolvedUniqueWheres((_value$connect2 = value.connect) !== null && _value$connect2 !== void 0 ? _value$connect2 : [], context, foreignList, 'connect'));
|
|
3160
|
+
const disconnects = Promise.allSettled(getResolvedUniqueWheres((_value$disconnect = value.disconnect) !== null && _value$disconnect !== void 0 ? _value$disconnect : [], context, foreignList, 'disconnect'));
|
|
3161
|
+
const sets = Promise.allSettled(getResolvedUniqueWheres((_value$set2 = value.set) !== null && _value$set2 !== void 0 ? _value$set2 : [], context, foreignList, 'set'));
|
|
3162
|
+
|
|
3163
|
+
// Perform nested mutations for the creations
|
|
3164
|
+
const creates = Promise.allSettled(((_value$create2 = value.create) !== null && _value$create2 !== void 0 ? _value$create2 : []).map(x => nestedMutationState.create(x, foreignList)));
|
|
3165
|
+
|
|
3166
|
+
// Resolve items
|
|
3167
|
+
const [connectResult, createResult, disconnectResult, setResult] = await Promise.all([connects, creates, disconnects, sets]);
|
|
3168
|
+
|
|
3169
|
+
// Collect all the errors
|
|
3170
|
+
const errors = [...connectResult, ...createResult, ...disconnectResult, ...setResult].filter(isRejected);
|
|
3171
|
+
if (errors.length) throw new RelationshipErrors(errors.map(x => ({
|
|
3172
|
+
error: x.reason,
|
|
3173
|
+
tag
|
|
3174
|
+
})));
|
|
3175
|
+
return {
|
|
3176
|
+
// unlike all the other operations, an empty array isn't a no-op for set
|
|
3177
|
+
set: value.set ? setResult.filter(isFulfilled).map(x => x.value) : undefined,
|
|
3178
|
+
disconnect: disconnectResult.filter(isFulfilled).map(x => x.value),
|
|
3179
|
+
connect: [...connectResult, ...createResult].filter(isFulfilled).map(x => x.value)
|
|
3180
|
+
};
|
|
3181
|
+
};
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
async function handleCreateAndUpdate(value, nestedMutationState, context, foreignList) {
|
|
3185
|
+
if (value.connect) {
|
|
3186
|
+
return {
|
|
3187
|
+
connect: await checkUniqueItemExists(value.connect, foreignList, context, 'connect')
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
if (value.create) {
|
|
3191
|
+
const {
|
|
3192
|
+
id
|
|
3193
|
+
} = await nestedMutationState.create(value.create, foreignList);
|
|
3194
|
+
return {
|
|
3195
|
+
connect: {
|
|
3196
|
+
id
|
|
3197
|
+
}
|
|
3198
|
+
};
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
function resolveRelateToOneForCreateInput(nestedMutationState, context, foreignList) {
|
|
3202
|
+
return async value => {
|
|
3203
|
+
const numOfKeys = Object.keys(value).length;
|
|
3204
|
+
if (numOfKeys !== 1) {
|
|
3205
|
+
throw userInputError(`You must provide "connect" or "create" in to-one relationship inputs for "create" operations.`);
|
|
3206
|
+
}
|
|
3207
|
+
return handleCreateAndUpdate(value, nestedMutationState, context, foreignList);
|
|
3208
|
+
};
|
|
3209
|
+
}
|
|
3210
|
+
function resolveRelateToOneForUpdateInput(nestedMutationState, context, foreignList) {
|
|
3211
|
+
return async value => {
|
|
3212
|
+
if (Object.keys(value).length !== 1) {
|
|
3213
|
+
throw userInputError(`You must provide one of "connect", "create" or "disconnect" in to-one relationship inputs for "update" operations.`);
|
|
3214
|
+
}
|
|
3215
|
+
if (value.connect || value.create) {
|
|
3216
|
+
return handleCreateAndUpdate(value, nestedMutationState, context, foreignList);
|
|
3217
|
+
}
|
|
3218
|
+
if (value.disconnect) {
|
|
3219
|
+
return {
|
|
3220
|
+
disconnect: true
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
};
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
async function getFilteredItem(list, context, uniqueWhere, accessFilters, operation) {
|
|
3227
|
+
// early exit if they want to exclude everything
|
|
3228
|
+
if (accessFilters === false) {
|
|
3229
|
+
throw accessDeniedError(cannotForItem(operation, list));
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
// merge the filter access control and try to get the item
|
|
3233
|
+
let where = mapUniqueWhereToWhere(uniqueWhere, list);
|
|
3234
|
+
await checkFilterOrderAccess([...traverse(list, where)], context, 'filter');
|
|
3235
|
+
if (typeof accessFilters === 'object') {
|
|
3236
|
+
where = {
|
|
3237
|
+
AND: [where, await resolveWhereInput(accessFilters, list, context)]
|
|
3238
|
+
};
|
|
3239
|
+
}
|
|
3240
|
+
const item = await context.prisma[list.listKey].findFirst({
|
|
3241
|
+
where
|
|
3242
|
+
});
|
|
3243
|
+
if (item !== null) return item;
|
|
3244
|
+
throw accessDeniedError(cannotForItem(operation, list));
|
|
3245
|
+
}
|
|
3246
|
+
async function createSingle__(inputData, list, context) {
|
|
3247
|
+
return await withSpan(`create ${list.graphql.names.outputTypeNameLower}`, async span => {
|
|
3248
|
+
var _result$id;
|
|
3249
|
+
// throw an accessDeniedError if not allowed
|
|
3250
|
+
await enforceListLevelAccessControl(context, 'create', list, inputData, undefined);
|
|
3251
|
+
await enforceFieldLevelAccessControl(context, 'create', list, inputData, undefined);
|
|
3252
|
+
const {
|
|
3253
|
+
beforeOperation,
|
|
3254
|
+
afterOperation,
|
|
3255
|
+
data
|
|
3256
|
+
} = await resolveInputForCreateOrUpdate(list, context, inputData, undefined);
|
|
3257
|
+
|
|
3258
|
+
// before operation
|
|
3259
|
+
await beforeOperation();
|
|
3260
|
+
|
|
3261
|
+
// operation
|
|
3262
|
+
const result = await context.prisma[list.listKey].create({
|
|
3263
|
+
data: list.isSingleton ? {
|
|
3264
|
+
...data,
|
|
3265
|
+
id: 1
|
|
3266
|
+
} : data
|
|
3267
|
+
});
|
|
3268
|
+
span.setAttribute('nixxie.result.id', (_result$id = result === null || result === void 0 ? void 0 : result.id) !== null && _result$id !== void 0 ? _result$id : '');
|
|
3269
|
+
return {
|
|
3270
|
+
item: result,
|
|
3271
|
+
afterOperation
|
|
3272
|
+
};
|
|
3273
|
+
}, {
|
|
3274
|
+
'nixxie.list': list.listKey,
|
|
3275
|
+
'nixxie.operation': 'create'
|
|
3276
|
+
});
|
|
3277
|
+
}
|
|
3278
|
+
var _afterOperations = /*#__PURE__*/new WeakMap();
|
|
3279
|
+
var _context = /*#__PURE__*/new WeakMap();
|
|
3280
|
+
class NestedMutationState {
|
|
3281
|
+
constructor(context) {
|
|
3282
|
+
_classPrivateFieldInitSpec(this, _afterOperations, []);
|
|
3283
|
+
_classPrivateFieldInitSpec(this, _context, void 0);
|
|
3284
|
+
_classPrivateFieldSet(_context, this, context);
|
|
3285
|
+
}
|
|
3286
|
+
async create(data, list) {
|
|
3287
|
+
const context = _classPrivateFieldGet(_context, this);
|
|
3288
|
+
const operationAccess = await getOperationAccess(list, context, 'create');
|
|
3289
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));
|
|
3290
|
+
|
|
3291
|
+
// before operation AND operation
|
|
3292
|
+
const {
|
|
3293
|
+
item,
|
|
3294
|
+
afterOperation
|
|
3295
|
+
} = await createSingle__(data, list, context);
|
|
3296
|
+
|
|
3297
|
+
// after operation
|
|
3298
|
+
_classPrivateFieldGet(_afterOperations, this).push(() => afterOperation(item));
|
|
3299
|
+
return {
|
|
3300
|
+
id: item.id
|
|
3301
|
+
};
|
|
3302
|
+
}
|
|
3303
|
+
async afterOperation() {
|
|
3304
|
+
await promiseAllRejectWithAllErrors(_classPrivateFieldGet(_afterOperations, this).map(async x => x()));
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
async function updateSingle__({
|
|
3308
|
+
where,
|
|
3309
|
+
data: inputData
|
|
3310
|
+
}, list, context, accessFilters) {
|
|
3311
|
+
return await withSpan(`update ${list.graphql.names.outputTypeNameLower}`, async span => {
|
|
3312
|
+
var _result$id2;
|
|
3313
|
+
// validate and resolve the input filter
|
|
3314
|
+
const uniqueWhere = await resolveUniqueWhereInput(where, list, context);
|
|
3315
|
+
|
|
3316
|
+
// filter and item access control - throws an AccessDeniedError if not allowed
|
|
3317
|
+
const item = await getFilteredItem(list, context, uniqueWhere, accessFilters, 'update');
|
|
3318
|
+
|
|
3319
|
+
// throw an accessDeniedError if not allowed
|
|
3320
|
+
await enforceListLevelAccessControl(context, 'update', list, inputData !== null && inputData !== void 0 ? inputData : {}, item);
|
|
3321
|
+
await enforceFieldLevelAccessControl(context, 'update', list, inputData !== null && inputData !== void 0 ? inputData : {}, item);
|
|
3322
|
+
const {
|
|
3323
|
+
beforeOperation,
|
|
3324
|
+
afterOperation,
|
|
3325
|
+
data
|
|
3326
|
+
} = await resolveInputForCreateOrUpdate(list, context, inputData !== null && inputData !== void 0 ? inputData : {}, item);
|
|
3327
|
+
|
|
3328
|
+
// before operation
|
|
3329
|
+
await beforeOperation();
|
|
3330
|
+
|
|
3331
|
+
// operation
|
|
3332
|
+
const result = await context.prisma[list.listKey].update({
|
|
3333
|
+
where: {
|
|
3334
|
+
id: item.id
|
|
3335
|
+
},
|
|
3336
|
+
data
|
|
3337
|
+
});
|
|
3338
|
+
span.setAttribute('nixxie.result.id', (_result$id2 = result === null || result === void 0 ? void 0 : result.id) !== null && _result$id2 !== void 0 ? _result$id2 : '');
|
|
3339
|
+
|
|
3340
|
+
// after operation
|
|
3341
|
+
await afterOperation(result);
|
|
3342
|
+
return result;
|
|
3343
|
+
}, {
|
|
3344
|
+
'nixxie.list': list.listKey,
|
|
3345
|
+
'nixxie.operation': 'update'
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
async function deleteSingle__(where, list, context, accessFilters) {
|
|
3349
|
+
return await withSpan(`delete ${list.graphql.names.outputTypeNameLower}`, async span => {
|
|
3350
|
+
var _result$id3;
|
|
3351
|
+
// validate and resolve the input filter
|
|
3352
|
+
const uniqueWhere = await resolveUniqueWhereInput(where, list, context);
|
|
3353
|
+
|
|
3354
|
+
// filter and item access control throw an AccessDeniedError if not allowed
|
|
3355
|
+
// apply access.filter.* controls
|
|
3356
|
+
const item = await getFilteredItem(list, context, uniqueWhere, accessFilters, 'delete');
|
|
3357
|
+
await enforceListLevelAccessControl(context, 'delete', list, {}, item);
|
|
3358
|
+
// WARNING: no field level access control for delete operations
|
|
3359
|
+
|
|
3360
|
+
const hookArgs = {
|
|
3361
|
+
operation: 'delete',
|
|
3362
|
+
listKey: list.listKey,
|
|
3363
|
+
context,
|
|
3364
|
+
item,
|
|
3365
|
+
resolvedData: undefined,
|
|
3366
|
+
inputData: undefined
|
|
3367
|
+
};
|
|
3368
|
+
|
|
3369
|
+
// hooks
|
|
3370
|
+
await validate({
|
|
3371
|
+
list,
|
|
3372
|
+
hookArgs
|
|
3373
|
+
});
|
|
3374
|
+
|
|
3375
|
+
// before operation
|
|
3376
|
+
await runSideEffectOnlyHook(list, 'beforeOperation', hookArgs);
|
|
3377
|
+
|
|
3378
|
+
// operation
|
|
3379
|
+
const result = await context.prisma[list.listKey].delete({
|
|
3380
|
+
where: {
|
|
3381
|
+
id: item.id
|
|
3382
|
+
}
|
|
3383
|
+
});
|
|
3384
|
+
span.setAttribute('nixxie.result.id', (_result$id3 = result === null || result === void 0 ? void 0 : result.id) !== null && _result$id3 !== void 0 ? _result$id3 : '');
|
|
3385
|
+
|
|
3386
|
+
// after operation
|
|
3387
|
+
await runSideEffectOnlyHook(list, 'afterOperation', {
|
|
3388
|
+
...hookArgs,
|
|
3389
|
+
item: undefined,
|
|
3390
|
+
originalItem: item
|
|
3391
|
+
});
|
|
3392
|
+
return result;
|
|
3393
|
+
}, {
|
|
3394
|
+
'nixxie.list': list.listKey,
|
|
3395
|
+
'nixxie.operation': 'delete'
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
async function actionSingle__(context, list, action, {
|
|
3399
|
+
where,
|
|
3400
|
+
args
|
|
3401
|
+
}) {
|
|
3402
|
+
return await withSpan(action.otel, async span => {
|
|
3403
|
+
var _ref;
|
|
3404
|
+
// no before operation hook for actions
|
|
3405
|
+
|
|
3406
|
+
// operation
|
|
3407
|
+
const result = await action.resolve({
|
|
3408
|
+
listKey: list.listKey,
|
|
3409
|
+
actionKey: action.actionKey,
|
|
3410
|
+
where,
|
|
3411
|
+
args
|
|
3412
|
+
}, context);
|
|
3413
|
+
span.setAttribute('nixxie.result.id', (_ref = result === null || result === void 0 ? void 0 : result.id) !== null && _ref !== void 0 ? _ref : '');
|
|
3414
|
+
|
|
3415
|
+
// no after operation hook for actions
|
|
3416
|
+
return result;
|
|
3417
|
+
}, {
|
|
3418
|
+
'nixxie.list': list.listKey,
|
|
3419
|
+
'nixxie.action': action.actionKey
|
|
3420
|
+
});
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
//
|
|
3424
|
+
|
|
3425
|
+
async function createOne(inputData, list, context) {
|
|
3426
|
+
const operationAccess = await getOperationAccess(list, context, 'create');
|
|
3427
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));
|
|
3428
|
+
|
|
3429
|
+
// get list-level access control filters
|
|
3430
|
+
// NOTHING - no filters for create operations
|
|
3431
|
+
|
|
3432
|
+
// operation
|
|
3433
|
+
const {
|
|
3434
|
+
item,
|
|
3435
|
+
afterOperation
|
|
3436
|
+
} = await createSingle__(inputData !== null && inputData !== void 0 ? inputData : {}, list, context);
|
|
3437
|
+
|
|
3438
|
+
// after operation // TODO: move to createSingle__
|
|
3439
|
+
await afterOperation(item);
|
|
3440
|
+
return item;
|
|
3441
|
+
}
|
|
3442
|
+
async function createMany(inputDatas, list, context) {
|
|
3443
|
+
const operationAccess = await getOperationAccess(list, context, 'create');
|
|
3444
|
+
// WARNING: we do not short-circuit here, we throw for each
|
|
3445
|
+
|
|
3446
|
+
// get list-level access control filters
|
|
3447
|
+
// NOTHING - no filters for create operations
|
|
3448
|
+
|
|
3449
|
+
return inputDatas.map(async inputData => {
|
|
3450
|
+
// throw for each attempt
|
|
3451
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));
|
|
3452
|
+
|
|
3453
|
+
// operation
|
|
3454
|
+
const {
|
|
3455
|
+
item,
|
|
3456
|
+
afterOperation
|
|
3457
|
+
} = await createSingle__(inputData !== null && inputData !== void 0 ? inputData : {}, list, context);
|
|
3458
|
+
|
|
3459
|
+
// after operation // TODO: move to createSingle__
|
|
3460
|
+
await afterOperation(item);
|
|
3461
|
+
return item;
|
|
3462
|
+
});
|
|
3463
|
+
}
|
|
3464
|
+
async function updateOne(updateInput, list, context) {
|
|
3465
|
+
const operationAccess = await getOperationAccess(list, context, 'update');
|
|
3466
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('update', list));
|
|
3467
|
+
|
|
3468
|
+
// get list-level access control filters
|
|
3469
|
+
const accessFilters = await getAccessFilters(list, context, 'update');
|
|
3470
|
+
return updateSingle__(updateInput, list, context, accessFilters);
|
|
3471
|
+
}
|
|
3472
|
+
async function updateMany(updateManyInput, list, context) {
|
|
3473
|
+
const operationAccess = await getOperationAccess(list, context, 'update');
|
|
3474
|
+
// WARNING: we do not short-circuit here, we throw for each
|
|
3475
|
+
|
|
3476
|
+
// get list-level access control filters
|
|
3477
|
+
const accessFilters = await getAccessFilters(list, context, 'update');
|
|
3478
|
+
return updateManyInput.map(async updateInput => {
|
|
3479
|
+
// throw for each attempt
|
|
3480
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('update', list));
|
|
3481
|
+
return updateSingle__(updateInput, list, context, accessFilters);
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3484
|
+
async function deleteOne(where, list, context) {
|
|
3485
|
+
const operationAccess = await getOperationAccess(list, context, 'delete');
|
|
3486
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('delete', list));
|
|
3487
|
+
|
|
3488
|
+
// get list-level access control filters
|
|
3489
|
+
const accessFilters = await getAccessFilters(list, context, 'delete');
|
|
3490
|
+
return deleteSingle__(where, list, context, accessFilters);
|
|
3491
|
+
}
|
|
3492
|
+
async function deleteMany(wheres, list, context) {
|
|
3493
|
+
const operationAccess = await getOperationAccess(list, context, 'delete');
|
|
3494
|
+
// WARNING: we do not short-circuit here, we throw for each
|
|
3495
|
+
|
|
3496
|
+
// get list-level access control filters
|
|
3497
|
+
const accessFilters = await getAccessFilters(list, context, 'delete');
|
|
3498
|
+
return wheres.map(async where => {
|
|
3499
|
+
// throw for each attempt
|
|
3500
|
+
if (!operationAccess) throw accessDeniedError(cannotForItem('delete', list));
|
|
3501
|
+
return deleteSingle__(where, list, context, accessFilters);
|
|
3502
|
+
});
|
|
3503
|
+
}
|
|
3504
|
+
async function actionOne(input, list, context, action) {
|
|
3505
|
+
const operationAccess = await action.access({
|
|
3506
|
+
context,
|
|
3507
|
+
session: context.session,
|
|
3508
|
+
// TODO: remove in breaking change
|
|
3509
|
+
listKey: list.listKey,
|
|
3510
|
+
actionKey: action.actionKey
|
|
3511
|
+
});
|
|
3512
|
+
if (!operationAccess) throw accessDeniedError(cannotActionForItem(action, list));
|
|
3513
|
+
|
|
3514
|
+
// get list-level access control filters
|
|
3515
|
+
// NOTHING - no filters for action operations
|
|
3516
|
+
|
|
3517
|
+
return actionSingle__(context, list, action, input);
|
|
3518
|
+
}
|
|
3519
|
+
async function actionMany(inputs, list, context, action) {
|
|
3520
|
+
const operationAccess = await action.access({
|
|
3521
|
+
context,
|
|
3522
|
+
session: context.session,
|
|
3523
|
+
// TODO: remove in breaking change
|
|
3524
|
+
listKey: list.listKey,
|
|
3525
|
+
actionKey: action.actionKey
|
|
3526
|
+
});
|
|
3527
|
+
// WARNING: we do not short-circuit here, we throw for each
|
|
3528
|
+
|
|
3529
|
+
// get list-level access control filters
|
|
3530
|
+
// NOTHING - no filters for action operations
|
|
3531
|
+
|
|
3532
|
+
return inputs.map(async ({
|
|
3533
|
+
where,
|
|
3534
|
+
...args
|
|
3535
|
+
}) => {
|
|
3536
|
+
// throw for each attempt
|
|
3537
|
+
if (!operationAccess) throw accessDeniedError(cannotActionForItem(action, list));
|
|
3538
|
+
return actionSingle__(context, list, action, {
|
|
3539
|
+
where,
|
|
3540
|
+
args
|
|
3541
|
+
});
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3544
|
+
async function getResolvedData(list, hookArgs, nestedMutationState) {
|
|
3545
|
+
const {
|
|
3546
|
+
context,
|
|
3547
|
+
operation
|
|
3548
|
+
} = hookArgs;
|
|
3549
|
+
let resolvedData = hookArgs.inputData;
|
|
3550
|
+
|
|
3551
|
+
// apply non-relationship field type input resolvers
|
|
3552
|
+
const resolverErrors = [];
|
|
3553
|
+
resolvedData = Object.fromEntries(await Promise.all(Object.entries(list.fields).map(async ([fieldKey, field]) => {
|
|
3554
|
+
var _field$input;
|
|
3555
|
+
const inputResolver = (_field$input = field.input) === null || _field$input === void 0 || (_field$input = _field$input[operation]) === null || _field$input === void 0 ? void 0 : _field$input.resolve;
|
|
3556
|
+
if (inputResolver && field.dbField.kind !== 'relation') {
|
|
3557
|
+
try {
|
|
3558
|
+
return [fieldKey, await inputResolver(resolvedData[fieldKey], context, undefined)];
|
|
3559
|
+
} catch (error) {
|
|
3560
|
+
resolverErrors.push({
|
|
3561
|
+
error,
|
|
3562
|
+
tag: `${list.listKey}.${fieldKey}`
|
|
3563
|
+
});
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
return [fieldKey, resolvedData[fieldKey]];
|
|
3567
|
+
})));
|
|
3568
|
+
if (resolverErrors.length) throw resolverError(resolverErrors);
|
|
3569
|
+
|
|
3570
|
+
// apply relationship field type input resolvers
|
|
3571
|
+
const relationshipErrors = [];
|
|
3572
|
+
resolvedData = Object.fromEntries(await Promise.all(Object.entries(list.fields).map(async ([fieldKey, field]) => {
|
|
3573
|
+
var _field$input2;
|
|
3574
|
+
const inputResolver = (_field$input2 = field.input) === null || _field$input2 === void 0 || (_field$input2 = _field$input2[operation]) === null || _field$input2 === void 0 ? void 0 : _field$input2.resolve;
|
|
3575
|
+
let input = resolvedData[fieldKey];
|
|
3576
|
+
if (inputResolver && field.dbField.kind === 'relation') {
|
|
3577
|
+
const tag = `${list.listKey}.${fieldKey}`;
|
|
3578
|
+
try {
|
|
3579
|
+
input = await inputResolver(input, context,
|
|
3580
|
+
// this third argument only applies to relationship fields
|
|
3581
|
+
(() => {
|
|
3582
|
+
if (input === undefined) {
|
|
3583
|
+
// no-op: this is what we want
|
|
3584
|
+
return () => undefined;
|
|
3585
|
+
}
|
|
3586
|
+
if (input === null) {
|
|
3587
|
+
// no-op: should this be userinputerror?
|
|
3588
|
+
return () => undefined;
|
|
3589
|
+
}
|
|
3590
|
+
const foreignList = list.lists[field.dbField.list];
|
|
3591
|
+
if (field.dbField.mode === 'many' && operation === 'create') {
|
|
3592
|
+
return resolveRelateToManyForCreateInput(nestedMutationState, context, foreignList, tag);
|
|
3593
|
+
}
|
|
3594
|
+
if (field.dbField.mode === 'many' && operation === 'update') {
|
|
3595
|
+
return resolveRelateToManyForUpdateInput(nestedMutationState, context, foreignList, tag);
|
|
3596
|
+
}
|
|
3597
|
+
if (field.dbField.mode === 'one' && operation === 'create') {
|
|
3598
|
+
return resolveRelateToOneForCreateInput(nestedMutationState, context, foreignList);
|
|
3599
|
+
}
|
|
3600
|
+
if (field.dbField.mode === 'one' && operation === 'update') {
|
|
3601
|
+
return resolveRelateToOneForUpdateInput(nestedMutationState, context, foreignList);
|
|
3602
|
+
}
|
|
3603
|
+
throw new Error('Unknown relationship field type input mode or operation');
|
|
3604
|
+
})());
|
|
3605
|
+
} catch (error) {
|
|
3606
|
+
if (error instanceof RelationshipErrors) {
|
|
3607
|
+
relationshipErrors.push(...error.errors);
|
|
3608
|
+
} else {
|
|
3609
|
+
relationshipErrors.push({
|
|
3610
|
+
error,
|
|
3611
|
+
tag
|
|
3612
|
+
});
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
return [fieldKey, input];
|
|
3617
|
+
})));
|
|
3618
|
+
if (relationshipErrors.length) throw relationshipError(relationshipErrors);
|
|
3619
|
+
|
|
3620
|
+
// field hooks
|
|
3621
|
+
const fieldsErrors = [];
|
|
3622
|
+
resolvedData = Object.fromEntries(await Promise.all(Object.entries(list.fields).map(async ([fieldKey, field]) => {
|
|
3623
|
+
try {
|
|
3624
|
+
return [fieldKey, operation === 'create' ? await field.hooks.resolveInput.create({
|
|
3625
|
+
...hookArgs,
|
|
3626
|
+
itemField: undefined,
|
|
3627
|
+
inputFieldData: hookArgs.inputData[fieldKey],
|
|
3628
|
+
resolvedData,
|
|
3629
|
+
resolvedFieldData: resolvedData[fieldKey],
|
|
3630
|
+
fieldKey
|
|
3631
|
+
}) : await field.hooks.resolveInput.update({
|
|
3632
|
+
...hookArgs,
|
|
3633
|
+
itemField: hookArgs.item[fieldKey],
|
|
3634
|
+
inputFieldData: hookArgs.inputData[fieldKey],
|
|
3635
|
+
resolvedData,
|
|
3636
|
+
resolvedFieldData: resolvedData[fieldKey],
|
|
3637
|
+
fieldKey
|
|
3638
|
+
})];
|
|
3639
|
+
} catch (error) {
|
|
3640
|
+
fieldsErrors.push({
|
|
3641
|
+
error,
|
|
3642
|
+
tag: `${list.listKey}.${fieldKey}.hooks.resolveInput`
|
|
3643
|
+
});
|
|
3644
|
+
return [fieldKey, undefined];
|
|
3645
|
+
}
|
|
3646
|
+
})));
|
|
3647
|
+
if (fieldsErrors.length) throw extensionError('resolveInput', fieldsErrors);
|
|
3648
|
+
|
|
3649
|
+
// list hooks
|
|
3650
|
+
try {
|
|
3651
|
+
if (operation === 'create') {
|
|
3652
|
+
resolvedData = await list.hooks.resolveInput.create({
|
|
3653
|
+
...hookArgs,
|
|
3654
|
+
resolvedData
|
|
3655
|
+
});
|
|
3656
|
+
} else if (operation === 'update') {
|
|
3657
|
+
resolvedData = await list.hooks.resolveInput.update({
|
|
3658
|
+
...hookArgs,
|
|
3659
|
+
resolvedData
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
} catch (error) {
|
|
3663
|
+
throw extensionError('resolveInput', [{
|
|
3664
|
+
error,
|
|
3665
|
+
tag: `${list.listKey}.hooks.resolveInput`
|
|
3666
|
+
}]);
|
|
3667
|
+
}
|
|
3668
|
+
return resolvedData;
|
|
3669
|
+
}
|
|
3670
|
+
async function resolveInputForCreateOrUpdate(list, context, inputData, item) {
|
|
3671
|
+
const nestedMutationState = new NestedMutationState(context);
|
|
3672
|
+
const baseHookArgs = {
|
|
3673
|
+
context,
|
|
3674
|
+
listKey: list.listKey,
|
|
3675
|
+
inputData,
|
|
3676
|
+
resolvedData: {}
|
|
3677
|
+
};
|
|
3678
|
+
const hookArgs = item === undefined ? {
|
|
3679
|
+
...baseHookArgs,
|
|
3680
|
+
operation: 'create',
|
|
3681
|
+
item,
|
|
3682
|
+
originalItem: undefined
|
|
3683
|
+
} : {
|
|
3684
|
+
...baseHookArgs,
|
|
3685
|
+
operation: 'update',
|
|
3686
|
+
item,
|
|
3687
|
+
originalItem: item
|
|
3688
|
+
};
|
|
3689
|
+
|
|
3690
|
+
// Take the original input and resolve all the fields down to what
|
|
3691
|
+
// will be saved into the database.
|
|
3692
|
+
hookArgs.resolvedData = await getResolvedData(list, hookArgs, nestedMutationState);
|
|
3693
|
+
|
|
3694
|
+
// Apply all validation checks
|
|
3695
|
+
await validate({
|
|
3696
|
+
list,
|
|
3697
|
+
hookArgs
|
|
3698
|
+
});
|
|
3699
|
+
|
|
3700
|
+
// Return the full resolved input (ready for prisma level operation),
|
|
3701
|
+
// and the afterOperation hook to be applied
|
|
3702
|
+
return {
|
|
3703
|
+
data: transformForPrismaClient(list, context, hookArgs.resolvedData),
|
|
3704
|
+
beforeOperation: async () => {
|
|
3705
|
+
// before operation
|
|
3706
|
+
await runSideEffectOnlyHook(list, 'beforeOperation', hookArgs);
|
|
3707
|
+
},
|
|
3708
|
+
afterOperation: async updatedItem => {
|
|
3709
|
+
await nestedMutationState.afterOperation();
|
|
3710
|
+
|
|
3711
|
+
// after operation
|
|
3712
|
+
await runSideEffectOnlyHook(list, 'afterOperation', {
|
|
3713
|
+
...hookArgs,
|
|
3714
|
+
item: updatedItem
|
|
3715
|
+
});
|
|
3716
|
+
}
|
|
3717
|
+
};
|
|
3718
|
+
}
|
|
3719
|
+
function transformInnerDBField(dbField, context, value) {
|
|
3720
|
+
if (dbField.kind === 'scalar' && dbField.scalar === 'Json' && value === null) {
|
|
3721
|
+
return context.__internal.prisma.DbNull;
|
|
3722
|
+
}
|
|
3723
|
+
return value;
|
|
3724
|
+
}
|
|
3725
|
+
function transformForPrismaClient(list, context, data) {
|
|
3726
|
+
return Object.fromEntries([...function* () {
|
|
3727
|
+
for (const fieldKey in data) {
|
|
3728
|
+
if (!(fieldKey in list.fields)) {
|
|
3729
|
+
// either the types are wrong, or someone didnt use them, either way, bail out
|
|
3730
|
+
throw new Error(`Attempted to use unknown field "${fieldKey}"`);
|
|
3731
|
+
}
|
|
3732
|
+
const value = data[fieldKey];
|
|
3733
|
+
const {
|
|
3734
|
+
dbField
|
|
3735
|
+
} = list.fields[fieldKey];
|
|
3736
|
+
if (dbField.kind === 'multi') {
|
|
3737
|
+
for (const innerFieldKey in value) {
|
|
3738
|
+
const innerFieldValue = value[innerFieldKey];
|
|
3739
|
+
yield [getDBFieldKeyForFieldOnMultiField(fieldKey, innerFieldKey), transformInnerDBField(dbField.fields[innerFieldKey], context, innerFieldValue)];
|
|
3740
|
+
}
|
|
3741
|
+
continue;
|
|
3742
|
+
}
|
|
3743
|
+
yield [fieldKey, transformInnerDBField(dbField, context, value)];
|
|
3744
|
+
}
|
|
3745
|
+
}()]);
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
// This is not a thing that I really agree with but it's to make the behaviour consistent with old nixxie.
|
|
3749
|
+
// Basically, old nixxie uses Promise.allSettled and then after that maps that into promises that resolve and reject,
|
|
3750
|
+
// whereas the new stuff is just like "here are some promises" with no guarantees about the order they will be settled in.
|
|
3751
|
+
// That doesn't matter when they all resolve successfully because the order they resolve successfully in
|
|
3752
|
+
// doesn't affect anything, If some reject though, the order that they reject in will be the order in the errors array
|
|
3753
|
+
// and some of our tests rely on the order of the graphql errors array. They shouldn't, but they do.
|
|
3754
|
+
function promisesButSettledWhenAllSettledAndInOrder(promises) {
|
|
3755
|
+
const resultsPromise = Promise.allSettled(promises);
|
|
3756
|
+
return promises.map(async (_, i) => {
|
|
3757
|
+
const result = (await resultsPromise)[i];
|
|
3758
|
+
return result.status === 'fulfilled' ? Promise.resolve(result.value) : Promise.reject(result.reason);
|
|
3759
|
+
});
|
|
3760
|
+
}
|
|
3761
|
+
function nonNull(t) {
|
|
3762
|
+
if (t === g.Empty) return t;
|
|
3763
|
+
return g.nonNull(t);
|
|
3764
|
+
}
|
|
3765
|
+
function getMutationsForList(list) {
|
|
3766
|
+
const defaultUniqueWhereInput = list.isSingleton ? {
|
|
3767
|
+
id: '1'
|
|
3768
|
+
} : undefined;
|
|
3769
|
+
const createOne_ = g.field({
|
|
3770
|
+
type: list.graphql.types.output,
|
|
3771
|
+
args: {
|
|
3772
|
+
data: g.arg({
|
|
3773
|
+
type: nonNull(list.graphql.types.create)
|
|
3774
|
+
})
|
|
3775
|
+
},
|
|
3776
|
+
async resolve(_, {
|
|
3777
|
+
data
|
|
3778
|
+
}, context, info) {
|
|
3779
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3780
|
+
return createOne(data, list, context);
|
|
3781
|
+
}, {
|
|
3782
|
+
'nixxie.list': list.listKey,
|
|
3783
|
+
'nixxie.operation': 'create'
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3786
|
+
});
|
|
3787
|
+
const createMany_ = g.field({
|
|
3788
|
+
type: g.list(list.graphql.types.output),
|
|
3789
|
+
args: {
|
|
3790
|
+
data: g.arg({
|
|
3791
|
+
type: g.nonNull(g.list(nonNull(list.graphql.types.create)))
|
|
3792
|
+
})
|
|
3793
|
+
},
|
|
3794
|
+
async resolve(_, {
|
|
3795
|
+
data
|
|
3796
|
+
}, context, info) {
|
|
3797
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3798
|
+
return promisesButSettledWhenAllSettledAndInOrder(await createMany(data, list, context));
|
|
3799
|
+
}, {
|
|
3800
|
+
'nixxie.list': list.listKey,
|
|
3801
|
+
'nixxie.operation': 'create',
|
|
3802
|
+
'nixxie.many': true
|
|
3803
|
+
});
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
const updateOne_ = g.field({
|
|
3807
|
+
type: list.graphql.types.output,
|
|
3808
|
+
args: {
|
|
3809
|
+
where: g.arg({
|
|
3810
|
+
type: g.nonNull(list.graphql.types.uniqueWhere),
|
|
3811
|
+
defaultValue: defaultUniqueWhereInput
|
|
3812
|
+
}),
|
|
3813
|
+
data: g.arg({
|
|
3814
|
+
type: nonNull(list.graphql.types.update)
|
|
3815
|
+
})
|
|
3816
|
+
},
|
|
3817
|
+
async resolve(_, {
|
|
3818
|
+
where,
|
|
3819
|
+
data
|
|
3820
|
+
}, context, info) {
|
|
3821
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3822
|
+
return updateOne({
|
|
3823
|
+
where,
|
|
3824
|
+
data
|
|
3825
|
+
}, list, context);
|
|
3826
|
+
}, {
|
|
3827
|
+
'nixxie.list': list.listKey,
|
|
3828
|
+
'nixxie.operation': 'update'
|
|
3829
|
+
});
|
|
3830
|
+
}
|
|
3831
|
+
});
|
|
3832
|
+
const updateManyInput = g.inputObject({
|
|
3833
|
+
name: list.graphql.names.updateManyInputName,
|
|
3834
|
+
fields: {
|
|
3835
|
+
where: g.arg({
|
|
3836
|
+
type: g.nonNull(list.graphql.types.uniqueWhere),
|
|
3837
|
+
defaultValue: defaultUniqueWhereInput
|
|
3838
|
+
}),
|
|
3839
|
+
data: g.arg({
|
|
3840
|
+
type: nonNull(list.graphql.types.update)
|
|
3841
|
+
})
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
const updateMany_ = g.field({
|
|
3845
|
+
type: g.list(list.graphql.types.output),
|
|
3846
|
+
args: {
|
|
3847
|
+
data: g.arg({
|
|
3848
|
+
type: g.nonNull(g.list(g.nonNull(updateManyInput)))
|
|
3849
|
+
})
|
|
3850
|
+
},
|
|
3851
|
+
async resolve(_, {
|
|
3852
|
+
data
|
|
3853
|
+
}, context, info) {
|
|
3854
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3855
|
+
return promisesButSettledWhenAllSettledAndInOrder(await updateMany(data, list, context));
|
|
3856
|
+
}, {
|
|
3857
|
+
'nixxie.list': list.listKey,
|
|
3858
|
+
'nixxie.operation': 'update',
|
|
3859
|
+
'nixxie.many': true
|
|
3860
|
+
});
|
|
3861
|
+
}
|
|
3862
|
+
});
|
|
3863
|
+
const deleteOne_ = g.field({
|
|
3864
|
+
type: list.graphql.types.output,
|
|
3865
|
+
args: {
|
|
3866
|
+
where: g.arg({
|
|
3867
|
+
type: g.nonNull(list.graphql.types.uniqueWhere),
|
|
3868
|
+
defaultValue: defaultUniqueWhereInput
|
|
3869
|
+
})
|
|
3870
|
+
},
|
|
3871
|
+
async resolve(_, {
|
|
3872
|
+
where
|
|
3873
|
+
}, context, info) {
|
|
3874
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3875
|
+
return deleteOne(where, list, context);
|
|
3876
|
+
}, {
|
|
3877
|
+
'nixxie.list': list.listKey,
|
|
3878
|
+
'nixxie.operation': 'delete'
|
|
3879
|
+
});
|
|
3880
|
+
}
|
|
3881
|
+
});
|
|
3882
|
+
const deleteMany_ = g.field({
|
|
3883
|
+
type: g.list(list.graphql.types.output),
|
|
3884
|
+
args: {
|
|
3885
|
+
where: g.arg({
|
|
3886
|
+
type: g.nonNull(g.list(g.nonNull(list.graphql.types.uniqueWhere)))
|
|
3887
|
+
})
|
|
3888
|
+
},
|
|
3889
|
+
async resolve(_, {
|
|
3890
|
+
where
|
|
3891
|
+
}, context, info) {
|
|
3892
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3893
|
+
return promisesButSettledWhenAllSettledAndInOrder(await deleteMany(where, list, context));
|
|
3894
|
+
}, {
|
|
3895
|
+
'nixxie.list': list.listKey,
|
|
3896
|
+
'nixxie.operation': 'delete',
|
|
3897
|
+
'nixxie.many': true
|
|
3898
|
+
});
|
|
3899
|
+
}
|
|
3900
|
+
});
|
|
3901
|
+
const collectedTypes = [];
|
|
3902
|
+
const {
|
|
3903
|
+
isEnabled
|
|
3904
|
+
} = list.graphql;
|
|
3905
|
+
if (isEnabled.type) {
|
|
3906
|
+
// adding all of these types explicitly isn't strictly necessary but we do it to create a certain order in the schema
|
|
3907
|
+
collectedTypes.push(list.graphql.types.output);
|
|
3908
|
+
if (isEnabled.query || isEnabled.update || isEnabled.delete) {
|
|
3909
|
+
collectedTypes.push(list.graphql.types.uniqueWhere);
|
|
3910
|
+
}
|
|
3911
|
+
if (isEnabled.query) {
|
|
3912
|
+
for (const field of Object.values(list.fields)) {
|
|
3913
|
+
if (isEnabled.query && field.graphql.isEnabled.read && field.unreferencedConcreteInterfaceImplementations) {
|
|
3914
|
+
// this _IS_ actually necessary since they aren't implicitly referenced by other types, unlike the types above
|
|
3915
|
+
collectedTypes.push(...field.unreferencedConcreteInterfaceImplementations);
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
collectedTypes.push(list.graphql.types.where);
|
|
3919
|
+
collectedTypes.push(list.graphql.types.orderBy);
|
|
3920
|
+
}
|
|
3921
|
+
if (isEnabled.update) {
|
|
3922
|
+
if (list.graphql.types.update instanceof GInputObjectType) {
|
|
3923
|
+
collectedTypes.push(list.graphql.types.update);
|
|
3924
|
+
}
|
|
3925
|
+
collectedTypes.push(updateManyInput);
|
|
3926
|
+
}
|
|
3927
|
+
if (isEnabled.create) {
|
|
3928
|
+
if (list.graphql.types.create instanceof GInputObjectType) {
|
|
3929
|
+
collectedTypes.push(list.graphql.types.create);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
return {
|
|
3934
|
+
mutations: {
|
|
3935
|
+
...(list.graphql.isEnabled.create && {
|
|
3936
|
+
[list.graphql.names.createMutationName]: createOne_,
|
|
3937
|
+
[list.graphql.names.createManyMutationName]: createMany_
|
|
3938
|
+
}),
|
|
3939
|
+
...(list.graphql.isEnabled.update && {
|
|
3940
|
+
[list.graphql.names.updateMutationName]: updateOne_,
|
|
3941
|
+
[list.graphql.names.updateManyMutationName]: updateMany_
|
|
3942
|
+
}),
|
|
3943
|
+
...(list.graphql.isEnabled.delete && {
|
|
3944
|
+
[list.graphql.names.deleteMutationName]: deleteOne_,
|
|
3945
|
+
[list.graphql.names.deleteManyMutationName]: deleteMany_
|
|
3946
|
+
}),
|
|
3947
|
+
...Object.fromEntries(function* () {
|
|
3948
|
+
for (const action of list.actions) {
|
|
3949
|
+
yield [action.graphql.names.one, g.field({
|
|
3950
|
+
type: list.graphql.types.output,
|
|
3951
|
+
args: {
|
|
3952
|
+
where: g.arg({
|
|
3953
|
+
type: g.nonNull(list.graphql.types.uniqueWhere),
|
|
3954
|
+
defaultValue: defaultUniqueWhereInput
|
|
3955
|
+
}),
|
|
3956
|
+
...action.graphql.types.arguments
|
|
3957
|
+
},
|
|
3958
|
+
async resolve(_, {
|
|
3959
|
+
where,
|
|
3960
|
+
...args
|
|
3961
|
+
}, context, info) {
|
|
3962
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3963
|
+
return actionOne({
|
|
3964
|
+
where,
|
|
3965
|
+
args
|
|
3966
|
+
}, list, context, action);
|
|
3967
|
+
}, {
|
|
3968
|
+
'nixxie.list': list.listKey,
|
|
3969
|
+
'nixxie.action': action.actionKey
|
|
3970
|
+
});
|
|
3971
|
+
}
|
|
3972
|
+
})];
|
|
3973
|
+
yield [action.graphql.names.many, g.field({
|
|
3974
|
+
type: g.list(list.graphql.types.output),
|
|
3975
|
+
args: {
|
|
3976
|
+
data: g.arg({
|
|
3977
|
+
type: g.nonNull(g.list(g.nonNull(action.graphql.types.args)))
|
|
3978
|
+
})
|
|
3979
|
+
},
|
|
3980
|
+
async resolve(_, {
|
|
3981
|
+
data
|
|
3982
|
+
}, context, info) {
|
|
3983
|
+
return await withSpan(`mutation ${info.fieldName}`, async () => {
|
|
3984
|
+
return promisesButSettledWhenAllSettledAndInOrder(await actionMany(data, list, context, action));
|
|
3985
|
+
}, {
|
|
3986
|
+
'nixxie.list': list.listKey,
|
|
3987
|
+
'nixxie.action': action.actionKey,
|
|
3988
|
+
'nixxie.many': true
|
|
3989
|
+
});
|
|
3990
|
+
}
|
|
3991
|
+
})];
|
|
3992
|
+
}
|
|
3993
|
+
}())
|
|
3994
|
+
},
|
|
3995
|
+
types: collectedTypes
|
|
3996
|
+
};
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
function getQueriesForList(list) {
|
|
4000
|
+
if (!list.graphql.isEnabled.query) return {};
|
|
4001
|
+
const findOne$1 = g.field({
|
|
4002
|
+
type: list.graphql.types.output,
|
|
4003
|
+
args: {
|
|
4004
|
+
where: g.arg({
|
|
4005
|
+
type: g.nonNull(list.graphql.types.uniqueWhere),
|
|
4006
|
+
defaultValue: list.isSingleton ? {
|
|
4007
|
+
id: '1'
|
|
4008
|
+
} : undefined
|
|
4009
|
+
})
|
|
4010
|
+
},
|
|
4011
|
+
async resolve(_, args, context, info) {
|
|
4012
|
+
return await withSpan(`query ${info.fieldName}`, async () => {
|
|
4013
|
+
return findOne(args, list, context, info);
|
|
4014
|
+
}, {
|
|
4015
|
+
'nixxie.list': list.listKey
|
|
4016
|
+
});
|
|
4017
|
+
}
|
|
4018
|
+
});
|
|
4019
|
+
const findMany$1 = g.field({
|
|
4020
|
+
type: g.list(g.nonNull(list.graphql.types.output)),
|
|
4021
|
+
args: list.graphql.types.findManyArgs,
|
|
4022
|
+
async resolve(_, args, context, info) {
|
|
4023
|
+
return await withSpan(`query ${info.fieldName}`, async () => {
|
|
4024
|
+
return findMany(args, list, context, info);
|
|
4025
|
+
}, {
|
|
4026
|
+
'nixxie.list': list.listKey
|
|
4027
|
+
});
|
|
4028
|
+
}
|
|
4029
|
+
});
|
|
4030
|
+
const countQuery = g.field({
|
|
4031
|
+
type: g.Int,
|
|
4032
|
+
args: {
|
|
4033
|
+
where: g.arg({
|
|
4034
|
+
type: g.nonNull(list.graphql.types.where),
|
|
4035
|
+
defaultValue: list.isSingleton ? {
|
|
4036
|
+
id: {
|
|
4037
|
+
equals: '1'
|
|
4038
|
+
}
|
|
4039
|
+
} : {}
|
|
4040
|
+
})
|
|
4041
|
+
},
|
|
4042
|
+
async resolve(_, args, context, info) {
|
|
4043
|
+
return await withSpan(`query ${info.fieldName}`, async () => {
|
|
4044
|
+
return count(args, list, context, info);
|
|
4045
|
+
}, {
|
|
4046
|
+
'nixxie.list': list.listKey
|
|
4047
|
+
});
|
|
4048
|
+
}
|
|
4049
|
+
});
|
|
4050
|
+
return {
|
|
4051
|
+
[list.graphql.names.itemQueryName]: findOne$1,
|
|
4052
|
+
[list.graphql.names.listQueryName]: findMany$1,
|
|
4053
|
+
[list.graphql.names.listQueryCountName]: countQuery
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
4056
|
+
|
|
4057
|
+
function getGraphQLSchema(lists, extraFields, sudo) {
|
|
4058
|
+
const query = g.object()({
|
|
4059
|
+
name: 'Query',
|
|
4060
|
+
fields: Object.assign({}, ...Object.values(lists).map(list => getQueriesForList(list)), extraFields.query)
|
|
4061
|
+
});
|
|
4062
|
+
const collectedTypes = [];
|
|
4063
|
+
const mutation = g.object()({
|
|
4064
|
+
name: 'Mutation',
|
|
4065
|
+
fields: Object.assign({}, ...Object.values(lists).map(list => {
|
|
4066
|
+
const {
|
|
4067
|
+
mutations,
|
|
4068
|
+
types
|
|
4069
|
+
} = getMutationsForList(list);
|
|
4070
|
+
collectedTypes.push(...types);
|
|
4071
|
+
return mutations;
|
|
4072
|
+
}), extraFields.mutation)
|
|
4073
|
+
});
|
|
4074
|
+
return new GraphQLSchema({
|
|
4075
|
+
query,
|
|
4076
|
+
mutation,
|
|
4077
|
+
types: [...collectedTypes, g.JSON, mutation],
|
|
4078
|
+
extensions: {
|
|
4079
|
+
sudo
|
|
4080
|
+
}
|
|
4081
|
+
});
|
|
4082
|
+
}
|
|
4083
|
+
function createGraphQLSchema(config, lists, adminMeta, sudo) {
|
|
4084
|
+
var _config$graphql$exten, _config$graphql, _config$graphql$exten2;
|
|
4085
|
+
const graphQLSchema = getGraphQLSchema(lists, {
|
|
4086
|
+
mutation: {},
|
|
4087
|
+
query: adminMeta ? {
|
|
4088
|
+
nixxie: g.field({
|
|
4089
|
+
type: g.nonNull(NixxieMeta),
|
|
4090
|
+
resolve: () => ({
|
|
4091
|
+
adminMeta
|
|
4092
|
+
})
|
|
4093
|
+
})
|
|
4094
|
+
} : {}
|
|
4095
|
+
}, sudo);
|
|
4096
|
+
|
|
4097
|
+
// merge in the user defined graphQL API
|
|
4098
|
+
return (_config$graphql$exten = (_config$graphql = config.graphql) === null || _config$graphql === void 0 || (_config$graphql$exten2 = _config$graphql.extendGraphqlSchema) === null || _config$graphql$exten2 === void 0 ? void 0 : _config$graphql$exten2.call(_config$graphql, graphQLSchema)) !== null && _config$graphql$exten !== void 0 ? _config$graphql$exten : graphQLSchema;
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
// TODO: this cannot be changed for now, circular dependency with getSystemPaths, getEsbuildConfig
|
|
4102
|
+
function getBuiltNixxieConfigurationPath(cwd) {
|
|
4103
|
+
return path.join(cwd, '.nixxie/config.js');
|
|
4104
|
+
}
|
|
4105
|
+
function posixify(s) {
|
|
4106
|
+
return s.split(path.sep).join('/');
|
|
4107
|
+
}
|
|
4108
|
+
function getSystemPaths(cwd, config) {
|
|
4109
|
+
var _config$types, _config$db, _config$graphql;
|
|
4110
|
+
const prismaClientPath = config.db.prismaClientPath === '@prisma/client' ? null : config.db.prismaClientPath ? path.join(cwd, config.db.prismaClientPath) : null;
|
|
4111
|
+
const builtTypesPath = (_config$types = config.types) !== null && _config$types !== void 0 && _config$types.path ? path.join(cwd, config.types.path) // TODO: enforce initConfig before getSystemPaths
|
|
4112
|
+
: path.join(cwd, 'node_modules/.nixxie/types.ts');
|
|
4113
|
+
const builtPrismaPath = (_config$db = config.db) !== null && _config$db !== void 0 && _config$db.prismaSchemaPath ? path.join(cwd, config.db.prismaSchemaPath) // TODO: enforce initConfig before getSystemPaths
|
|
4114
|
+
: path.join(cwd, 'schema.prisma');
|
|
4115
|
+
const relativePrismaPath = prismaClientPath ? `./${posixify(path.relative(path.dirname(builtTypesPath), prismaClientPath))}` : '@prisma/client';
|
|
4116
|
+
const builtGraphqlPath = (_config$graphql = config.graphql) !== null && _config$graphql !== void 0 && _config$graphql.schemaPath ? path.join(cwd, config.graphql.schemaPath) // TODO: enforce initConfig before getSystemPaths
|
|
4117
|
+
: path.join(cwd, 'schema.graphql');
|
|
4118
|
+
return {
|
|
4119
|
+
config: getBuiltNixxieConfigurationPath(cwd),
|
|
4120
|
+
admin: path.join(cwd, '.nixxie/admin'),
|
|
4121
|
+
prisma: prismaClientPath !== null && prismaClientPath !== void 0 ? prismaClientPath : '@prisma/client',
|
|
4122
|
+
types: {
|
|
4123
|
+
relativePrismaPath
|
|
4124
|
+
},
|
|
4125
|
+
schema: {
|
|
4126
|
+
types: builtTypesPath,
|
|
4127
|
+
prisma: builtPrismaPath,
|
|
4128
|
+
graphql: builtGraphqlPath
|
|
4129
|
+
}
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
function getInternalGraphQLSchema(config) {
|
|
4133
|
+
// omit `graphql.omit`
|
|
4134
|
+
const withoutOmit = {
|
|
4135
|
+
...config,
|
|
4136
|
+
lists: Object.fromEntries(Object.entries(config.lists).map(([listKey, list]) => {
|
|
4137
|
+
return [listKey, {
|
|
4138
|
+
...list,
|
|
4139
|
+
graphql: {
|
|
4140
|
+
...(list.graphql || {}),
|
|
4141
|
+
omit: false
|
|
4142
|
+
},
|
|
4143
|
+
fields: Object.fromEntries(Object.entries(list.fields).map(([fieldKey, field]) => {
|
|
4144
|
+
if (fieldKey.startsWith('__group')) return [fieldKey, field];
|
|
4145
|
+
return [fieldKey, data => {
|
|
4146
|
+
const f = field(data);
|
|
4147
|
+
return {
|
|
4148
|
+
...f,
|
|
4149
|
+
graphql: {
|
|
4150
|
+
...(f.graphql || {}),
|
|
4151
|
+
omit: false
|
|
4152
|
+
},
|
|
4153
|
+
// WARNING: this bypasses access control checks for filtering and ordering on the internal schema
|
|
4154
|
+
isFilterable: true,
|
|
4155
|
+
// TODO: remove when moved to .access.filter and .omit.filter
|
|
4156
|
+
isOrderable: true // TODO: remove when moved to .access.filter and .omit.filter
|
|
4157
|
+
};
|
|
4158
|
+
}];
|
|
4159
|
+
}))
|
|
4160
|
+
}];
|
|
4161
|
+
}))
|
|
4162
|
+
};
|
|
4163
|
+
const lists = initialiseLists(withoutOmit);
|
|
4164
|
+
const adminMeta = createAdminMeta(withoutOmit, lists);
|
|
4165
|
+
return createGraphQLSchema(withoutOmit, lists, adminMeta, true);
|
|
4166
|
+
}
|
|
4167
|
+
function injectNewDefaults(prismaClient, lists) {
|
|
4168
|
+
for (const listKey in lists) {
|
|
4169
|
+
var _dbField$default;
|
|
4170
|
+
const list = lists[listKey];
|
|
4171
|
+
|
|
4172
|
+
// TODO: other fields might use 'random' too
|
|
4173
|
+
const {
|
|
4174
|
+
dbField
|
|
4175
|
+
} = list.fields.id;
|
|
4176
|
+
if ('default' in dbField && ((_dbField$default = dbField.default) === null || _dbField$default === void 0 ? void 0 : _dbField$default.kind) === 'random') {
|
|
4177
|
+
const {
|
|
4178
|
+
bytes,
|
|
4179
|
+
encoding
|
|
4180
|
+
} = dbField.default;
|
|
4181
|
+
prismaClient = prismaClient.$extends({
|
|
4182
|
+
query: {
|
|
4183
|
+
[list.prisma.listKey]: {
|
|
4184
|
+
async create({
|
|
4185
|
+
args,
|
|
4186
|
+
query
|
|
4187
|
+
}) {
|
|
4188
|
+
var _args$data$id;
|
|
4189
|
+
return query({
|
|
4190
|
+
...args,
|
|
4191
|
+
data: {
|
|
4192
|
+
...args.data,
|
|
4193
|
+
id: (_args$data$id = args.data.id) !== null && _args$data$id !== void 0 ? _args$data$id : randomBytes(bytes).toString(encoding)
|
|
4194
|
+
}
|
|
4195
|
+
});
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
});
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
return prismaClient;
|
|
4203
|
+
}
|
|
4204
|
+
function formatUrl(provider, url) {
|
|
4205
|
+
if (url.startsWith('file:')) {
|
|
4206
|
+
const parsed = new URL(url);
|
|
4207
|
+
if (provider === 'sqlite' && !parsed.searchParams.get('connection_limit')) {
|
|
4208
|
+
// https://github.com/prisma/prisma/issues/9562
|
|
4209
|
+
// https://github.com/prisma/prisma/issues/10403
|
|
4210
|
+
// https://github.com/prisma/prisma/issues/11789
|
|
4211
|
+
parsed.searchParams.set('connection_limit', '1');
|
|
4212
|
+
const [uri] = url.split('?');
|
|
4213
|
+
return `${uri}?${parsed.search}`;
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
return url;
|
|
4217
|
+
}
|
|
4218
|
+
function createSystem(config) {
|
|
4219
|
+
const lists = initialiseLists(config);
|
|
4220
|
+
const adminMeta = createAdminMeta(config, lists);
|
|
4221
|
+
const graphQLSchemas = {
|
|
4222
|
+
public: createGraphQLSchema(config, lists, adminMeta, false),
|
|
4223
|
+
internal: getInternalGraphQLSchema(config)
|
|
4224
|
+
};
|
|
4225
|
+
return {
|
|
4226
|
+
config,
|
|
4227
|
+
graphql: {
|
|
4228
|
+
schemas: graphQLSchemas
|
|
4229
|
+
},
|
|
4230
|
+
adminMeta,
|
|
4231
|
+
lists,
|
|
4232
|
+
getPaths: cwd => getSystemPaths(cwd, config),
|
|
4233
|
+
getNixxie: PM => {
|
|
4234
|
+
const prePrismaClient = new PM.PrismaClient({
|
|
4235
|
+
datasourceUrl: formatUrl(config.db.provider, config.db.url),
|
|
4236
|
+
log: config.db.enableLogging
|
|
4237
|
+
});
|
|
4238
|
+
const prismaClient = config.db.extendPrismaClient(injectNewDefaults(prePrismaClient, lists));
|
|
4239
|
+
const context = createContext({
|
|
4240
|
+
config,
|
|
4241
|
+
lists,
|
|
4242
|
+
graphQLSchemas,
|
|
4243
|
+
prismaClient,
|
|
4244
|
+
prismaTypes: {
|
|
4245
|
+
DbNull: PM.Prisma.DbNull,
|
|
4246
|
+
JsonNull: PM.Prisma.JsonNull
|
|
4247
|
+
}
|
|
4248
|
+
});
|
|
4249
|
+
return {
|
|
4250
|
+
// TODO: replace with server.onStart, remove in breaking change
|
|
4251
|
+
async connect() {
|
|
4252
|
+
var _config$db$onConnect, _config$db2;
|
|
4253
|
+
await prismaClient.$connect();
|
|
4254
|
+
await ((_config$db$onConnect = (_config$db2 = config.db).onConnect) === null || _config$db$onConnect === void 0 ? void 0 : _config$db$onConnect.call(_config$db2, context));
|
|
4255
|
+
},
|
|
4256
|
+
// TODO: only used by tests, remove in breaking change
|
|
4257
|
+
async disconnect() {
|
|
4258
|
+
await prismaClient.$disconnect();
|
|
4259
|
+
},
|
|
4260
|
+
context
|
|
4261
|
+
};
|
|
4262
|
+
}
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
function getContext(config, PrismaModule) {
|
|
4266
|
+
const system = createSystem(config);
|
|
4267
|
+
const {
|
|
4268
|
+
context
|
|
4269
|
+
} = system.getNixxie(PrismaModule);
|
|
4270
|
+
return context;
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
export { getBuiltNixxieConfigurationPath as a, createSystem as c, getContext as g, withSpan as w };
|