Git Product home page Git Product logo

ra-data-prisma's Introduction

ra-data-prisma

Packages to connect react-admin 🧩 with prisma version 2 🌈

  • dataprovider: the dataprovider for the frontend
  • backend: tools to help making a nexus-prisma backend compatible with the data-provider

Usage

you need to add the dataprovider to your react-admin app. Your backend needs additional resolver for all the resoures you gonna need. backend package will help you with making your backend compatible with the dataprovider!

See the readmes above for further information.

Develop

call yarn install to set it up.

yarn test to run unit tests.

Some tests use an actual introspection result from a nexus-prisma backend. If you want to extend the underlying model do:

  • edit datamodel.prisma to alter the underlying prisma model
  • edit testSchemaNexus.ts to modify the nexus types
  • call yarn install in the root to update all types and the test introspection schema

Prior work

loosly based on https://github.com/Weakky/ra-data-opencrud, thanks @Weakky

ra-data-prisma's People

Contributors

claudiocro avatar darcien avatar davidmwhynot avatar dependabot[bot] avatar hajnalben avatar izziaraffaele avatar jaymaycry avatar khanhpv0305 avatar knapeto avatar lubosmato avatar macrozone avatar matcic avatar mwillbanks avatar smtex avatar voytechg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ra-data-prisma's Issues

TypeError: graphQLDataProvider is not a function

I'm trying to use the latest version of @ra-data-prisma/dataprovider with a typegraphql backend. (crud generated from a prisma schema)

My component looks like this:

import React from "react"
import { Admin, Resource, ListGuesser } from "react-admin"
import { useDataProvider } from "@ra-data-prisma/dataprovider"

const ReactAdmin = () => {
  const dataProvider = useDataProvider({
    clientOptions: { uri: "/api/graphql" },
    queryDialect: "typegraphql",
  })

  if (!dataProvider) {
    return <div>Loading...</div>
  }

  return (
    <Admin dataProvider={dataProvider}>
      <Resource name="Contractor" list={ListGuesser} />
    </Admin>
  )
}

export default ReactAdmin

When I try to open it in the browser, I'm getting the following error in the console:

TypeError: graphQLDataProvider is not a function
    at eval (buildDataProvider.js?6d27:62)
    at Proxy.eval (convertLegacyDataProvider.js?0029:38)
    at performPessimisticQuery (performPessimisticQuery.js?924a:37)
    at doQuery (doQuery.js?0197:59)
    at Proxy.eval (useDataProvider.js?e59e:188)
    at eval (useQueryWithStore.js?897f:196)
    at new Promise (<anonymous>)
    at eval (useQueryWithStore.js?897f:195)
    at commitHookEffectListMount (react-dom.development.js?61bb:22857)
    at commitPassiveMountOnFiber (react-dom.development.js?61bb:24569)
    at commitPassiveMountEffects_complete (react-dom.development.js?61bb:24533)
    at commitPassiveMountEffects_begin (react-dom.development.js?61bb:24520)
    at commitPassiveMountEffects (react-dom.development.js?61bb:24508)
    at flushPassiveEffectsImpl (react-dom.development.js?61bb:26597)
    at flushPassiveEffects (react-dom.development.js?61bb:26550)
    at eval (react-dom.development.js?61bb:26360)
    at workLoop (scheduler.development.js?1911:256)
    at flushWork (scheduler.development.js?1911:229)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js?1911:523)

I get the same error with and without TS in a brand new CRA app.

