overview
Dream, which can be found at https://github.com/rvohealth/dream, is a custom ORM that provides the heartbeat of our framework. Psychic was built around and alongside this ORM, with the intention of providing powerful web bindings to couple with the ORM and make developing backend or fullstack applications absolutely seamless.
Since most web applications will require a database, Dream is the tool for abstracting the interaction with the database. Using conventional active record patterns, Dream leverages models to hold the individual values stored within the database, creating a powerful bridge between the types held in the database and the properties designated to the model.
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable('users')
.addColumn('id', 'bigserial', col => col.primaryKey())
.addColumn('email', 'varchar(64)')
.addColumn('created_at', 'timestamp', col => col.notNull())
.addColumn('updated_at', 'timestamp', col => col.notNull())
.execute()
}
class User extends ApplicationModel {
public id: DreamColumn<User, 'id'> // string
public email: DreamColumn<User, 'email'> // string | null
public createdAt: DreamColumn<User, 'createdAt'> // DateTime
public updatedAt: DreamColumn<User, 'updatedAt'> // DateTime
}
With migrations run, and the above model in place, you can begin leveraging some of the powerful methods built into Dream to simplify your interactions with the database.
const user = await User.create({ email: 'how@yadoin' })
user.email // 'how@yadoin'
await User.all()
// [User{ email: 'how@yadoin' }]
generators
Use generators to quickly prop up the scaffolding for your application. Using the provided CLI utils, you can customize the shape of your models without writing a line of code.
yarn psy g:dream User name:string email:string birthdate:date
yarn psy g:dream Post user:belongs_to body:string
To learn more about generators, see our generating guide.
Querying records
Searching your database has never been so intuitive using the suite of Dream tools provided.
// find many records by condition
const users = await User.where({ email: null }).whereNot({ name: null }).order('createdAt').all()
// find first record, or null if not found
const user = await User.order('createdAt').first()
// find first record, or raise exception. Psychic will
// automatically raise a 404 if this exception is thrown.
const user = await User.order('createdAt').firstOrFail()
To learn how to query records, see our creating guide
Creating new records
Tap into the underlying power of Dream to insert new records into your database
// create in one call
await User.create({ email: 'how@yadoin' })
// build and save
const user = User.new({ email: 'how@yadoin' })
if (something) {
user.name = 'chalupajoe'
}
await user.save()
// attempts to create, but if it runs into a foreign key
// violation, it returns the violating record instead.
// requires a unique index on the column you are looking up
await User.createOrFindBy({ email: 'how@yadoin' }, { createWith: { name: 'chalupajoe' } })
To learn how to create new records, see our creating guide
Updating existing records
With records that are already in the database, making changes to that data is made trivial by Dream.
// in a single call
await user.update({ email: 'how@yadoin' })
// build and save
if (something) {
user.name = 'chalupajoe'
}
await user.save()
To learn how to update records, see our updating guide.
Destroying
With records that are already in the database, making changes to that data is made trivial by Dream.
// in a single call
await user.destroy()
// in a bulk query
await User.where({ email: ops.ilike('%burpcollaborator%') }).destroy()
To learn how to delete records, see our destroying guide.
Associations
Take advantage of powerful association mechanisms within Dream to forge relationships between your models
class Post extends ApplicationModel {
@deco.BelongsTo('User')
public user: User
@deco.HasMany('Comment')
public comments: Comment[]
@deco.HasMany('Comment', { through: 'comments', source: 'replies' })
public replies: Comment[]
}
To learn how to build associations, see our associations guide
Validations
Use validations to ensure the integrity of data entering your system, empowering psychic to automatically raise clean validation errors to the client in contexts where these validation criterion fail.
class User extends ApplicationModel {
@deco.Validates('contains', '@')
@deco.Validates('length', { min: 4 })
public email: DreamColumn<User, 'email'>
@deco.Validates('numericality', { min: 1, max: 5 })
public numCoachingSessions: DreamColumn<User, 'numCoachingSessions'>
}
To learn how to leverage validations, see our validations guide
Dream provides a rich set of features for interacting with your database. We have only begun to get into it here, so we encourage you to explore the model guides to learn more.
Basic model interactions
- generating guide
- querying guide
- creating guide
- updating guide
- destroying guide
- associations guide
- validations guide