Print or Log FQL for debugging

Hi there, console.log enthusiast here.

I am starting to get the hang of FQL but often just want to see what an expression evaluates to, especially when I’m a few nested Lets into my query with a multiple variables set. Is there a way to print/log at intermediary steps in the Shell for debugging purposes?

2 Likes

Hey hey,

I understand completely why you would want that :slight_smile:.
Of course, that means we need to print somewhere that makes sense since that FQL is, of course, executed on the FaunaDB’s side. At this point we do not have a mechanism to log and send these logs back to the client. Similar to this request, there are feature-requests in our backlog to have feedback on the results of ABAC FQL-based roles as well, we are definitely considering these ideas but have not implemented them yet.

The best advice I can give you atm is to build your FQL step by step. I typically construct everything with Let constructs and initially return each step of the Let to see the result while I’m writing a query. I often try it out in the dashboard shell and/or write unit tests immediately if I’m writing complex ABAC roles.

I hope that advice helps a tiny little bit :slight_smile:

Check out Format. Specifically, the %@ conversion parameter. It states

The result is formatted as the FaunaDB wire protocol. (This is a debug conversion which applies to all non-scalar values)

That means you can wrap any query, or portion of a query, in Abort(Format('%@', ... )) to force the query to stop and just give you a portion of the wire protocol. Quite handy.

Credit goes at least to @gahabeen, @eigilsagafos and maybe others, for bringing to my attention.

The really REALLY cool part is that variables are printed as however they are evaluated!!

This, for example, lets you define a bunch of stuff early in the Let bindings, but then see that expanded simply in some later expressions.

very contrived example:

Let(
  {
    id: "238074636851479047",
    coll: Collection('Book'),
    ref: Ref(Var('coll'), Var('id')),
    doc: Get(Var('ref'))
  },
  {
    id: Format("%@", Var("id")),
    coll: Format("%@", Var("coll")),
    ref: Format("%@", Var("ref")),
    doc: Format("%@", Var("doc")),
  }
)

// RETURNS
{
  id: '"238074636851479047"',
  coll: '{"@ref":{"id":"Book","class":{"@ref":{"id":"classes"}}}}',
  ref: '{"@ref":{"id":"238074636851479047","class":{"@ref":{"id":"Book","class":{"@ref":{"id":"classes"}}}}}}',
  doc: '{"ref":{"@ref":{"id":"238074636851479047","class":{"@ref":{"id":"Book","class":{"@ref":{"id":"classes"}}}}}},"ts":1563304516560000,"data":{"title":"Oh the places you\'ll go","author":{"@ref":{"id":"238074636850430471","class":{"@ref":{"id":"Member","class":{"@ref":{"id":"classes"}}}}}}}}'
}
3 Likes

Agree @ptpaterson. I have this wrapped in a Debug function. I use this daily when working with FQL. (https://github.com/shiftx/faunadb-fql-lib#debug)

3 Likes

That’s some great advice there, thanks @ptpaterson and others!

I just found this post here. Great stuff! That’s what is working best to me so far:

Abort(Format("%@", VALUE_TO_BE_CHECKED))

As an example, to check the user’s identity:

Abort(Format("%@", CurrentIdentity()))

I just wish the same trick would work inside the role definitions.
It seems pretty impossible to debug anything there.

Do we have any similar trick that would work there?

Are you trying to debug the predicate functions?

yes! Like in the example below

For this is might be easiest to inspect just CurrentIdentity() using one of the drivers.

const userClient = new Client({ secret: USER_TOKEN })
userClient.query(CurrentIdentity())

You can be confident that the Identity for the role predicate comes from the token used to create the client, so just running the query for it directly will work.

You can Abort(Format(...)) this if you really want to see the wire protocol, but the Ref results, or even Get(CurrentIdendity()) might give you all the clues you’re looking for.

There is an effort to impersonate different tokens inside the cloud shell, which would make it easier. But until that happens, you’ll need to do this from a local shell or driver.