hasura / graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
https://hasura.io
Apache License 2.0
31.08k stars 2.77k forks source link

docs: document `table_by_pk` query #2047

Closed corysimmons closed 2 years ago

corysimmons commented 5 years ago

Instead of query { person(where: ... ) { id } } returning an array of person, it would be nice if it returned a single object.

This pattern of duplicating interactions for both plural (arrays) and singular (objects) results can be applied to mutations as well as queries.

Example:

// before
{
  users(where: {
    id: {
      _eq: 123
    }
  }) {
    id
  }
} // returns an array of users even if I just want one... this makes destructuring and working with these values messy

// after
{
  user (where: {
    id: {
      _eq: 123
    }
  }) {
    id
  }
} // returns a single user object

// OR

{
  users (where: {
    id: {
      _eq: 123
    }
  }) {
    id
  }
} // returns an array of users that might match that query

// before
mutation AddUser ($objects: [users_insert_input!]!) { // I only want to insert a single user but I have to submit the mutation as an array.
  insert_users(objects: $objects) {
    returning {
      id
    }
  }
}

// after
mutation AddUser ($object: user_insert_input!) { // only inserting a single user; returning a single object
  insert_user(object: $object) {
    returning {
      id
    }
  }
}

// OR

mutation AddUsers ($objects: [users_insert_input!]!) { // Sometimes I will want to add multiple users, so keep the existing queries/mutations available.
  insert_users(objects: $objects) {
    returning {
      id
    }
  }
}

GraphCMS does this and it's a really nice user experience. In contrast, this is really one of the few things I find actually hinders my productivity and ability to read the code with Hasura.

revskill10 commented 5 years ago

@corysimmons I think, adding an argument like {singular: true} (default is false) for query is enough ? For mutation, i don't think it's nessessary. Because it would requires code modification on client side. And you can always return a query as mutation response.

My 2c.

corysimmons commented 5 years ago

I don't think it requires clientside anything and wouldn't be a breaking change?

users_insert_input gets turned into

Adding { singular: true } to everything would be better than nothing, but isn't quite as elegant as just using singular named queries/mutations.

corepay commented 5 years ago

