The Model API
The @teamkeel/sdk
package is generated based on your schema and contains type-safe APIs for interacting with your models. These APIs are all available on the exported models
object.
import { models } from "@teamkeel/sdk";
Given the following Keel schema:
model Post {
fields {
title Text
}
actions {
write createPost()
}
}
model Author {
fields {
name Text
}
}
models.post
and models.author
will be available.
Creating a record
.create()
receives a single parameter:
params
- object representing all of the data you would like to insert. This must include all required fields on the model.
Fields that have a @default
value in the schema will have their default values populated if no value is provided.
For @unique
fields, inserted data will be checked for uniqueness.
import { models } from "@teamkeel/sdk";
const post = await models.post.create({
title: "a post about star wars",
});
console.log(post.title); // => a post about star wars
The return type is Promise<Model>
Updating a record
.update()
receives two parameters:
where
- the query conditions to lookup records by.values
- the set of changes you want to update the record(s) with.
For @unique
fields, updated data will be checked for uniqueness.
import { models } from "@teamkeel/sdk";
const where = {
id: "123",
};
const values = {
title: "a post about star wars",
};
const post = await models.post.update(where, values);
console.log(`Updated ${post.id}'s title`);
The return type is Promise<Model>
Deleting a record
.delete()
receives a single parameter:
where
- the conditions applied to the database query that will determine which records will be deleted
import { models } from "@teamkeel/sdk";
const deletedId = models.post.delete({
id: "123",
});
Reading a single record
.findOne()
receives a single parameter:
where
- an object where the keys are any unique field on a model and the values are the unique values you want to look up by
import { models } from "@teamkeel/sdk";
const post = await models.post.findOne({
id: "abc",
});
The return type is Promise<Model | null>
Reading multiple records
.findMany
receives a single parameter:
params
- Object of typeFindManyParams
FindManyParams
Consists of four top level properties:
limit
(number
) - the number of rows to limit the result set byimport { models } from "@teamkeel/sdk"; const results = await models.post.findMany({ limit: 5, });
offset
(number
) - the number of rows to offset by. Usually combined withlimit
andorderBy
to return individual pages of data.import { models } from "@teamkeel/sdk"; const results = await models.post.findMany({ limit: 10, offset: 2, orderBy: { title: "asc", }, });
where
(Where
) - an object where the keys are one of the fields on the model and the values are objects conforming to theWhereConditions
type. See theWhereConditions
reference for a full table of the available options for different field types below.import { models } from "@teamkeel/sdk"; const postsBeginningWithA = await models.post.findMany({ { where: { title: { startsWith: 'a' } } } });
orderBy
(OrderBy
) - an object used to define the sort order of the results returned from the database. The object must contain one property where the key is a known field name on the model, and the value must either beasc
,desc
.import { models } from "@teamkeel/sdk"; const orderedByTitle = await models.post.findMany( orderBy: { title: 'asc' } );
WhereConditions
The WhereConditions
type can be used with the findMany
method to filter by a range of different operators:
Operator Name | Field Types | Description | Usage |
---|---|---|---|
startsWith | Text | Match values beginning with the search value | { title: { startsWith: 'abc' }} |
endsWith | Text | Match values ending with the search value | { title: { endsWith: 'xyz' }} |
oneOf | Text | Match values against an array of possible values | { title: { oneOf: ['apple', 'orange'] }} |
contains | Text | Match values against a partial match within a string | { title: { contains: 'apple' } } |
notEquals | Text, Number, Boolean | Find values where not matching search value | { title: { notEquals: 'apple' }} |
equals | Text, Number, Date, ID, Boolean | Find values matching the search value | { title: { equals: 'orange' }} |
greaterThan | Number | Find values where the value is greater than the search value | { rating: { greaterThan: 5 }} |
greaterThanOrEquals | Number | Find values where the value is greater than or equal to the search value | { rating: { greaterThanOrEquals: 5 }} |
lessThan | Number | Find values where the value is less than the search value | { rating: { lessThan: 5 }} |
lessThanOrEquals | Number | Find values where the value is less than or equal to the search value | { rating: { lessThanOrEquals: 5 }} |
before | Date | Find values where the date is before the search date | { createdAt: { before: new Date(2020, 1, 1) }} |
onOrBefore | Date | Find values where the date is equal to or before the search date | { createdAt: { onOrBefore: new Date(2020, 1, 1) }} |
after | Date | Find values where the date is after the search date | { createdAt: { after: new Date(2020, 1, 1) }} |
onOrAfter | Date | Find values where the date is equal to or after the search date | { createdAt: { onOrAfter: new Date(2020, 1, 1) }} |
Nested Create / Update
The Model API doesn't currently support creating or updating nested relations, but will in the near future.
Until then, you can create related models yourself using the Model API:
import { CreatePost, models } from '@teamkeel/sdk';
export default CreatePost({
beforeWrite: async (ctx, inputs) => {
const {
author: { name }
} = inputs;
// create the new author prior to creating the post
const author = await models.author.create({ name });
return {
...inputs,
authorId: author.id
}
}
});
Rich Data Types
The SDK also provides class implementation for certain field types. These further simplify the interaction with these rich data types:
Field Type | Description | SDK Class |
---|---|---|
Duration | A time interval (ISO 8601 format) | Duration |
File | A file input, supplied as a data URL | File and InlineFile |
Duration
This class provides utility methods for working with durations, such as:
Duration.fromISOString(s)
: Static constructor used to create an instance ofDuration
.toISOString()
: Converts the duration to an ISO 8601 string.toPostgres()
: Converts the duration to PostgreSQL's interval format.
Creating and retrieving records with durations:
import { WriteCustomFunction, models, Duration } from "@teamkeel/sdk";
export default WriteCustomFunction(async (ctx, inputs) => {
const post = await models.post.create({ readTime: Duration.fromISOString("PT1H") });
const readPost = await models.post.findOne({ id: post.id });
return {
readTime: readPost.readTime.toISOString(),
};
});
When using a duration field as an input to a custom function, the input will automatically be an instance of the Duration
class:
message DurationInput {
duration Duration
}
export default DurationInputFunction(async (ctx, inputs) => {
console.log(inputs.duration.toISOString());
const post = await models.post.create({ readTime: inputs.duration });
return {
readTime: post.readTime.toISOString(),
};
});
Duration fields are also returned as an instance of the Duration
class when using the query builder:
const posts = await useDatabase()
.selectFrom("posts")
.selectAll()
.execute();
return {
readTime: posts[0].readTime.toISOString()
};
File
and InlineFile
Keel provides a File
TypeScript class in the functions runtime and full support for reading and writing files, which means that they can be used in read
and write
custom functions, action hooks, jobs and subscriber functions. For more information please refer to the Files documentation.