FQL v4 migration

If you have an existing application currently querying Fauna using the FQL v4 API, you can transition existing FQL v4 applications to FQL v10 incrementally. FQL v10 is backward-compatible with all your existing data, so you don’t have to change or migrate the data.

The following sections describe some changes introduced with FQL v10 that you should be aware of.

Document structure improvements

User-defined fields

To improve ergonomics, user-defined fields in a document are promoted to top-level fields in FQL v10 as the document structure. Notice the difference between the same document in the FQL v4 and the FQL v10 APIs.

{
  "_id": "340888671260508194",
  "_ts": 1661355620630000,
  "data": {
    "name": "Hard Anodised 12 Kadhai",
    "type": "Kitchen & Dining",
    "price": 999,
    "quantity": 30
   }
}
{
  id: "340888671260508194",
  coll: Product;
  ts: 1661355620630000,
  name: "Hard Anodised 12 Kadhai",
  type: "Kitchen & Dining",
  price: 999,
  quantity: 30
}

Metadata field names

In FQL v4 document metadata fields with the reserved names _id, _coll, and _ts include an underscore prefix. In FQL v10, these fields omit the underscore with id, coll, and ts as field names. The meaning and semantics of the fields remain unchanged.

Data field

In FQL v10, customer data is stored as top-level fields instead of in a data field.

FQL presents these fields without the need for you to make changes. The presentation of these fields is done by Fauna without alteration to your existing documents. You can continue to use your existing FQL v4 queries on Collections you are also querying on using the FQL v10 API. Your FQL v4 queries continue to reference and write to fields nested in the data field.

User-defined functions

You can embed FQL queries into an FQL v4 application by encapsulating the FQL query in a User Defined Function (UDF) and calling that UDF in your FQL v4 queries. In fact, UDFs enable interoperability between the two versions of the language in each direction. If you want to use an FQL v4 index in FQL, wrap the indexed query in an FQL v4 UDF, and call that UDF in FQL v10. See User-defined functions for more information.

Here are some examples of what such queries would look like. For the following FQL v10 function:

Function.create({
  name: "getOrdersByCustomer",
  body: "name => Order.all.where(.customer.name == name)"
})

 

You can invoke the FQL v10 UDF in FQL v4 with the following query:

Call( 'getOrdersByCustomer', 'Gregor Samsa' )

 

For the following FQL v4 function:

CreateFunction({
  name: "Increment",
  body: Query(Lambda("number", Add(1, Var("number"))))
})

 

You call the FQL v4 function using the following FQL v10 expression:

let num = Increment( 1 )

Indexes

Indexes in FQL v10 are now declared in the Collection they cover. This is different from FQL v4 indexes, which were top-level schema objects that exist at the same level as a collection. FQL v4 indexes can’t be called directly in FQL v10, but indexed queries can be used in FQL v10 if they’re embedded in a UDF. Similarly, FQL v10 indexes can’t be directly called from an FQL v4 query unless the indexed query is in a UDF.

Indexes in FQL v10 are full indexes whereas v4 indexes are sparse indexes. For example, if you declared a v4 index with a value field foo, in FQL v4 there is an entry in the index for every document that has a non-null foo value. In FQL v10, all documents are indexed, including those that have a null foo value.

In FQL v4, terms and values treat arrays as a multivalued attribute (MVA) such that when a term targets a document field or index binding result that is an array, one index entry per array item is created. In FQL v10, you must explicitly state that a term or a value is an MVA. See Indexes definition.

FQL v10 computed fields is generally equivalent toFQL v4 index binding, and are declared inside the collection instead of in the index. See collection.compute.

Reserved words and field names

As described previously, the document metadata id, coll, and ts keywords are reserved. See Reserved words. If your existing documents use these field names, they’re nested in the data field of your documents to avoid colliding with the FQL v10 reserved key names. For example, notice how the id field in the following FQL v4 document is nested in data, avoiding collision on the reserved key name:

{
  "Ref": Ref(
    Collection("Product"),
    "340888671260508194"),
  "_ts": 1661355620630000,
  "data": {
    "id":   "Premium Kadhai",
    "name": "Hard Anodised 12 Kadhai",
    "type": "Kitchen & Dining",
    "price": 999,
    "quantity": 30
   }
}
{
  id: "340888671260508194",
  coll: Product;
  ts: 1661355620630000,
  name: "Hard Anodised 12 Kadhai",
  type: "Kitchen & Dining",
  price: 999,
  quantity: 30,
  data: {
    "id":   "Premium Kadhai"
  }
}

System-level reserved Collection names

To avoid naming conflicts with system Collections and entities, FQL v10 doesn’t allow you to name top-level entities, such as collections and UDFs, with a reserved name. Where a user-defined collection or function has a conflicting name, you can assign collections and UDFs an alias that makes that resource available in the FQL v10 environment. For example, when migrating from FQL v4 with a Collection named Collection, you must add an alias to the collection to use it in their FQL v10 environment.

// adding an alias to a Collection named Collection
Collection.byName("Collection")!.update(
  {
    alias: "Products"
  }
)

// using that collection in a subsequent query
Products.firstWhere(.name == "Hard Anodised 12 Kadhai")
Products.create(...)

If the original name is non-conflicting, the Collection/UDF is available as its name and as the aliased name. If it is conflicting, the Collection/UDF is available only under the aliased name.

Referenced collections

You can no longer delete a collection that is referenced by a Role or Key document. This is true of roles or keys created in v4 or v10. You must reconfigure or remove the Role or Key and then delete the collection.

AccessProvider and Role configure

You must configure AccessProviders and Roles using FQL v10 methods and not FQL v4 methods.

In v10, the Role name must be a valid identifier. In v4, these were a resource type. In the membership and privileges configuration, the v10 resource field is a name String.

The Role specification of privileges changed substantially in v10. In v10, predicate bodies are FQL strings. In v4, these were Query structures. For Role documents, the history_write and history_read actions aren’t yet supported in v10.

This example shows a v4 privileges configuration:

privileges: [
 {
    resource: Ref("Foo"),
    actions: {
      read: true,
      write: false,
      create: false,
      delete: false,
      history_read: false,
      history_write: false
    }
  }

In v10, these same privileges have this configuration.

privileges: [
  {
    "resource": "Foo",
    "actions": {
      "read": true,
      "write": true,
      "create": true
    }
  },
  ... etc
]

You should review the Role document fields for specifics about writing actions predicates in v10.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!