Checkpwd as variable in condition

Hi,
im having a bad time trying to conditionally upsert the actual password to a new password if checkpwd from the actual password is true.

  1. if used as var and evaluate with val, checkpwd returns 0 or 1 instead of true or false (perhaps due to Convert(from Val, toID TypeID) not beeing called internally)
    e.g.
{
users(func: has(password)) {
  	a as authenticated: checkpwd(password, "mySecret")
  	test: val(a)
}
}

returns (if password actually is “mySecret”), otherwise it return false and 0

{
  "data": {
    "users": [
      {
        "authenticated": true,
        "test": 1
      },
...
  1. already tried: if used with bool or string like
Cond:    `@if(eq(val(a), true))`,
or
Cond:    `@if(eq(val(a), "true"))`, 

of course you will get a type error: rpc error: code = Unknown desc = : Invalid argment true. Comparing with different type

  1. if used in condition from upsert, the condition will always return false - so no mutation happens.

Cond: `@if(eq(val(a), 1)))`,

it does not matter, if the password is right, or you change the Condition to only mutate when the password is wrong…

Cond: `@if(eq(val(a), 0)))`,

the mutation is never fired.

  1. same thing if used checkpwd is used in a filter query (to test len of a in Condition):
passwordCondition(func: uid($uid)) @filter(eq(val(b), 1)) {
				a as uid
				b as checkpwd(password, $password)
  			}

How to use checkpwd in upsert / as variable in val?

(PS: i know i can split this into two transactions, but only one upsert call would be much more convenient, as this checkpwd is used on change email, change password and other more confidential methods…)

That won’t work. The Cond operation accepts only length function as far as I know.
You can do this in two ways. 1:1 query and 1:Many query.

I mean 1 query to one result or 1 query to many results

It is worth mentioning that there is no function that checks True or False at Root queries. There is “cond” in math func, but it is not useful in these cases.

The 1:1 query

upsert {
  query {
    my_q(func: eq(name, "Alice")) {
      a as authenticated: checkpwd(password, "AlicePass")
      test: val(a)
    }
}
  mutation @if(eq(len(a), 1)) {
    set {
      uid(a) <test> "test 1:1" .
    }
  }
}

This function is 1 to 1, using length is fine.
It will check if the my_q block was successful in the query. However, if there were several Alices. It won’t update anything (cuz the length is greater than 1) and if you use gt(len(a), 1 It will update all of them, even if the password for each one of them returns false and a single true. So it is not really checking any logic in the password func. The length of it could by 1 > N.

The 1:Many query

upsert {
  query {
    users(func: has(password)) {
      a as authenticated: checkpwd(password, "AlicePass")
      test: val(a)
    }
    F as var(func: uid(a)) @filter(eq(val(a), 1))
}
  mutation @if(eq(len(F), 1)) {
    set {
      uid(F) <test> "test 1:Many" .
    }
  }
}

This query is purposely querying every user who has the “password” predicate. That is, it could potentially return thousands of nodes. The only way to check if the password matches is creating an intermediate block to check if the variable ‘a’ has a value of 1. In this case, the numbers 0 or 1 play the role of True or False.

In the mutation block, you can simply use length func as normal.

This is the approach I recommend (I mean use an intermediate block and also filters in the query block). And the more refined the query, the more safe your upsert txn query is.

Dataset

{
   "set": [
      {
         "name": "Alice",
         "password": "AlicePass"
      },
      {
         "name": "Bob",
         "password": "BobPass"
      }
   ]
}

Base query

{
  users(func: has(password)) {
    a as authenticated: checkpwd(password, "AlicePass")
    test: val(a)
  }
  q(func: uid(a)) @filter(eq(val(a), 1)){
    name
  }
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.