Allow time functions (Now, TimeAdd, TimeSubtract, Time, etc.) on indexes

I have the following index:

q.CreateIndex({
  name,
  source: {
    collection: q.Collection('userTokens'),
    fields: {
      isActive: q.Query(
        q.Lambda(
          ['document'],
          q.If(
            q.LT(q.Now(), q.Select(['data', 'expiresAt'], q.Var('document'))),
            1,
            0
          )
        )
      )
    }
  },
  terms: [
    { field: ['data', 'userId'] },
    { field: ['data', 'token'] },
    { binding: 'isActive' }
  ]
});

For some weird resons this:

q.If(
  q.LT(q.Now(), q.Select(['data', 'expiresAt'], q.Var('document'))),
  1,
  0
)

results to 0 even though it should be 1, resulting to instance not found errors, but when I tried that on the shell, it actually gave me back the expected output.

If(
  LT(
    Now(),
    Time("2021-01-20T14:43:41.419689Z")
  ),
  1,
  0
)

It may have something to do with the index itself but I can’t find what it is, it can’t be the lambda because as far as I know, this:

q.Lambda(
  ['document'],

is the same as this:

q.Lambda(
  'document',

Now I see why, it’s because of this Indexes | Fauna Documentation apparently NOW cannot be used in an index. I think this will be a limitation and will have a negative impact on how we create and use indexes…

I tried using Time('now') but also resulted to the same problem.

Hi @aprilmintacpineda ,

Your goal is to pass to the index

userId, token, isActive

where isActive is 0 or 1 and get back the reference for the document, is it correct?

Luigi

Yes, that is correct. The isActive is a binding and is determined by checking if a particular date has already past, which I can see that is only possible by using Now but that’s not allowed to be used in indexes.

Hi @aprilmintacpineda ,

as a simple workaround, you can create an index like this:

CreateIndex({
  name: "refByIdToken",
  source: Collection('userTokens'),
  terms: [
    { field: ['data', 'userId'] },
    { field: ['data', 'token'] }
  ],
  values: [
    { field: ['data', 'expiresAt'] },
    { field: ['ref'] }
  ]
})

and a function:

CreateFunction(
  {
    name: 'getUser',
    body: Query(
      Lambda(['userId','token','isActive'],
        Let(
          {
            document: Get(Match('refByIdToken',[Var('userId'),Var('token')])),
            expired: If(LT(Now(),Select(['data','expiresAt'],Var('document'))),1,0) 
          },
          If(Equals(Var('isActive'),Var('expired')),Var('document'),"Token not valid")
        )
      )
    )
  }
)
and then call the function:

Call(Function(“getUser”),[‘test1’,‘abcde’,1])
{ ref: Ref(Collection(“userTokens”), “287691618317763079”),
ts: 1610622957440000,
data:
{ userId: ‘test1’,
token: ‘abcde’,
expiresAt: Time(“2021-01-20T14:43:41.419689Z”) } }

Call(Function(“getUser”),[‘test1’,‘abcde’,0])
‘Token not valid’

or

Call(Function(“getUser”),[‘test2’,‘fghij’,0])
{ ref: Ref(Collection(“userTokens”), “287691672105517575”),
ts: 1610623008876000,
data:
{ userId: ‘test2’,
token: ‘fghij’,
expiresAt: Time(“2021-01-10T14:43:41.419689Z”) } }

Call(Function(“getUser”),[‘test2’,‘fghij’,1])
‘Token not valid’


Hope this helps.

Luigi

That gave me an idea of what I can do as a workaround, but I think that would be inefficient, it would be more efficient to add this functionality to indexes, what I will have to do is this:

This should return a list of tokens generated by the user.

  1. Get all tokens.
  2. Filter out the expired documents.
  3. Return the filtered documents.

Which I believe will do quite a lot of computes compared to doing it on indexes.

I will give this a try though, thanks for the suggestion!