0.12 Migration Notes
Tags: devops, webdev, javascript, appwrite
Published: 2022-01-04 16:47:04

0.12 introduces a few breaking changes that you must mitigate before upgrading from any previous version of Appwrite. Please make sure to read these notes before migration.

## Breaking Changes
➤ Nested documents no longer exist as they cause massive performance degradation

The deprecation of nested documents means that you now have to store nested documents as JSON within a String attribute. An example of code that uses nested documents is below:

```js
let actorsCollection = await database.createCollection(
    'Actors', // Collection Name
    ['*'], // Read permissions
    ['user:amadeus', 'user:salieri'], // Write permissions
    [ // Rules
      {
        "label": "Name",
        "key": "name",
        "type": "text",
        "default": "Empty Name",
        "required": true,
        "array": false
      },
      {
        "label": "Age",
        "key": "age",
        "type": "number",
        "default": 0,
        "required": true,
        "array": false
      }
    ]
);

let moviesCollection = await database.createCollection(
    'Movies', // Collection Name
    ['*'], // Read permissions
    ['user:amadeus', 'user:salieri'], // Write permissions
    [ // Rules
      {
        "label": "Name",
        "key": "name",
        "type": "text",
        "default": "Empty Name",
        "required": true,
        "array": false
      },
      {
        "label": "Release Year",
        "key": "releaseYear",
        "type": "numeric",
        "default": 1970,
        "required": true,
        "array": false
      },
      {
        "label": "Actors",
        "key": "actors",
        "type": "document",
        "default": null,
        "required": false,
        "array": true,
        "list": [actorsCollection['$id']] // Name the collections unique IDs that are allowed in the attribute
      }
    ]
);
let response = await database.createDocument(
  moviesCollection['$id'], // Parent collection unique ID
  {
    "name": "Frozen 2",
    "releaseYear": 2019,
    "actors": [
      {
        "$collection": actorsCollection['$id'], // The actors collection unique ID
        "$permissions": {"read": ["*"], "write": ['user:amadeus', 'user:salieri']}, // Set document permissions
        "name": "Idina Menzel",
        "age": 35
      },
      {
        "$collection": actorsCollection['$id'], // The actors collection unique ID
        "$permissions": {"read": ["*"], "write": ['user:amadeus', 'user:salieri']}, // Set document permissions
        "name": "Kristen Bell",
        "age": 35
      }
    ]
  },
  ['*'], // Read permissions
);
```

Converting that code so it works without nested documents looks like so:

```js
let moviesCollection = await database.createCollection(
    'Movies', // Collection Name
    ['role:all'], // Read permissions, notice how it's now 'role:all' instead of '*'
    ['user:amadeus', 'user:salieri'], // Write permissions
    [ // Rules
      {
        "label": "Name",
        "key": "name",
        "type": "text",
        "default": "Empty Name",
        "required": true,
        "array": false
      },
      {
        "label": "Release Year",
        "key": "releaseYear",
        "type": "numeric",
        "default": 1970,
        "required": true,
        "array": false
      },
      {
        "label": "Actors",
        "key": "actors",
        "type": "Text",
        "default": null,
        "required": false,
        "array": true,
      }
    ]
);
let response = await database.createDocument(
  moviesCollection['$id'], // Parent collection unique ID
  {
    "name": "Frozen 2",
    "releaseYear": 2019,
    "actors": [
      JSON.stringify({
        "name": "Idina Menzel",
        "age": 35
      }),
      JSON.stringify({
        "name": "Kristen Bell",
        "age": 35
      })
    ]
  },
  ['role:all'], // Read permissions, notice how it's now 'role:all' instead of '*'
);
```

As you can see, the code is more straightforward now since we don't have to create an entirely different collection for that data. This change makes Appwrite overall faster and makes you a quicker developer when using Appwrite.

➤ Numeric Values are now migrated to floats

When using the migration tool, numeric values are now migrated to floats. If you create new integers, they will stay as integers. It only affects documents that have been migrated using the tool.

If you use a dynamically typed language, you won't need to worry about migrating this change.

You will need to update your values from integers to your language's relevant float type for a language like flutter, swift or java.

➤ Wildcard and Markdown rules no longer exist

The Appwrite team have removed the markdown and wildcard attribute because there isn't any reason to have a specific type of them. To migrate from these two changes, we recommend using the Text attribute. The migration tool will automatically handle this change for you.

➤ The Appwrite SDK/HTTP API now requires custom ID's for certain endpoints

