Photon is a type-safe database client auto-generated based on your data model definition (which is a representation of your database schema). This page explains the generated API operations you have available when using Photon.
- Overview
- CRUD
- Field selection
- Relations
- Raw databases access
- API Reference
- Debugging
- Managing connections
Using Photon typically follows this high-level workflow:
- Define/update your data model definition (e.g. by manually adding a new model or by (re)introspecting your database)
- Generate your Photon database client based on the changes in the data model definition
Your Photon
instance can then be imported from node_modules/@generated
.
Assume you have the following data model definition:
model User {
id Int @id
name String
role Role
posts Post[]
}
model Post {
id Int @id
title String
author User
}
enum Role {
USER
ADMIN
}
Your generated Photon API will expose the following CRUD operations for the User
and Post
models:
You can access each function via the respective model property on your generated Photon
instance, e.g. users
for the User
model:
import { Photon } from '@generated/photon'
const photon = new Photon()
async function main() {
await photon.connect()
const result = await photon.users.findOne({
where: { id: 1 },
})
// result = { id: 1, name: "Alice", role: "USER" }
await photon.disconnect()
}
Note that the name of the users
property is auto-generated using the pluralize
package.
This section explains how to predict and control which fields of a model are returned in a Photon API call.
To understand which fields are being returned by a certain API call, you need to be aware of its selection set.
The selection set defines the set of fields on a model instance that is returned in a Photon API call.
For example, in the findOne
API call from above, the selection set includes the id
, name
and role
fields of the model User
. In that example, the selection set has not been manipulated and the API call therefore returns the default selection set (read below).
If the selection set is not manipulated (via select
or include
), a Photon API call returns the default selection set for a model. It includes all scalar fields (including enums) fields of the model.
Considering the sample datamodel from above:
- The default selection set for the
User
model includesid
,name
,role
. It does not includeposts
because that's a relation and not a scalar field. - The default selection set for the
Post
model includesid
,title
. It does not includeauthor
because that's a relation and not a scalar field.
There are two ways how the default selection set can be manipulated to specify which fields should be returned by a Photon API call:
- Select exclusively (via
select
): When usingselect
, the selection set only contains the fields that are explicitly provided as arguments toselect
. - Include additionally (via
include
): When usinginclude
, the default selection set gets extended with additional fields that are provided as arguments toinclude
.
In this example, we're using select
to exclusively select the name
field of the returned User
object:
const result = await photon.users.findOne({
where: { id: 1 },
select: { name: true },
})
// result = { name: "Alice" }
Sometimes you want to directly include a relation when retrieving data from a database. To eagerly load and include the relations of a model in an API call right away, you can use include
:
const result = await photon.users.findOne({
where: { id: 1 },
include: { posts: true },
})
// result = {
// id: 1,
// name: "Alice",
// role: "USER",
// posts: [
// { id: 1, title: "Hello World"},
// ]
// }
Coming soon.
Learn more about relations in the generated Photon API here.
Coming soon.
For simplicity, we're assuming the User
model from above as foundation for the generated code.
Creates a new Photon
instance.
Name | Type | Required | Description |
---|---|---|---|
debug |
boolean |
No | When set to true , the Photon instance prints additional logging output to the console when sending requests to Prisma's query engine. Default: false . |
datasources |
Datasources |
No | Lets you override the connection string for a data source. The keys of the datasources object are autogenerated and correspond to the names to the data sources specified in your Prisma schema file. |
const photon = new Photon({ debug: true })
Returns a single object identified by a unique value (e.g. id
or email
). You can use the select
and include
arguments to determine which fields should be included on the returned object.
Name | Type | Required | Description |
---|---|---|---|
where |
UserWhereUniqueInput |
Yes | Wraps all unique fields of a model so that individual records can be selected. |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.findOne({
where: { id: 1 },
})
Returns a list of objects. The list can be altered using pagination, filtering and ordering arguments. You can use the select
and include
arguments to determine which fields should be included on each object in the returned list.
For more filtering examples, look here.
Name | Type | Required | Description |
---|---|---|---|
where |
UserWhereInput |
No | Wraps all fields of a model so that the list can be filtered by any model property. |
orderBy |
UserOrderByInput |
No | Lets you order the returned list by any model property. |
skip |
string |
No | Specifies how many of the returned objects in the list should be skipped. |
after |
string |
No | Specifies the starting object for the list (the value typically specifies an id or another unique value). |
before |
string |
No | Specifies the last object for the list (the value typically specifies an id or another unique value). |
first |
number |
No | Specifies how many elements should be returned in the list (as seen from the beginning of the list). |
last |
number |
No | Specifies how many elements should be returned in the list (as seen from the end of the list). |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.findMany({
where: { name: 'Alice' },
})
Creates a new record and returns the corresponding object. You can use the select
and include
arguments to determine which fields should be included on the returned object. create
also lets you perform transactional nested inserts (e.g. create a new User
and Post
in the same API call).
Name | Type | Required | Description |
---|---|---|---|
data |
UserCreateInput |
Yes | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional on data . |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.create({
data: { name: 'Alice' },
})
Updates an existing record and returns the corresponding object. You can use the select
and include
arguments to determine which fields should be included on the returned object.
Name | Type | Required | Description |
---|---|---|---|
data |
UserUpdateInput |
Yes | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on data . |
where |
UserWhereUniqueInput |
Yes | Wraps all unique fields of a model so that individual records can be selected. |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.update({
where: { id: 1 },
data: { name: 'ALICE' },
})
Updates a batch of existing records in bulk and returns the number of updated records.
Name | Type | Required | Description |
---|---|---|---|
data |
UserUpdateManyMutationInput |
Yes | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on data . |
where |
UserWhereInput |
No | Wraps all fields of a model so that the list can be filtered by any model property. |
const updatedUserCount = await photon.users.updateMany({
where: { name: 'Alice' },
data: { name: 'ALICE' },
})
Updates an existing or creates a new record and returns the corresponding object. You can use the select
and include
arguments to determine which fields should be included on the returned object.
Name | Type | Required | Description |
---|---|---|---|
create |
UserCreateInput |
Yes | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional on data . |
update |
UserUpdateInput |
Yes | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on data . |
where |
UserWhereUniqueInput |
Yes | Wraps all unique fields of a model so that individual records can be selected. |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.upsert({
where: { id: 1 },
update: { name: "ALICE" }
create: { name: "ALICE" }
})
Deletes an existing record and returns the corresponding object. You can use the select
and include
arguments to determine which fields should be included on the returned object.
Name | Type | Required | Description |
---|---|---|---|
where |
UserWhereUniqueInput |
Yes | Wraps all unique fields of a model so that individual records can be selected. |
select |
UserSelect |
No | Specifies which fields to include in the selection set. |
const user = await photon.users.delete({
where: { id: 1 },
})
Deletes a batch of existing records in bulk and returns the number of deleted records.
Name | Type | Required | Description |
---|---|---|---|
where |
UserWhereInput |
No | Wraps all fields of a model so that the list can be filtered by any model property. |
const deletedUserCount = await photon.users.deleteMany({
where: { name: 'Alice' },
})
select
and include
is for specifying what to retrieve from the Photon API call (think 'SELECT' statement from SQL), whereas the filtering API (where
) is for filtering the arguments to the call (think 'WHERE' clause from SQL).
The following examples are based from this data model:
model User {
id Int @id
name String
email String
role String
active Boolean
}
enum Role {
USER
ADMIN
}
Using the `select` API on this data model
The `select` API is used to retrieve the `name` column of this `User` database.const result = await photon.users.findMany({
select: { name: "Alice" },
})
// result = {
// name: "Alice",
// }
Filtering can be applied to this data model. It is not the same as manipulating the selection set. Based on the User
model, Photon generates the UserWhereInput
type, which holds the filtering properties.
export declare type UserWhereInput = {
id?: number | IntFilter | null;
name?: string | StringFilter | null;
email?: string | StringFilter | null;
role?: Role | RoleFilter | null;
active?: boolean | BooleanFilter | null;
AND?: Enumerable<UserWhereInput>;
OR?: Enumerable<UserWhereInput>;
NOT?: Enumerable<UserWhereInput>;
};
For example, to get the record for the user with the id
1, where
is used in combination with the id
IntFilter
:
const result = await photon.users.findMany({
where: { id: 1 },
})
// result = {
// id: 1,
// name: "Alice",
// email: "[email protected]",
// role: "USER",
// active: true
// }
Note: As a recap, the
findMany
API returns a list of objects which can be filtered by any model property.
To get the record for the user with the name
Alice with a USER role
, where
is used in combination with the name
StringFilter
and the role
RoleFilter
:
const result = await photon.users.findMany({
where: {
name: "Alice",
role: "USER",
},
})
// result = {
// id: 1,
// name: "Alice",
// email: "[email protected]",
// role: "USER",
// active: true
// }
To apply one of the operator filters (AND, OR, NOT), filter for the record where the user with the name
Alice has a non-active status. Here, where
is used in combination with the name
StringFilter
, the active
BooleanFilter
, and the NOT
operator:
const result = await photon.users.findMany({
where: {
name: "Alice",
NOT:{
active: true
}
},
})
// result = {
//
// }
You can view the generated database queries that Photon sends to your database by setting the debug
option to true
when instantiating Photon
:
const photon = new Photon({ debug: true })
Photon connects and disconnects from your data sources using the following two methods:
connect(): Promise<void>
disconnect(): Promise<void>
Unless you want to employ a specific optimization, calling photon.connect()
is not necessary thanks to the lazy connect behavior: The Photon
instance connects lazily when the first request is made to the API (connect()
is called for you under the hood).
If you need the first request to respond instantly and can't wait for the lazy connection to be established, you can explicitly call photon.connect()
to establish a connection to the data source.
IMPORTANT: It is recommended to always explicitly call photon.disconnect()
in your code. Generally the Photon
instance disconnects automatically. However, if your program terminates but still has an unhandled promise rejection, the port will keep the connection to the data source open beyond the lifetime of your program!