@corysimmons running into similar issue now and yes returning an object on a query would be nice so I can reuse components without restructuring. Question though (i am still new at all this..) is my table names are singular now - - - so my single object query (for example form(where:... returning an array (causing me grief) are singular form now and not forms

{
query fetchForm($id: String!) {
  form(where: {id: {_eq: $id}}) {
    id
   ...
  }
}

Are you suggesting that I should be able to use forms(where:... and Hasura will recognize this is an array request but will remap the current singular table query form(where:... as an object response?

corysimmons commented 5 years ago

Yeah, I suppose Hasura would have to have to enforce your model being singular in the db, and then Hasura would just intelligently provide queryable/mutatable plurals and singulars.

fwiw, currently I'm going against my gut and naming db models plural just so the querying/mutating doesn't feel so off...

I suppose singular naming convention is easier to enforce in things like GraphCMS/DatoCMS since they're GUI heavy, but it could definitely still be done in Hasura.

OLDIN commented 5 years ago

When will support for a single query be implemented?

coco98 commented 5 years ago

@OLDIN There's already a table_by_pk style query root that you should see. We're going to make it easier to rename that to a better form.

revskill10 commented 5 years ago

@coco98 I see Hasura understands unique key constraints, so is it possible to autogenerate table_by_unique_key_constraint which return singular response also ?

corepay commented 5 years ago

afaik - response is an array even for single object fetch. I just extract the index[0] and assign to an object when received, problem solved. example. var item = this.items[0]

On Jun 20, 2019, at 10:20 AM, Truong Hoang Dung notifications@github.com wrote:

@coco98 https://github.com/coco98 I see Hasura understands unique key constraints, so is it possible to autogenerate table_by_unique_key_constraint which return singular response also ?

ā€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hasura/graphql-engine/issues/2047?email_source=notifications&email_token=ALVZFG3GVDBWZCKNU3WBTDLP3OG2XA5CNFSM4HHQSC72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYFRYZI#issuecomment-504044645, or mute the thread https://github.com/notifications/unsubscribe-auth/ALVZFG7LNUQTSRAH5ZTKLFTP3OG2XANCNFSM4HHQSC7Q.

corysimmons commented 5 years ago

@corepay Yes. I know how to do that. It's annoying and unintuitive vs stuff like Prisma/GraphCMS where there is a standard that you name a model singular, then Prisma generates both singular and plural resolvers so you can query for either:

{
  user(id: "abc") {
    first_name
  }
}
// const { first_name } = user

{
  users {
    first_name
  }
}
// users.map(u => u.first_name)

It's a QoL thing.

Hasura is more powerful/flexible/better than Prisma. This is the one thing I've noticed from extensively working with both that Prisma does much better than Hasura.

OLDIN commented 5 years ago

@coco98 I know about searching by primary key, but what about searching through other columns for a single query?

bkstorm commented 5 years ago

@coco98 I know about searching by primary key, but what about searching through other columns for a single query?

yeah, for example, email is unique in user table, so I want to search by email and return only a single row.

lostb1t commented 5 years ago

Would love to see this feature.

Use case: This would allow for returning a single user object from the auth context more cleanly.

lostb1t commented 5 years ago

This seems like a duplicate of https://github.com/hasura/graphql-engine/issues/1910

marionschleifer commented 5 years ago

Singular and plural resolvers are already available for querying. I will update the docs on this soon šŸ™‚

Also, renaming the singular resolvers like user_by_pk to something like user will be possible via this PR: https://github.com/hasura/graphql-engine/pull/2509.

OLDIN commented 5 years ago

@marionschleifer This is fantastic but how long would that take?

corysimmons commented 5 years ago

@marionschleifer Awesome! Renaming from user_by_pk to user in https://github.com/hasura/graphql-engine/pull/2509 will be amazing as well!

Thanks so much for the Hasura team's work on this!

marionschleifer commented 5 years ago

@OLDIN we will release this in the next few weeks šŸ™‚

revskill10 commented 5 years ago

Please keep the option to be optional, as current projects are still using the user_by_pk . My suggestion is keeping the current as default, and allow user to provide custom name if they want.

marionschleifer commented 5 years ago

@revskill10 it will be optional šŸ™‚

davetapley commented 5 years ago

I just want to call out that this will be very useful for a specific use case of views, which helps with auditing changes to data:

  1. Have a widget_revision table, which is insert only, and has columns for widget_id and created_at (along with other widget data).
  2. When a widget is updated, the client inserts a new row in to widget_revision, and in Hasura we set its created_at to the current time.
  3. We have a widget view which has the most recent widget_revision for each widget_id.

It's a great pattern, but we struggle because we'd like to have widget_by_pk, but no such query exists. Presumably because we can't make widget_id on widget a PK, because Postgres doesn't allow PKs on view.

I'm hoping this issue would allow us to add widget_by_pk?

haaah commented 4 years ago

adding support of returning a single object will be useful in "view" scenario.

tirumaraiselvan commented 4 years ago

Dup of https://github.com/hasura/graphql-engine/issues/519 ?

SidhNor commented 4 years ago

@marionschleifer I believe the feature request wasn't just about querying by the primary key, but rather by unique columns (including primary key) Documenting table_by_pk will not actually solve the initial request.

Thank you

marionschleifer commented 4 years ago

@SidhNor we are tracking this feature here: https://github.com/hasura/graphql-engine/issues/519. But we left this issue open to document table_by_pk.

tafelito commented 4 years ago

@marionschleifer it seems to me that the original request was not only about changing the default name for the query_by_pk queries, but also be able to return a single object as the result of a mutation. Is that something that you are planning on add later on?

I'm referring to this

// before
mutation AddUser ($objects: [users_insert_input!]!) { // I only want to insert a single user but I have to submit the mutation as an array.
  insert_users(objects: $objects) {
    returning {
      id
    }
  }
}

// after
mutation AddUser ($object: user_insert_input!) { // only inserting a single user; returning a single object
  insert_user(object: $object) {
    returning {
      id
    }
  }
}

// OR

mutation AddUsers ($objects: [users_insert_input!]!) { // Sometimes I will want to add multiple users, so keep the existing queries/mutations available.
  insert_users(objects: $objects) {
    returning {
      id
    }
  }
}

I think there is an open RFC for this here

coco98 commented 4 years ago

@tafelito Yep, single element mutations (inserts/updates/deletes) are already available in 1.2-beta* and will be available in 1.2! They implement that RFC :)

tafelito commented 4 years ago

Awesome thanks @coco98!

what about returning a single row for custom functions, instead of an array? I tried to find a related issue but I couldn't find it