Deepkit ORM

Raw Access

It's often necessary to access the database directly, for example to run a SQL query that is not supported by the ORM. This can be done using the raw method on the Database class.

import { PrimaryKey, AutoIncrement, @entity } from '@deepkit/type';
import { Database } from '@deepkit/orm';
import { sql } from '@deepkit/sql';
import { SqliteDatabaseAdapter } from '@deepkit/sqlite';

@entity.collection('users')
class User {
    id: number & PrimaryKey & AutoIncrement = 0;
    created: Date = new Date;
    constructor(public username: string) {}
}

const database = new Database(new SQLiteDatabaseAdapter(':memory:'), [User]);

const query = 'Pet%';
const rows = await database.raw<User>(sql`SELECT * FROM users WHERE username LIKE ${query}`).find();

const result = await database.raw<{ count: number }>(sql`SELECT count(*) as count FROM users WHERE username LIKE ${query}`).findOne();
console.log('Found', result.count, 'users');

The SQL query is built using the sql template string tag. This is a special template string tag that allows to pass values as parameters. These parameters are then automatically parsed and converted to a safe prepared statement. This is important to avoid SQL injection attacks.

To pass a dynamic identifier like a column name, identifier can be used:

import { identifier, sql } from '@deepkit/sql';

let column = 'username';
const rows = await database.raw<User>(sql`SELECT * FROM users WHERE ${identifier(column)} LIKE ${query}`).find();

For SQL adapters, the raw method returns an RawQuery with findOne and find methods to retrieve the results. To execute a SQL without returning rows like UPDATE/DELETE/etc, execute can be used:

let username = 'Peter';
await database.raw(sql`UPDATE users SET username = ${username} WHERE id = 1`).execute();

RawQuery also supports getting the final SQL string and parameters, correctly formatted for the database adapter:

const query = database.raw(sql`SELECT * FROM users WHERE username LIKE ${query}`);
console.log(query.sql);
console.log(query.params);

This way the SQL can be used to execute it in a different database client, for example.

Types

Note that you can pass any type to raw and the result from the database will be automatically converted to that type. This is especially useful for SQL adapters, where you can pass a class and the result will be automatically converted to that class.

This has limitations though. SQL Joins are not supported this way. If you want to use joins, you have to use the ORM's query builder.

Mongo

MongoDB adapter works a bit different since it's not based on SQL queries but on Mongo commands.

A command could be an aggregation pipeline, a find query, or a write command.