Appwrite SDK's / HTTP API requires you to pass a custom ID or `unique()` as the first param for many of the `createX()` functions. We recommend double-checking the updated documentation to see which ones were updated.

We recommend finding all the instances of a create function within your code, then checking the documentation for each to see if they have unique ID support. If it does, add a new parameter at the start, which will be a string and will contain `unique()`. This change will then return functionality to generating a random unique ID as before 0.12.

➤ The * permission has been renamed

`*` has been renamed `role:all`, which clarifies what it means and follows other role conventions. With this change, the database migration tool will automatically migrate the data already in Appwrite. However, your code interacting with Appwrite will need to be updated to deal with this change.

We recommend changing all instances of `*` for Appwrite permissions to `role:all`.

➤ Tasks service has been deprecated and removed

The Appwrite team has removed the Tasks service because its functionality can be easily replicated and improved with functions.

➤ CreateCollection() no longer accepts rules

Instead of directly adding rules inside CreateCollection(), you now need to use `createXAttribute()` to add rules to the collection after the collection has been created. The `X` means a type of attribute, and there are a few of them: there is `string`, `bool` and `integer`.

➤ User status is now a boolean
The Appwrite team has now made user status a boolean to simplify determining if a user is active or not.

➤ Order parameters have been renamed for listDocuments()

`orderAttributes` have been renamed to `orderField`
`orderTypes` have beben renamed to `orderType`

➤ listDocument filters now use a different syntax

We have updated the syntax for listDocument filters to make it more powerful and easier to use. Each SDK has a `Query` class to help you build queries.

➤ Permission Levels act differently when migrated

In 0.12 we introduced two different permission levels `document-level` and `collection-level`. In previous versions, permissions were nested, which meant you would have to satisfy both permission levels to access a document. In 0.12, we have changed this only to require one permission level that you select to access a document.

By default, when migrating, this is set to document-level permissions.

## Upgrading your SDK's
Updating your SDK varies depending on your language. For most of them, you only need to run a command.

➤ Client SDK's

#### **Web**

Run the relevant command for your package manager:

NPM:
```
npm update appwrite
```

Yarn:
```
yarn upgrade appwrite
```

#### **Flutter**
```
pub upgrade appwrite
```
#### **Apple**
Update the Appwrite entry in your `Package.swift` file to:
```
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "0.2.0"),
```
#### **Android**
Gradle
Update the Appwrite entry in your `build.gradle(.kts)` to:
```
implementation("io.appwrite:sdk-for-android:0.3.0")
```
Maven
Update the Appwrite entry in your `pom.xml` file to:
```xml
    <dependency>
        <groupId>io.appwrite</groupId>
        <artifactId>sdk-for-android</artifactId>
        <version>0.3.0</version>
    </dependency>
```

➤ Server SDK's

#### **NodeJS**
Run the relevant command for your package manager:

NPM:
```
npm update node-appwrite
```

Yarn:
```
yarn upgrade node-appwrite
```

#### **PHP**
Run the following command:
```
composer update appwrite/appwrite
```

#### **Dart**
Run the following command:
```
pub upgrade dart_appwrite
```

#### **Deno**
Update the version after the `@` in the URL of your import statement like so:
```
import * as SDK from "https://deno.land/x/appwrite@2.0.0/mod.ts";
```
Note: We highly recommend pinning your versions with Deno since your code could break when we push an update with a breaking change or for a newer version of Appwrite.

#### **Ruby**
Run the following command:
```
gem update appwrite
```

#### **Python**
Run the following command: 
```
pip install appwrite --upgrade
```
Make sure to update your `requirements.txt` file if you use one.

#### **Kotlin**
Gradle
Update the Appwrite entry in your `build.gradle(.kts)` to:
```
implementation("io.appwrite:sdk-for-kotlin:0.2.0")
```
Maven
Update the Appwrite entry in your `pom.xml` file to:
```xml
    <dependency>
        <groupId>io.appwrite</groupId>
        <artifactId>sdk-for-android</artifactId>
        <version>0.2.0</version>
    </dependency>
```
#### **Apple**
Update the Appwrite entry in your `Package.swift` file to:
```
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "0.2.0"),
```

#### **Dotnet**
Update the Appwrite entry in your project's `.csproj` file to:
```
<PackageReference Include="Appwrite" Version="0.4.0" />
```

You can also upgrade the packages from the command line:
```
# Package Manager
Install-Package Appwrite -Version 0.4.0

# or .NET CLI
dotnet add package Appwrite --version 0.4.0
```