Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Current user subscription #4112

Closed
maxpain opened this issue Mar 14, 2020 · 8 comments
Closed

Current user subscription #4112

maxpain opened this issue Mar 14, 2020 · 8 comments

Comments

@maxpain
Copy link
Contributor

maxpain commented Mar 14, 2020

We have these tables:

users (id, user_name)
user_stats (user_id, rating, matches_count, etc.)

We want to make a subscription to the current user (with some relations, like user_stats) with this query:

SELECT *
FROM users
WHERE id = X-Hasura-User-Id

So, we have two ways to do that:

1. Make a custom function, using X-Hasura-User-Id session variable.

Pros:

  • We get right typename (users)
  • We don't have to recreate all permissions for all roles
  • We don't have to recreate all relations for other tables

Cons:

  • This way works only for queries. In subscriptions, this way doesn't support batching/multiplexing

So we can't use this way due to performance reasons.

2. Make a view, using custom check ({"id":{"_eq":"X-Hasura-User-Id"}})

Pros:

  • Subscriptions are multiplexed

Cons:

  • We get different typename (users_current instead of users), so we can't reuse cache and the same fragments on our react/apollo frontend.
  • We have to recreate all permissions
  • We have to recreate all relations and maintain them.

What we can do?

@rikinsk
Copy link
Member

rikinsk commented Mar 16, 2020

@Maxpain177 Any reason you aren't setting the {"id":{"_eq":"X-Hasura-User-Id"}} check as a permission rule and then using subscriptions on the users table directly?

@rikinsk
Copy link
Member

rikinsk commented Mar 16, 2020

@0x777 any insights on the subscriptions bit?

@maxpain
Copy link
Contributor Author

maxpain commented Mar 16, 2020

@rikinsk Because we want to get not only current user from users table

@kelly-ry4n
Copy link

kelly-ry4n commented Mar 16, 2020

Can you get the user id from your auth server, and query users using that and 2 different subscriptions / queries?

subscription currentUser {
  currentUser:user(where: {id: {_eq: 1}}) {
    id
    email
  }

}

subscription otherUsers {
    otherUsers:user(where: {id: {_neq: 1}}) {
    id
    email
  }
}

@lexi-lambda
Copy link
Contributor

I agree with @kelly-ry4n: why not just look up the current user’s id and create a subscription on users filtered by that id?

@0x777
Copy link
Member

0x777 commented Mar 17, 2020

@Maxpain177

Both the solutions you suggested work (with small changes)

Using functions:

Subscriptions on functions which accept session variables as their arguments are multiplexed. The function should look something like this:

create function get_current_user(hasura_session json) returns setof users as $$
  select * from users where id = (hasura_session ->> 'x-hasura-user-id')::Int
$$ language sql stable;

Console doesn't yet support tracking functions which require session variables so you'll need to manually hit /v1/query endpoint with this query:

{
  "type": "track_function",
  "version": 2,
  "args": {
    "function": {
      "schema": "public",
      "name": "get_current_user"
    },
    "configuration": {
      "session_argument": "hasura_session"
    }
  }
}

or it can also be made part of metadata as follows:

{
  "version": 2,
  "tables": [
    {
      "table": {
        "schema": "public",
        "name": "users"
      }
    }
  ],
  "functions": [
    {
      "function": {
        "schema": "public",
        "name": "get_current_user"
      },
      "configuration": {
        "session_argument": "hasura_session"
      }
    }
  ]
}

Using views

To avoid the cons that you listed, you just need to create an object relationship to the users table. So this will be the workflow:

  1. create a view called current_user as follows:

    create view current_user as select * from users
  2. Create permission on current_user for user roles as {"user_id": {"_eq": "x-hasura-user-id"}}

  3. Create a manual object relationship from current_user view to user table so that you can access all the relationships defined on the user table. Your subscription would look something like this:

    subscription current_user {
      current_user {
        user {
          id
          stats {
            
          }
        }
      }
    }
    

You can use any of the above approaches.

@makinde
Copy link

makinde commented Sep 1, 2022

In case it is useful to anyone, I'm currently doing the second solution that @0x777 suggested with the views, but with a slightly different approach. I have an object relationship from users to current_user labeled isCurrentUser. That allows me to write queries that don't start with current_user at the root. So I can do something like,

query MyQuery {
  users(where: { isCurrentUser: {} }) {
    id
    stats {
      ...
    }
  }
}

that where clause can be used in any larger query where I need to filter for the current user.

@wenerme
Copy link

wenerme commented Mar 3, 2023

@0x777 method 2 is failed for 2.20

the relationships page is failed with follow request

POST /v1/metadata
{"type":"pg_suggest_relationships","args":{"omit_tracked":true,"tables":[null],"source":"App"}}
{
  "code": "parse-failed",
  "error": "Error when parsing command suggest_relationships.\nSee our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis.\nInternal error message: \n  Previous branch failure: Error in $: expected Null, but encountered Array\n  Previous branch failure: Error in $: parsing PostgresQualified_TableName failed, expected Object, but encountered Null\nparsing Text failed, expected String, but encountered Null",
  "path": "$.args.tables[0]"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants