fauna / faunadb-js

Javascript driver for Fauna v4 (deprecated)
https://docs.fauna.com/fauna/v4/
Other
702 stars 75 forks source link

[FE-2892] fix single ref argument #667

Open ptpaterson opened 1 year ago

ptpaterson commented 1 year ago

Jira Ticket

Problem

query.Ref accepts a single argument for backwards compatibility with the Ref("collections/widget/123") format, which is serialized as { "@ref": "collections/widget/123" }.

The driver does this by just stuffing whatever is given to it as value => { "@ref": value }. This is a problem when the value provided is anything other than a string. The database expects FQL values to be... values! E.g. is illegal to even provide an expression that resolves to a string

client.query(q.Ref(q.Concat(["collections", "widget", "123"], "/"))

// wire protocol
// {"@ref":{"concat":["collections","widget","123"],"separator":"/"}}

{
  "errors": [
    {
    "position": [],
    "code": "invalid expression",
    "description": "Ref expected, Object provided."
    }
  ]
}

This error is correct behavior.

examples of other problematic queries

It is illegal wire protocol for FQL expressions to be in literal values, but is currently allowed

const funky_ref = q.Ref(q.Ref(q.Collection("things"), "307286571965481024"))
const funky_wire = JSON.stringify(funky_ref, null, 2)
console.log(funky_wire)

{
  "@ref": {
    "ref": {
      "collection": "things"
    },
    "id": "307286571965481024"
  }
}

It there is also potential for folks to wrap a value.Ref into another layer of @ref, which is problematic.

const result = await client.query(q.Ref(q.Collection("things"), "307286571965481024"))
const funky_ref = q.Ref(result)
const funky_wire = JSON.stringify(funky_ref, null, 2)

console.log(funky_wire)
{
  "@ref": {
    "@ref": {
      "id": "307286571965481024",
      "collection": {
        "@ref": {
          "id": "things",
          "collection": {
            "@ref": {
              "id": "collections"
            }
          }
        }
      }
    }
  }
}

Expected behavior

Using query.Ref with two arguments, it is expected that the arguments can be any expression 👍🏻

But if only one argument is provided, we know it must be a string (again, not even an expression that could resolve to a string).

Solution

Assert that in the single-argument case the argument is a string, i.e. typeof arguments[0] === 'string' || arguments[0] instanceof String

Testing

additional tests added