I also tried to roll back to the previous version with no luck. :(

Do you guys have any idea what could be the problem?

how to specify Resources with typegraphql

I am using the beta useDataProvider

  const dataProvider = useDataProvider({
    clientOptions: { uri: "localhost:4000/graphql" },
    queryDialect: "typegraphql"
  })

How would I get the vars like

import { UserList, UserEdit, UserCreate } from "./resources/user

using this method?

This?

<Resource name="Customer" list={ListGuesser} />

How to build custom query?

hi buddy, I want to build a custom query for a specify resource? I tried for days but couldn't find a solution……

Could you please give me some direction?

Thank you very much!

const AdminApp = () => {
  const dataProvider = useDataProvider({
    client: apolloClient,
    aliasPrefix: "", 
    filters: {}, // custom filters
    queryDialect: "nexus-prisma", // customize query dialect, defaults to nexus-prisma
  });

  if (!dataProvider) {
    return <Loading />;
  }

  return (
    <Admin dataProvider={dataProvider} authProvider={authProvider}>
      <Resource name="Product" {...product} />
      <Resource name="Customer" {...customer} />
      <Resource name="Order" {...order} />
      <Resource name="Activation" {...activation} />
      <Resource name="ActivationWithCustomerProduct" {...activationWithCustomerProduct} />
    </Admin>
  );
};

How To Use connectOrCreate In ReferenceInput ?

after using ra-data-prisma , saved me a lot of time! thanks a lot!

what I expected

I have a one to many model(eg: customers - orders), when I want to create a record in the orders table , the logic is : " if the customerId is exists, then connect , else create "

I tried this , but failed

const OrderCreate = (props) => (
 <Create {...props}>
   <SimpleForm>
     <ReferenceInput label="Product Name" source="product" reference="Product">
       <SelectInput optionText="name" />
     </ReferenceInput>
     <ReferenceInput source="customer.connectOrCreate" reference="Customer" label="Email" filterToQuery={(searchText) => ({ email: searchText })}>
       <AutocompleteInput optionText="email" />
     </ReferenceInput>
     <NumberInput source="permitUsers" label="permitUsers" initialValue={3} />
     <DateInput source="orderDate" label="orderDate" initialValue={new Date()} />
   </SimpleForm>
 </Create>
);

the browser request payload:

image-20210820202851233

my backend api service connectOrCreate can work

image-20210820201745011

customize or extend resolvers from addCrudResolvers

Is there a way to customize or extend the resolvers created by addCrudResolvers?

The use case I'm thinking of for this is to automatically generate slugs for e.g. a blog post model. The slug is a required string field in the schema, but if it is not provided it could be autogenerated from the post title.

The Nexus prisma plugin provides the resolve arg on t.crud and t.model which allows for customizing the resolver, but addCrudResolvers just calls t.crud without passing any arguments.

I realize I could just skip using addCrudResolvers for models where I want to have this level of control, but I just wanted to see if this was a customization that had been considered.

Thank you!

Adding headers

Isn't it possible to add headers (e.g., authorization) at this point?

I found a similar issue here in the related project but it seems the workaround is not available here.

Extra `{id: ...}` in filter queries?

{
  "operationName": "actors",
  "variables": {
    "skip": 0,
    "take": 10,
    "orderBy": { "id": "asc" },
    "where": { "AND": [{}, { "publish": { "id": { "equals": true } } }] }
  },
  "query": "query actors($where: ActorWhereInput, $orderBy: ActorOrderByInput, $take: Int, $skip: Int) {\n  items: actors(where: $where, orderBy: $orderBy, take: $take, skip: $skip) {\n    id\n    firstName\n    lastName\n    picture\n    text\n    projects {\n      id\n      __typename\n    }\n    publish\n    __typename\n  }\n  total: actorsCount(where: $where)\n}\n"
}

this is the query sent by some filter set that looks like:

const ActorFilter = (props) => (
  <Filter {...props}>
    <SearchInput source="q" alwaysOn />
    <BooleanInput source="publish" />
  </Filter>
);

I'm getting a graph ql error when using the "publish" filter. I think according to the generated CRUD in the backend, it should be something like:

"where": { "AND": [{}, { "publish": { "equals": true } }] }

Find a different way to define if an input is a relation when building variabled

In my application, I do not allow nested writes for certain resources so I redefined the input type created by prisma removing all other modifiers except the connect modifier but this seems to break the dataprovider.

Also considering this feature (which is currently still in a definition process) I believe we should find a better way to identify a nested resource while creating and updating a resource.

So instead of check the existence of create + connect modifiers here we could check if the data contains only modifier fields and nothing else.

Using composite primary keys on typegraphql

Hi there, following on from #97, I'm still having some difficulties. It seems like entities that have a to-many relationship with entities with composite primary keys aren't being queried correctly. For example, for this schema:

model Membership {
  user    User    @relation(fields: [userId], references: [id])
  userId  String
  org     Org     @relation(fields: [orgId], references: [id])
  orgId   String
  enabled Boolean @default(true)

  @@id([userId, orgId])
}
model User {
  id             String   @id @default(uuid())
  memberships Membership[]
  // ...
}
model Org {
  id              String @id @default(uuid())
  memberships  Membership[]
  // ...
}

Loading the Memberships page works fine, but loading Users results in the following error:

{
  "errors": [
    {
      "message": "Cannot query field \"id\" on type \"Membership\".",
      "locations": [
        {
          "line": 29,
          "column": 7
        }
      ]
    }
  ]
}

Again, thanks so much for your hard work and expertise.

`pluralize("audio") === "audio"`

Sometimes the plural of a word equals its singular. For instance I had a table "audio" and pluralize.js generates "audio" as plural. Which is I think correct (for the curious, compare "video").

Anyways, it that was a hard to spot bug for me and I think there should be some mechanism to avoid this.

ResourceViews and normalisation

ResourceViews allow to specify fragments to fetch only the data that you really need.

It also allow to fetch nested data, which might be useful in exports or lists.

The Problem is now that when defining Fragments, relations are not normalized which can be annoying in some cases. Let me explain:

Consider a Team with its Members. In the Team admin resource, you would like to have a ReferenceArrayInput where you can select the team members.

You can use this: <ReferenceArrayInput resource="User" source="members" />

React admin requires an array of strings (the ids) here as the value for the field. But the query sent to the backend looks like this:

user(...) {
  id
  members {
    id
  }
}

So one object fetched by this looks like this:

{
  id: "some-id",
  members: [ { id: "member-id-1"}, {id: "member-id-2"} ]
}

without any normalisation, this would not work with the input above as it expects an array of strings and not an array of objects

because we know that members is of type User and User has defined as a "resource" in react-admin, we "normalize" it, so that it will become an array of strings (basically it does members.map(m => m.id)

so what's the problem?

problem is now that we deliberately disabled this normalisation if you defined a ResourceView, because you might actually want to fetch the whole record as-is. That is a conflict.

Solutions

  • always normalize, even if you defined resourceViews (makes them less useful for certain cases). This is a BREAKING CHANGE
  • never normalize, but add a normalized additional property (this was done in the old version of the dataprovider for prisma1). E.g. members would stay as-is, but we would additionaly add members_ids (in case of array) or member_id. This is BREAKING CHANGE, but would be most simple and flexible. To mitigate the break, we could only do this when defined a resource view (but that would be inconsistent). To migrate, users would have to alter their ReferenceArrayInput to use members_ids instead of members
  • Always normalize IF only id is fetched from a resource. That looks like the only non-breaking change! but maybe its also a bit "magic" and inconsistent
  • ask react-admin team if they would support array of objects with id property out-of-the-box
  • other approaches?

Dataprovider does not support newest [email protected]

The new version of nexus-plugin-prisma comes with a few changes that break the dataprovider.

Mainly I'm experiencing issues with Int and Float update input which have been changed from a simple scalar field to a custom input type but also the changes to the ordering functionalities might break the dataprovider.

Idea: rework resource dependent options

options grew organically and currenlty contain (among others):

  • ResourceViews, which was initially to create "virtual" resource, but can now be used to customize fragment for one and many queries
  • customizeInputData, can be used to alter input data before beeing sent to the backend
  • filters, can be used to create custom filters. They are currently global, and not dependent on resources, which is odd

all those options kindof are related to a specific resource, so we could consider to rework those into something like this:


type Options = {

  resources: ResourceOptions

...

}


type ResourceOptions = Record<string, ResourceOption> // whereas key is the resourceName

type ResourceOption = {
   backendResource?: string // defaults to the key. This can be altered for "virtual" resources
  fragments: { // to alter what data is fetched, 
     one: ...,
     many: ... 
  },
  customizeInputData: {
     create: ...,
     update: ...
  },
filters: ...
}

so basically group the options. That will make it a bit easier to think about further improvements and customizations and is more logical

no typings on customize

i could not figure out how to get proper types on customize functions, that would be very cool to have

sort order

it return sort order must be object how do I fix this

query need to be

  "orderBy": [
    {
      "createdAt": {
        "sort": "desc"
      }
    }
  ],

instead of

  "orderBy": [
    {
      "createdAt": "desc"
    }
  ],

how do I customize this :(

How to handle file uploads?

The generated CRUD (by addCrudResolvers) assumes that there's a mapping from the input to the output types. But with a file upload, this pattern is broken as far as I can see. The input type will be some Upload scalar and the output type some custom File type.

Or do I miss something here?

I was trying to implement some file upload following this example.

ReferenceInput with @ra-data-prisma/dataprovider 6.3.2 not working

my dependencies

  "dependencies": {
    "@apollo/client": "^3.4.7",
    "@ra-data-prisma/dataprovider": "^6.3.2",
    "graphql": "^15.5.1",
    "react": "^17.0.2",
    "react-admin": "^3.17.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3"}

when i make a file called orderCreate.js, part of code is :

  <Create {...props}>
    <SimpleForm>

      <ReferenceInput label="Product" source="productId" reference="Product">
          <SelectInput optionText="name" />
      </ReferenceInput>

      <ReferenceInput  source="customerId" reference="Customer" filterToQuery={(searchText) => ({ email: searchText })}>
          <AutocompleteInput optionText="email" />
      </ReferenceInput>

      <NumberInput source="permitUsers" label="permitUsers" initialValue={3} />

      <DateInput source="orderDate" label="orderDate" initialValue={new Date()}/>
    </SimpleForm>
  </Create>

i checked the browser , the request body content is:

{"operationName":"createOneOrder",
"variables":{"data":{"orderDate":"2021-08-20T00:00:00.000Z","permitUsers":3}},
"query":"mutation createOneOrder($data: OrderCreateInput!) {\n  
data: createOneOrder(data: $data) {\n    id\n    customerId\n    productId\n    orderDate\n    permitUsers\n    product {\n      id\n      __typename\n    }\n    customer {\n      id\n      __typename\n    }\n    __typename\n  }\n}\n"}

all the other input components are fine, but ReferenceInput variables lost !

and the request failed!

image-20210820141959488

only seperated backend api service is fine

  "dependencies": {
    "@prisma/client": "^2.29.0",
    "@ra-data-prisma/backend": "^7.0.0",
    "apollo-server": "^3.1.2",
    "apollo-server-core": "^3.1.2",
    "bcryptjs": "^2.4.3",
    "graphql": "^15.5.1",
    "graphql-middleware": "^6.0.10",
    "graphql-scalars": "^1.10.0",
    "graphql-shield": "^7.5.0",
    "jsonwebtoken": "^8.5.1",
    "nexus": "^1.1.0",
    "nexus-plugin-prisma": "^0.35.0"
  }

in the playground test graphql mutation ( success ):

image-20210820141019548
image-20210820141222196

Batching requests?

I suppose this is more of a discussion thread instead of request for change or issue.

We're quite happily using this library in our project (somewhat heavily using the "virtual" resources provided with fragments) and things work pretty well. However, more and more I've been seeing the fact that React Admin with this data provider uses the GraphQL endpoint more like a REST API endpoint, possibly bombarding the endpoint way more than it should have (if it was utilizing the language properly).

For example, imagine a list with 5 different <Filter> components that are alwaysOn, fetching values via <ReferenceInput>, maybe even the list has some ReferenceFields etc. (though this can be solved via the virtual resources). Now every time you open the list, you've got at least 6 individual GQL requests, going to the server at the same time, each asking for one resource.

I wonder, do you think it would be possible to figure out a mechanism that would maybe group requests that happen within let's say 100ms within the first, creating a query maybe like

query BatchQuery ($where1: Resource1WhereInput!, $skip1: Int!, $take1: Int!, $where2: Resource2WhereInput!, ....) {
  request1: resource1GetList($where1, $skip1, $take1) {
    ...
  },
  request1Total: ....,
  request2: resource2GetList($where2, ...) {
    ...
  },
  request2Total: ...
}

After receiving this response, we would parse and return the individual results, possibly not even having to change anything in the frontend (all it would notice is that the first few requests could be slightly slower).

I'd imagine it would have to happen on both sides of the provider, and I'm not sure if we can construct promises that would work this way, so I'm just asking what you think of this?

Incorrect return type on `useDataProvider`

If I'm not mistaken, buildDataProvider returns the old version/interface of data provider - function (type, resource, params) => Promise<any> (https://github.com/panter/ra-data-prisma/blob/master/packages/dataprovider/src/buildDataProvider.ts#L36), which corresponds to React Admin's LegacyDataProvider (https://github.com/marmelab/react-admin/blob/master/packages/ra-core/src/types.ts#L303)

However, the return type of useDataProvider says DataProvider which has a different signature and cannot be casted (useDataProvider() as LegacyDataProvider).

Workaround is something like (useDataProvider() as unknown) as LegacyDataProvider which isn't very nice.

connect in update mutation

<ReferenceInput label="Shop" source="shopId" reference="Shop">
    <SelectInput optionText="name" />
</ReferenceInput>

ReferenceInput is not automatically converted to 'connect' format. If source="shop.connect.id" is used, it works functionally, but the existing shopId is not recognized in the edit screen.

Is there a solution to this?

better case insensitive search

newest prisma supports "native" case insensitive search. Would be nice if we could use that if its avialable (can be checked through introspection), instead of the "poor mans" version that is currently in place

TypeError: Int cannot represent non-integer value:

What you were expecting:

Retrieve a post for editing after configuring ra-data-prisma ( addCrudResolvers('Post') ...)

What happened instead:

Instead, I keep getting a 400 Bad Request because it sends the id as a String instead of as an Integer
{"errors":[{"message":"Variable \"$where\" got invalid value \"32\" at \"where.id\"; Expected type Int. Int cannot represent non-integer value: \"32\"","locations":[{"line":1,"column":12}]}]}

This is the request payload

operationName: "post"
query: "query post($where: PostWhereUniqueInput!) {
  data: post(where: $where) {
     id
     published 
     title
     content
    __typename
 }
}"
variables: {
 where: {
   id: "32"
}}
 

Steps to reproduce:

Just try to edit any resource in react-admin (user, post ...) where it needs to send a graphql query by id to prisma.

Environment

React-admin version: 3.6

linting and prettier config wrong

it seems that the prettier and linting config are not properly setup. I think we should run lint --fix on master and adjust some rules

[Future] Rewrite the backend to new Nexus Prisma plugin

This is a future issue

Yesterday I stumbled upon graphql-nexus/nexus-plugin-prisma#1039 . TL;DR of this is that nexus-plugin-prisma is no longer continued nor supported and there is ongoing project for rewriting the plugin to make it more maintainable (AFAIK on https://github.com/prisma/nexus-prisma/ )

It will probably take a while before things are completely unusable, but after this is done, the backend will need to change somehow accordingly.

Just wanted to have this somewhat documented when its time comes.

Allow fragment spread in resource views

Currently, we can specify arbitrary selection on a given resource, if we write it as a fragment on that given resource. Fields selected in this fragment are then used to build the query that is sent to the server.

The goal is to take

fragment X on Y {
  field
  anotherField
}

and produce a query

query Ys($where: YWhereInput $orderBy: [YOrderByInput!] $take: Int $skip: Int) {
  items: Ys(where: $where orderBy: $orderBy take: $take skip: $skip) {
    field
    anotherField
  }
  total: YsCount(where: $where)
}

This works well. I personally had a situation where I wanted to extract fields that are common in one and many fragments so I don't forget anything, like this:

const common = `
  id
  field
`
const one = gql`
  fragment Xone on Y {
    ${common}
    anotherField
  }
`
const many = gql`
  fragment Xmany on Y {
    ${common}
  }
`

This also works well, and allowed me to deconstruct the fragments into logical parts.

But then I ran into a problem. I wanted to have the types of the queries generated. In our case we use @graphql-codegen library which can scan files for export const something = gql.... objects and parses them and generates static types for them. The problem is, it needs to have everything available on compile time, so it can't process the previous example (explanation here). On the other hand, codegen can process GraphQL fragments, so if we were to rewrite the example with that, it would work:

const common = gql`
  fragment Xcommon on Y {
    id
    field
  }
`
const one = gql`
  fragment Xone on Y {
    ...Xcommon
    anotherField
  }
  ${common}
`
const many = gql`
  fragment Xmany on Y {
    ...Xcommon
  }
  ${common}
`

But then if we want to use one and many in our resource views, we run into a problem with the way we process the fragment. This is because one contains in this case

fragment Xone on Y {
  ...Xcommon
  anotherField
}
fragment Xcommon on Y {
  id
  field
}

which in code is a DocumentNode but with 2 definitions, and ra-data-prisma uses the first one, which would result in a spread of unknown fragment. AFAIK there's no way to combine the two approaches without duplication e.g.

At first I thought we could try to do the fragment "interpolation" manually (after all, the document is a JS object) but then again, we could miss something if there were many fragments combined. On a second thought though, we are in control of the outgoing query to the server, and if we were to supply all the used fragments outside of the query, it produces a valid GQL operation:

fragment X on Y {
  field
  anotherField
}
query Ys($where: YWhereInput $orderBy: [YOrderByInput!] $take: Int $skip: Int) {
  items: Ys(where: $where orderBy: $orderBy take: $take skip: $skip) {
    ...X
  }
  total: YsCount(where: $where)
}

This would keep the functionality intact if I'm not missing something, and allows us to freely use GQL fragments and in my case, the @graphql-codegen library.


Footnote: Not using fragments and directly specifying every field from the beginning works for both as well, but I think being able to use fragments would be nicer and more flexible.

FR: allow to specify different fragments for list and detail view

with the option resourceViews you can specify a custom fragment that will be used to fetch records. But it will be used for both list and detail view. it would be nice if you could specify a different fragment for detail and list view.

Proposal:

the fragment option for resource view could either be one fragment or an object with

{
   one: gql`... `
   many: gql`... `
}

i would use one and many because it aligns with the internal fetch types of react admin

Support custom input type for Json field

Defining a prisma model like the one below

model User {
  id               String  @default(uuid()) @id
  firstName String?
  lastName  String?
  address    Json?
}

And a nexus schema like below:

const User = objectType({
    name: "User",
    definition(t) {
      t.model.id();
      t.model.firstName();
      t.model.lastName();
      t.model.address({ type: "Address" });
    },
  });

  const Address = objectType({
    name: "Address",
    definition(t) {
      t.string("street");
      t.string("city");
      t.string("countryCode");
    },
  });

  const AddressInput = inputObjectType({
    name: "AddressInput",
    definition(t) {
      t.string("street");
      t.string("city");
      t.string("countryCode");
    },
  });

  // extend Prisma input type to use AddressInput
  const UserCreateInput = extendInputType({
    type: "UserCreateInput",
    definition(t) {
      t.field("address", { type: "AddressInput" });
    },
  });

  const UserUpdateInput = extendInputType({
    type: "UserUpdateInput",
    definition(t) {
      t.field("address", { type: "AddressInput" });
    },
  });

The request generated by the dataprovider for create/update does not include the address

Not compatible with nexus-prisma 0.15.0

I updated from nexus-prisma 0.14.0 to 0.15.0 and started to get the following error messages:

- Missing type UserWhereInput, did you forget to import a type to the root query?
- Missing type UserOrderByInput, did you forget to import a type to the root query?
- Missing type UserWhereUniqueInput, did you forget to import a type to the root query or mean PaymentWhereUniqueInput, SubmissionWhereUniqueInput?
....

If i remove addCrudResolvers methods schema generates properly

Incorrect query field with typegraphql

Hi there, I've been trying to get react-admin up and running with prisma and not having the greatest luck. After spending some time in dep hell trying to get nexus working, I switched to typegraphql and typegraphql-prisma. I had a lot more success with that, since react-admin starts now but it can't fetch any data, resulting in errors like these:

    {
      "message": "Cannot query field \"count\" on type \"AggregateActivity\". Did you mean \"_count\"?",
      "locations": [
        {
          "line": 25,
          "column": 5
        }
      ]
    }

I tried changing buildGqlQuery.js:218 to gqlTypes.field(gqlTypes.name("_count") from gqlTypes.field(gqlTypes.name("count"), but that hasn't stopped it. Is there some configuration that I'm missing or something? I'm quite new to react-admin and graphql, so it definitely wouldn't shock me if I was. Thanks so much for y'all's assistance and hard work on this valuable project.

How to use with explicit many-to-many models (error in Edit view due to Input)

My schema has a few models that are related via many-to-many relations. I'm using the explicit form of the relation in my prisma schema by defining the intermediate model exactly as described in the prisma docs.

As requested in the docs for ra-data-prisma, I'm calling addCrudResolvers on all 3 models (both sides of the relation and the intermediate model).

On the frontend, I'm also defining resources for all 3 models. My issues start when trying to build out the Edit page for the intermediate model. The List view works fine, but when trying to show the Edit view I'm getting a graphql error that says Error: Variable "$where" got invalid value "MODEL_ID" at "where.id"; Expected type StringFilter to be an object. This happens with both the EditGuesser and when trying to define a basic SimpleForm with only a single TextField for the id. (MODEL_ID actually shows up as the string id of the instance it's trying to fetch).

It seems that the Input type expected in the Edit view for the intermediate model is different from the Input type expected by other Edit views, including those for my one-to-many relations. The intermediate model is looking for a ${typeName}WhereInput, whereas the other models are looking for a ${typeName}WhereUniqueInput. This is causing the error since the dataProvider is passing just the id for both Inputs, but ${typeName}WhereInput seems to want a StringFilter.

Sorry for the long explanation. I'm not even sure this is the right package to be creating the issue for. If the explanation isn't clear, I'd be happy to try to create a minimal test repo that demonstrates the issue.

Thank you again for your help.

Handling noncount nouns / no plural forms

When using typegraphql (but also would likely be an issue when nexus), when using noncount nouns or a resource that does not have a plural form (i.e. equipment) the queries for GET_LIST and GET_ONE will be the same thus causing a conflict.

typegraphql handles this by exporting these differently instead of having a singular equipment which would be duplicated, it names the queries differently:

findManyEquipment
findUniqueEquipment

In this case, it would be somewhat easy to change the underlying query logic that is inside of the makeIntrospectionOptions to handle this based on the query dialect for now (which already exists). However, since other methods might exist it might be better to be able to pass in the query resolver name through the useDataProvider options.

As an example:

useDataProvider({
  clientOptions: { uri: "/graphql" },
  resourceViews: {
    Equipment: {
      resource: "Equipment",
      operationNames: {
        one: 'findUniqueEquipment',
        many: 'findManyEquipment',
      }
    }
  }
});

proper count

since prisma now supports count args, we can now send the filters to the count

(currently, the count is unfiltere and therefor too big)

delete or disconnect related records

if you have model A has many B and use the current (nexus)-crud api, there are two ways to remove an item B from A: by either disconnect it or delete it.

disconnecting it only works if any B can live on its own, wheras deleting them is correct if B is part of A and cannot live on its own.

at least in german, we call the case where B can live without A, an "aggregation" relation ship, whereas when B cannot live without A, its a "composition".

the generated crud api from nexus-prisma exposes both ways, even if disconnecting does not work, as it would leave items B as orphans and that could be prevented by restrictions in the schema.

our dataprovider always default to disconnect if that is available and uses delete if there is no disconnect on the introspection.

Now if you have the situation that disconnect does not work, its a bit annoying to deal with this. Here are some things you can do in this case:

  • try to remove disconnect from the update input types on the backend. This is described by @hajnalben in #79 and he also added some methods to do so for the tests, but its a bit awkard and requires internals of nexus-plugin-prisma
  • other backends might have better control over that, i am not sure. Nexus-plugin-prisma is anyway deprecated. If you create the backend api more manually, you can make a more concious decision here and not include disconnect

still it could be that both disconnect and delete could be correct and it depends on the usecase. So handling it on the client might be better:

  • you can use customizeInputData to replace disconnect with delete. A very dirty and brute force (but working) way is this:

 customizeInputData: {
      MyResourceA: {
        update: (data, params) => {
          return renameDeep(data, (key) =>
            key === "disconnect" ? "delete" : key,
          )
        },
      },
    },

  • we could think about how to do it more fine tuned. E.g. we could try to add customization on how relations are handled. E.g. as described here #128 we could reorganize the options to be more centered around resources and then do something like:
resources: {

   MyResourceA: {
    // other options like fragments...

   relations: {
      MyResourceB: {
       type: "composition" // something that describes that B cannot live without A and should be deleted. It would default to "aggregation" if not specified, which means to disconnect
     } 
   }
   }

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.