Skip to main content

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

tip

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

Advanced concepts