@mikro-orm/pglite 7.0.18-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/PgliteConnection.d.ts +10 -0
- package/PgliteConnection.js +77 -0
- package/PgliteDriver.d.ts +12 -0
- package/PgliteDriver.js +20 -0
- package/PgliteMikroORM.d.ts +20 -0
- package/PgliteMikroORM.js +26 -0
- package/PglitePlatform.d.ts +16 -0
- package/PglitePlatform.js +45 -0
- package/PgliteSchemaHelper.d.ts +12 -0
- package/PgliteSchemaHelper.js +19 -0
- package/README.md +226 -0
- package/index.d.ts +7 -0
- package/index.js +7 -0
- package/package.json +67 -0
- package/raw.d.ts +67 -0
- package/raw.js +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Martin Adámek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PGliteDialect } from 'kysely';
|
|
2
|
+
import { AbstractSqlConnection, type Dictionary } from '@mikro-orm/sql';
|
|
3
|
+
/** PostgreSQL-in-WASM database connection using `@electric-sql/pglite`. */
|
|
4
|
+
export declare class PgliteConnection extends AbstractSqlConnection {
|
|
5
|
+
#private;
|
|
6
|
+
createKyselyDialect(overrides: Dictionary): PGliteDialect;
|
|
7
|
+
close(force?: boolean): Promise<void>;
|
|
8
|
+
/** PGlite supports multi-statement scripts via `exec()`, which is what schema dumps need. */
|
|
9
|
+
executeDump(source: string): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { PGlite } from '@electric-sql/pglite';
|
|
2
|
+
import { PGliteDialect } from 'kysely';
|
|
3
|
+
import array from 'postgres-array';
|
|
4
|
+
import { AbstractSqlConnection, createPostgreSqlTypeParsers } from '@mikro-orm/sql';
|
|
5
|
+
const isInMemoryDataDir = (dataDir) => !dataDir || dataDir === 'memory://' || dataDir.startsWith('memory:');
|
|
6
|
+
/** PostgreSQL-in-WASM database connection using `@electric-sql/pglite`. */
|
|
7
|
+
export class PgliteConnection extends AbstractSqlConnection {
|
|
8
|
+
// Stored as a Promise so `createKyselyDialect` can stay synchronous (else
|
|
9
|
+
// `getClient()` would throw "Current driver requires async initialization")
|
|
10
|
+
// while `executeDump` and the kysely dialect both `await` the same instance.
|
|
11
|
+
#pglite;
|
|
12
|
+
#neuterClose = false;
|
|
13
|
+
#ownsPglite = true;
|
|
14
|
+
createKyselyDialect(overrides) {
|
|
15
|
+
const onCreateConnection = this.options.onCreateConnection ?? this.config.get('onCreateConnection');
|
|
16
|
+
const options = (overrides ?? {});
|
|
17
|
+
const { pglite: userPglite, ...pgliteOptions } = options;
|
|
18
|
+
const dataDir = options.dataDir ?? this.config.get('dbName');
|
|
19
|
+
const parsers = { ...createPostgreSqlTypeParsers(s => array.parse(s)), ...options.parsers };
|
|
20
|
+
this.#ownsPglite = !userPglite;
|
|
21
|
+
// Skip `pglite.close()` (called by kysely's `PGliteDriver.destroy()`) when:
|
|
22
|
+
// - the user owns the instance (closing it is their responsibility), or
|
|
23
|
+
// - we hold an in-memory DB whose data would otherwise be lost on
|
|
24
|
+
// reconnect (e.g. test harnesses that drive `orm.close()` + `orm.connect()`).
|
|
25
|
+
// For file/IDB-backed instances we let kysely close so file handles / IDB
|
|
26
|
+
// connections are released; we drop our cached promise in `close()` below
|
|
27
|
+
// so the next dialect-construction rebuilds the PGlite instance.
|
|
28
|
+
this.#neuterClose = !this.#ownsPglite || isInMemoryDataDir(dataDir);
|
|
29
|
+
if (!this.#pglite) {
|
|
30
|
+
if (userPglite) {
|
|
31
|
+
this.#pglite = typeof userPglite === 'function' ? Promise.resolve(userPglite()) : Promise.resolve(userPglite);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.#pglite = PGlite.create({ ...pgliteOptions, dataDir, parsers });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (this.#neuterClose) {
|
|
38
|
+
// Hand kysely a delegating wrapper rather than mutating the underlying
|
|
39
|
+
// instance — proxies can't pierce PGlite's private fields, and patching
|
|
40
|
+
// `close` directly would orphan a user-supplied PGlite (its real `close`
|
|
41
|
+
// would stay neutered after `orm.close()`). Each method call hits the
|
|
42
|
+
// original `p`, so `#private` fields stay reachable.
|
|
43
|
+
const sharedPglitePromise = this.#pglite.then(p => ({
|
|
44
|
+
query: p.query.bind(p),
|
|
45
|
+
transaction: p.transaction.bind(p),
|
|
46
|
+
close: () => Promise.resolve(),
|
|
47
|
+
get closed() {
|
|
48
|
+
return p.closed;
|
|
49
|
+
},
|
|
50
|
+
get ready() {
|
|
51
|
+
return p.ready;
|
|
52
|
+
},
|
|
53
|
+
// `waitReady` is a stable Promise on the underlying instance — capture it
|
|
54
|
+
// directly so coverage doesn't hinge on `kysely` actually awaiting it (which
|
|
55
|
+
// only happens in the WASM-not-yet-loaded transient window).
|
|
56
|
+
waitReady: p.waitReady,
|
|
57
|
+
}));
|
|
58
|
+
return new PGliteDialect({ pglite: () => sharedPglitePromise, onCreateConnection });
|
|
59
|
+
}
|
|
60
|
+
return new PGliteDialect({ pglite: () => this.#pglite, onCreateConnection });
|
|
61
|
+
}
|
|
62
|
+
async close(force) {
|
|
63
|
+
await super.close(force);
|
|
64
|
+
// Persistent backings (file/IDB) we own get really closed by kysely — drop
|
|
65
|
+
// the cached promise so a subsequent reconnect rebuilds a fresh instance
|
|
66
|
+
// (which then re-reads the persisted data from disk / IDB).
|
|
67
|
+
if (this.#ownsPglite && !this.#neuterClose) {
|
|
68
|
+
this.#pglite = undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** PGlite supports multi-statement scripts via `exec()`, which is what schema dumps need. */
|
|
72
|
+
async executeDump(source) {
|
|
73
|
+
await this.ensureConnection();
|
|
74
|
+
const pglite = await this.#pglite;
|
|
75
|
+
await pglite.exec(source);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Configuration, type Constructor, EntityManagerType } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractSqlDriver, BasePostgreSqlEntityManager } from '@mikro-orm/sql';
|
|
3
|
+
import { PgliteConnection } from './PgliteConnection.js';
|
|
4
|
+
import { PgliteMikroORM } from './PgliteMikroORM.js';
|
|
5
|
+
/** Database driver for PGlite (PostgreSQL in WASM). */
|
|
6
|
+
export declare class PgliteDriver extends AbstractSqlDriver<PgliteConnection> {
|
|
7
|
+
[EntityManagerType]: BasePostgreSqlEntityManager<this>;
|
|
8
|
+
constructor(config: Configuration);
|
|
9
|
+
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
10
|
+
/** @inheritDoc */
|
|
11
|
+
getORMClass(): Constructor<PgliteMikroORM>;
|
|
12
|
+
}
|
package/PgliteDriver.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EntityManagerType } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractSqlDriver, BasePostgreSqlEntityManager } from '@mikro-orm/sql';
|
|
3
|
+
import { PgliteConnection } from './PgliteConnection.js';
|
|
4
|
+
import { PglitePlatform } from './PglitePlatform.js';
|
|
5
|
+
import { PgliteMikroORM } from './PgliteMikroORM.js';
|
|
6
|
+
/** Database driver for PGlite (PostgreSQL in WASM). */
|
|
7
|
+
export class PgliteDriver extends AbstractSqlDriver {
|
|
8
|
+
[EntityManagerType];
|
|
9
|
+
constructor(config) {
|
|
10
|
+
super(config, new PglitePlatform(), PgliteConnection, ['kysely', '@electric-sql/pglite']);
|
|
11
|
+
}
|
|
12
|
+
createEntityManager(useContext) {
|
|
13
|
+
const EntityManagerClass = this.config.get('entityManager', BasePostgreSqlEntityManager);
|
|
14
|
+
return new EntityManagerClass(this.config, this, this.metadata, useContext);
|
|
15
|
+
}
|
|
16
|
+
/** @inheritDoc */
|
|
17
|
+
getORMClass() {
|
|
18
|
+
return PgliteMikroORM;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AnyEntity, type EntityClass, type EntitySchema, type MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType } from '@mikro-orm/core';
|
|
2
|
+
import { SqlMikroORM, type BasePostgreSqlEntityManager } from '@mikro-orm/sql';
|
|
3
|
+
import { PgliteDriver } from './PgliteDriver.js';
|
|
4
|
+
/** Configuration options for the PGlite driver. */
|
|
5
|
+
export type PgliteOptions<EM extends BasePostgreSqlEntityManager<PgliteDriver> = BasePostgreSqlEntityManager<PgliteDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Partial<Options<PgliteDriver, EM, Entities>>;
|
|
6
|
+
/** Creates a type-safe configuration object for the PGlite driver. */
|
|
7
|
+
export declare function definePgliteConfig<EM extends BasePostgreSqlEntityManager<PgliteDriver> = BasePostgreSqlEntityManager<PgliteDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: PgliteOptions<EM, Entities>): PgliteOptions<EM, Entities>;
|
|
8
|
+
/**
|
|
9
|
+
* @inheritDoc
|
|
10
|
+
*/
|
|
11
|
+
export declare class PgliteMikroORM<EM extends BasePostgreSqlEntityManager<PgliteDriver> = BasePostgreSqlEntityManager<PgliteDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends SqlMikroORM<PgliteDriver, EM, Entities> {
|
|
12
|
+
/**
|
|
13
|
+
* @inheritDoc
|
|
14
|
+
*/
|
|
15
|
+
static init<D extends IDatabaseDriver = PgliteDriver, EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
|
|
16
|
+
/**
|
|
17
|
+
* @inheritDoc
|
|
18
|
+
*/
|
|
19
|
+
constructor(options: Partial<Options<PgliteDriver, EM, Entities>>);
|
|
20
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig, } from '@mikro-orm/core';
|
|
2
|
+
import { SqlMikroORM } from '@mikro-orm/sql';
|
|
3
|
+
import { PgliteDriver } from './PgliteDriver.js';
|
|
4
|
+
/** Creates a type-safe configuration object for the PGlite driver. */
|
|
5
|
+
export function definePgliteConfig(options) {
|
|
6
|
+
// PGlite defaults to in-memory storage; satisfy MikroORM's `dbName` validation
|
|
7
|
+
// without forcing every user to spell it out.
|
|
8
|
+
return defineConfig({ driver: PgliteDriver, dbName: 'memory://', ...options });
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* @inheritDoc
|
|
12
|
+
*/
|
|
13
|
+
export class PgliteMikroORM extends SqlMikroORM {
|
|
14
|
+
/**
|
|
15
|
+
* @inheritDoc
|
|
16
|
+
*/
|
|
17
|
+
static async init(options) {
|
|
18
|
+
return super.init(definePgliteConfig(options));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @inheritDoc
|
|
22
|
+
*/
|
|
23
|
+
constructor(options) {
|
|
24
|
+
super(definePgliteConfig(options));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type IPostgresInterval } from 'postgres-interval';
|
|
2
|
+
import { BasePostgreSqlPlatform } from '@mikro-orm/sql';
|
|
3
|
+
import { PgliteSchemaHelper } from './PgliteSchemaHelper.js';
|
|
4
|
+
/** Platform implementation for PGlite (PostgreSQL in WASM, single-database). */
|
|
5
|
+
export declare class PglitePlatform extends BasePostgreSqlPlatform {
|
|
6
|
+
protected readonly schemaHelper: PgliteSchemaHelper;
|
|
7
|
+
/** PGlite uses the extended query protocol — one statement per `query()` call. */
|
|
8
|
+
supportsMultipleStatements(): boolean;
|
|
9
|
+
convertIntervalToJSValue(value: string): unknown;
|
|
10
|
+
convertIntervalToDatabaseValue(value: IPostgresInterval): unknown;
|
|
11
|
+
unmarshallArray(value: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* @inheritDoc
|
|
14
|
+
*/
|
|
15
|
+
parseDate(value: string | number): Date;
|
|
16
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import array from 'postgres-array';
|
|
2
|
+
import parseDate from 'postgres-date';
|
|
3
|
+
import PostgresInterval from 'postgres-interval';
|
|
4
|
+
import { BasePostgreSqlPlatform, Utils } from '@mikro-orm/sql';
|
|
5
|
+
import { PgliteSchemaHelper } from './PgliteSchemaHelper.js';
|
|
6
|
+
/** Platform implementation for PGlite (PostgreSQL in WASM, single-database). */
|
|
7
|
+
export class PglitePlatform extends BasePostgreSqlPlatform {
|
|
8
|
+
schemaHelper = new PgliteSchemaHelper(this);
|
|
9
|
+
/** PGlite uses the extended query protocol — one statement per `query()` call. */
|
|
10
|
+
supportsMultipleStatements() {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
convertIntervalToJSValue(value) {
|
|
14
|
+
return PostgresInterval(value);
|
|
15
|
+
}
|
|
16
|
+
convertIntervalToDatabaseValue(value) {
|
|
17
|
+
if (Utils.isObject(value) && 'toPostgres' in value && typeof value.toPostgres === 'function') {
|
|
18
|
+
return value.toPostgres();
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
unmarshallArray(value) {
|
|
23
|
+
return array.parse(value);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @inheritDoc
|
|
27
|
+
*/
|
|
28
|
+
parseDate(value) {
|
|
29
|
+
// postgres-date returns `null` for a JS ISO string which has the `T` separator
|
|
30
|
+
if (typeof value === 'string' && value.charAt(10) === 'T') {
|
|
31
|
+
return new Date(value);
|
|
32
|
+
}
|
|
33
|
+
/* v8 ignore next */
|
|
34
|
+
if (typeof value === 'number') {
|
|
35
|
+
return new Date(value);
|
|
36
|
+
}
|
|
37
|
+
// @ts-ignore fix wrong type resolution during build
|
|
38
|
+
const parsed = parseDate(value);
|
|
39
|
+
/* v8 ignore next */
|
|
40
|
+
if (parsed === null) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Connection } from '@mikro-orm/core';
|
|
2
|
+
import { PostgreSqlSchemaHelper } from '@mikro-orm/sql';
|
|
3
|
+
/**
|
|
4
|
+
* PGlite is a single-database engine — there is no management catalog and no
|
|
5
|
+
* `CREATE DATABASE`. Override the relevant lifecycle hooks to no-ops.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PgliteSchemaHelper extends PostgreSqlSchemaHelper {
|
|
8
|
+
getManagementDbName(): string;
|
|
9
|
+
getCreateDatabaseSQL(): string;
|
|
10
|
+
getDropDatabaseSQL(): string;
|
|
11
|
+
databaseExists(_connection: Connection, _name: string): Promise<boolean>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PostgreSqlSchemaHelper } from '@mikro-orm/sql';
|
|
2
|
+
/**
|
|
3
|
+
* PGlite is a single-database engine — there is no management catalog and no
|
|
4
|
+
* `CREATE DATABASE`. Override the relevant lifecycle hooks to no-ops.
|
|
5
|
+
*/
|
|
6
|
+
export class PgliteSchemaHelper extends PostgreSqlSchemaHelper {
|
|
7
|
+
getManagementDbName() {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
getCreateDatabaseSQL() {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
getDropDatabaseSQL() {
|
|
14
|
+
return '';
|
|
15
|
+
}
|
|
16
|
+
async databaseExists(_connection, _name) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL (including CockroachDB and PGlite), SQLite (including libSQL), MSSQL and Oracle databases.
|
|
6
|
+
|
|
7
|
+
> Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
|
|
8
|
+
|
|
9
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
10
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
11
|
+
[](https://discord.gg/w8bjxFHS7X)
|
|
12
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
13
|
+
[](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
|
|
14
|
+
[](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
Install a driver package for your database:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install @mikro-orm/postgresql # PostgreSQL
|
|
22
|
+
npm install @mikro-orm/pglite # PGlite (embedded PostgreSQL in WASM)
|
|
23
|
+
npm install @mikro-orm/mysql # MySQL
|
|
24
|
+
npm install @mikro-orm/mariadb # MariaDB
|
|
25
|
+
npm install @mikro-orm/sqlite # SQLite
|
|
26
|
+
npm install @mikro-orm/libsql # libSQL / Turso
|
|
27
|
+
npm install @mikro-orm/mongodb # MongoDB
|
|
28
|
+
npm install @mikro-orm/mssql # MS SQL Server
|
|
29
|
+
npm install @mikro-orm/oracledb # Oracle
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> If you use additional packages like `@mikro-orm/cli`, `@mikro-orm/migrations`, or `@mikro-orm/entity-generator`, install `@mikro-orm/core` explicitly as well. See the [quick start guide](https://mikro-orm.io/docs/quick-start) for details.
|
|
33
|
+
|
|
34
|
+
### Define Entities
|
|
35
|
+
|
|
36
|
+
The recommended way to define entities is using [`defineEntity`](https://mikro-orm.io/docs/define-entity) with `setClass`:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { defineEntity, p, MikroORM } from '@mikro-orm/postgresql';
|
|
40
|
+
|
|
41
|
+
const AuthorSchema = defineEntity({
|
|
42
|
+
name: 'Author',
|
|
43
|
+
properties: {
|
|
44
|
+
id: p.integer().primary(),
|
|
45
|
+
name: p.string(),
|
|
46
|
+
email: p.string(),
|
|
47
|
+
born: p.datetime().nullable(),
|
|
48
|
+
books: () => p.oneToMany(Book).mappedBy('author'),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export class Author extends AuthorSchema.class {}
|
|
53
|
+
AuthorSchema.setClass(Author);
|
|
54
|
+
|
|
55
|
+
const BookSchema = defineEntity({
|
|
56
|
+
name: 'Book',
|
|
57
|
+
properties: {
|
|
58
|
+
id: p.integer().primary(),
|
|
59
|
+
title: p.string(),
|
|
60
|
+
author: () => p.manyToOne(Author).inversedBy('books'),
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export class Book extends BookSchema.class {}
|
|
65
|
+
BookSchema.setClass(Book);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also define entities using [decorators](https://mikro-orm.io/docs/using-decorators) or [`EntitySchema`](https://mikro-orm.io/docs/define-entity#entityschema-low-level-api). See the [defining entities guide](https://mikro-orm.io/docs/defining-entities) for all options.
|
|
69
|
+
|
|
70
|
+
### Initialize and Use
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { MikroORM, RequestContext } from '@mikro-orm/postgresql';
|
|
74
|
+
|
|
75
|
+
const orm = await MikroORM.init({
|
|
76
|
+
entities: [Author, Book],
|
|
77
|
+
dbName: 'my-db',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Create new entities
|
|
81
|
+
const author = orm.em.create(Author, {
|
|
82
|
+
name: 'Jon Snow',
|
|
83
|
+
email: 'snow@wall.st',
|
|
84
|
+
});
|
|
85
|
+
const book = orm.em.create(Book, {
|
|
86
|
+
title: 'My Life on The Wall',
|
|
87
|
+
author,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Flush persists all tracked changes in a single transaction
|
|
91
|
+
await orm.em.flush();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Querying
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Find with relations
|
|
98
|
+
const authors = await orm.em.findAll(Author, {
|
|
99
|
+
populate: ['books'],
|
|
100
|
+
orderBy: { name: 'asc' },
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Type-safe QueryBuilder
|
|
104
|
+
const qb = orm.em.createQueryBuilder(Author);
|
|
105
|
+
const result = await qb
|
|
106
|
+
.select('*')
|
|
107
|
+
.where({ books: { title: { $like: '%Wall%' } } })
|
|
108
|
+
.getResult();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Request Context
|
|
112
|
+
|
|
113
|
+
In web applications, use `RequestContext` to isolate the identity map per request:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const app = express();
|
|
117
|
+
|
|
118
|
+
app.use((req, res, next) => {
|
|
119
|
+
RequestContext.create(orm.em, next);
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
More info about `RequestContext` is described [here](https://mikro-orm.io/docs/identity-map/#request-context).
|
|
124
|
+
|
|
125
|
+
## Unit of Work
|
|
126
|
+
|
|
127
|
+
> Unit of Work maintains a list of objects (_entities_) affected by a business transaction
|
|
128
|
+
> and coordinates the writing out of changes. [(Martin Fowler)](https://www.martinfowler.com/eaaCatalog/unitOfWork.html)
|
|
129
|
+
|
|
130
|
+
When you call `em.flush()`, all computed changes are queried inside a database transaction. This means you can control transaction boundaries simply by making changes to your entities and calling `flush()` when ready.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const author = await em.findOneOrFail(Author, 1, {
|
|
134
|
+
populate: ['books'],
|
|
135
|
+
});
|
|
136
|
+
author.name = 'Jon Snow II';
|
|
137
|
+
author.books.getItems().forEach(book => book.title += ' (2nd ed.)');
|
|
138
|
+
author.books.add(orm.em.create(Book, { title: 'New Book', author }));
|
|
139
|
+
|
|
140
|
+
// Flush computes change sets and executes them in a single transaction
|
|
141
|
+
await em.flush();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The above flush will execute:
|
|
145
|
+
|
|
146
|
+
```sql
|
|
147
|
+
begin;
|
|
148
|
+
update "author" set "name" = 'Jon Snow II' where "id" = 1;
|
|
149
|
+
update "book"
|
|
150
|
+
set "title" = case
|
|
151
|
+
when ("id" = 1) then 'My Life on The Wall (2nd ed.)'
|
|
152
|
+
when ("id" = 2) then 'Another Book (2nd ed.)'
|
|
153
|
+
else "title" end
|
|
154
|
+
where "id" in (1, 2);
|
|
155
|
+
insert into "book" ("title", "author_id") values ('New Book', 1);
|
|
156
|
+
commit;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Core Features
|
|
160
|
+
|
|
161
|
+
- [Clean and Simple Entity Definition](https://mikro-orm.io/docs/defining-entities) — decorators, `EntitySchema`, or `defineEntity`
|
|
162
|
+
- [Identity Map](https://mikro-orm.io/docs/identity-map) and [Unit of Work](https://mikro-orm.io/docs/unit-of-work) — automatic change tracking
|
|
163
|
+
- [Entity References](https://mikro-orm.io/docs/entity-references) and [Collections](https://mikro-orm.io/docs/collections)
|
|
164
|
+
- [QueryBuilder](https://mikro-orm.io/docs/query-builder) and [Kysely Integration](https://mikro-orm.io/docs/kysely)
|
|
165
|
+
- [Transactions](https://mikro-orm.io/docs/transactions) and [Cascading](https://mikro-orm.io/docs/cascading)
|
|
166
|
+
- [Populating Relations](https://mikro-orm.io/docs/populating-relations) and [Loading Strategies](https://mikro-orm.io/docs/loading-strategies)
|
|
167
|
+
- [Filters](https://mikro-orm.io/docs/filters) and [Lifecycle Hooks](https://mikro-orm.io/docs/events#hooks)
|
|
168
|
+
- [Schema Generator](https://mikro-orm.io/docs/schema-generator) and [Migrations](https://mikro-orm.io/docs/migrations)
|
|
169
|
+
- [Entity Generator](https://mikro-orm.io/docs/entity-generator) and [Seeding](https://mikro-orm.io/docs/seeding)
|
|
170
|
+
- [Embeddables](https://mikro-orm.io/docs/embeddables), [Custom Types](https://mikro-orm.io/docs/custom-types), and [Serialization](https://mikro-orm.io/docs/serializing)
|
|
171
|
+
- [Composite and Foreign Keys as Primary Key](https://mikro-orm.io/docs/composite-keys)
|
|
172
|
+
- [Entity Constructors](https://mikro-orm.io/docs/entity-constructors) and [Property Validation](https://mikro-orm.io/docs/property-validation)
|
|
173
|
+
- [Modelling Relationships](https://mikro-orm.io/docs/relationships) and [Vanilla JS Support](https://mikro-orm.io/docs/usage-with-js)
|
|
174
|
+
|
|
175
|
+
## Documentation
|
|
176
|
+
|
|
177
|
+
MikroORM documentation, included in this repo in the root directory, is built with [Docusaurus](https://docusaurus.io) and publicly hosted on GitHub Pages at https://mikro-orm.io.
|
|
178
|
+
|
|
179
|
+
There is also auto-generated [CHANGELOG.md](CHANGELOG.md) file based on commit messages (via `semantic-release`).
|
|
180
|
+
|
|
181
|
+
## Example Integrations
|
|
182
|
+
|
|
183
|
+
You can find example integrations for some popular frameworks in the [`mikro-orm-examples` repository](https://github.com/mikro-orm/mikro-orm-examples):
|
|
184
|
+
|
|
185
|
+
### TypeScript Examples
|
|
186
|
+
|
|
187
|
+
- [Express + MongoDB](https://github.com/mikro-orm/express-ts-example-app)
|
|
188
|
+
- [Nest + MySQL](https://github.com/mikro-orm/nestjs-example-app)
|
|
189
|
+
- [RealWorld example app (Nest + MySQL)](https://github.com/mikro-orm/nestjs-realworld-example-app)
|
|
190
|
+
- [Koa + SQLite](https://github.com/mikro-orm/koa-ts-example-app)
|
|
191
|
+
- [GraphQL + PostgreSQL](https://github.com/driescroons/mikro-orm-graphql-example)
|
|
192
|
+
- [Inversify + PostgreSQL](https://github.com/PodaruDragos/inversify-example-app)
|
|
193
|
+
- [NextJS + MySQL](https://github.com/jonahallibone/mikro-orm-nextjs)
|
|
194
|
+
- [Accounts.js REST and GraphQL authentication + SQLite](https://github.com/darkbasic/mikro-orm-accounts-example)
|
|
195
|
+
- [Nest + Shopify + PostgreSQL + GraphQL](https://github.com/Cloudshelf/Shopify_CSConnector)
|
|
196
|
+
- [Elysia.js + libSQL + Bun](https://github.com/mikro-orm/elysia-bun-example-app)
|
|
197
|
+
- [Electron.js + PostgreSQL](https://github.com/adnanlah/electron-mikro-orm-example-app)
|
|
198
|
+
|
|
199
|
+
### JavaScript Examples
|
|
200
|
+
|
|
201
|
+
- [Express + SQLite](https://github.com/mikro-orm/express-js-example-app)
|
|
202
|
+
|
|
203
|
+
## Contributing
|
|
204
|
+
|
|
205
|
+
Contributions, issues and feature requests are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the process for submitting pull requests to us.
|
|
206
|
+
|
|
207
|
+
## Authors
|
|
208
|
+
|
|
209
|
+
**Martin Adámek**
|
|
210
|
+
|
|
211
|
+
- Twitter: [@B4nan](https://twitter.com/B4nan)
|
|
212
|
+
- Github: [@b4nan](https://github.com/b4nan)
|
|
213
|
+
|
|
214
|
+
See also the list of contributors who [participated](https://github.com/mikro-orm/mikro-orm/contributors) in this project.
|
|
215
|
+
|
|
216
|
+
## Show Your Support
|
|
217
|
+
|
|
218
|
+
Please star this repository if this project helped you!
|
|
219
|
+
|
|
220
|
+
> If you'd like to support my open-source work, consider sponsoring me directly at [github.com/sponsors/b4nan](https://github.com/sponsors/b4nan).
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
Copyright © 2018-present [Martin Adámek](https://github.com/b4nan).
|
|
225
|
+
|
|
226
|
+
This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from '@mikro-orm/sql';
|
|
2
|
+
export * from './PgliteConnection.js';
|
|
3
|
+
export * from './PgliteDriver.js';
|
|
4
|
+
export * from './PglitePlatform.js';
|
|
5
|
+
export * from './PgliteSchemaHelper.js';
|
|
6
|
+
export { PgliteMikroORM as MikroORM, type PgliteOptions as Options, definePgliteConfig as defineConfig, } from './PgliteMikroORM.js';
|
|
7
|
+
export { raw } from './raw.js';
|
package/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from '@mikro-orm/sql';
|
|
2
|
+
export * from './PgliteConnection.js';
|
|
3
|
+
export * from './PgliteDriver.js';
|
|
4
|
+
export * from './PglitePlatform.js';
|
|
5
|
+
export * from './PgliteSchemaHelper.js';
|
|
6
|
+
export { PgliteMikroORM as MikroORM, definePgliteConfig as defineConfig, } from './PgliteMikroORM.js';
|
|
7
|
+
export { raw } from './raw.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mikro-orm/pglite",
|
|
3
|
+
"version": "7.0.18-dev.0",
|
|
4
|
+
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"data-mapper",
|
|
7
|
+
"ddd",
|
|
8
|
+
"entity",
|
|
9
|
+
"identity-map",
|
|
10
|
+
"javascript",
|
|
11
|
+
"js",
|
|
12
|
+
"mariadb",
|
|
13
|
+
"mikro-orm",
|
|
14
|
+
"mongo",
|
|
15
|
+
"mongodb",
|
|
16
|
+
"mysql",
|
|
17
|
+
"orm",
|
|
18
|
+
"pglite",
|
|
19
|
+
"postgresql",
|
|
20
|
+
"sqlite",
|
|
21
|
+
"sqlite3",
|
|
22
|
+
"ts",
|
|
23
|
+
"typescript",
|
|
24
|
+
"unit-of-work"
|
|
25
|
+
],
|
|
26
|
+
"homepage": "https://mikro-orm.io",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/mikro-orm/mikro-orm/issues"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"author": "Martin Adámek",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+ssh://git@github.com/mikro-orm/mikro-orm.git"
|
|
35
|
+
},
|
|
36
|
+
"type": "module",
|
|
37
|
+
"exports": {
|
|
38
|
+
"./package.json": "./package.json",
|
|
39
|
+
".": "./index.js"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "yarn compile && yarn copy",
|
|
46
|
+
"clean": "yarn run -T rimraf ./dist ./tsconfig.build.tsbuildinfo",
|
|
47
|
+
"compile": "yarn run -T tsc -p tsconfig.build.json",
|
|
48
|
+
"copy": "node ../../scripts/copy.mjs"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@electric-sql/pglite": "0.4.4",
|
|
52
|
+
"@mikro-orm/sql": "7.0.18-dev.0",
|
|
53
|
+
"kysely": "0.29.2",
|
|
54
|
+
"postgres-array": "3.0.4",
|
|
55
|
+
"postgres-date": "2.1.0",
|
|
56
|
+
"postgres-interval": "4.0.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@mikro-orm/core": "^7.0.17"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@mikro-orm/core": "7.0.18-dev.0"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">= 22.17.0"
|
|
66
|
+
}
|
|
67
|
+
}
|
package/raw.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AnyString, type Dictionary, type EntityKey, type RawQueryFragment } from '@mikro-orm/sql';
|
|
2
|
+
import type { SelectQueryBuilder as KyselySelectQueryBuilder } from 'kysely';
|
|
3
|
+
/** @internal Type for QueryBuilder instances passed to raw() - uses toRaw to distinguish from Kysely QueryBuilder */
|
|
4
|
+
type QueryBuilderLike = {
|
|
5
|
+
toQuery(): {
|
|
6
|
+
sql: string;
|
|
7
|
+
params: readonly unknown[];
|
|
8
|
+
};
|
|
9
|
+
toRaw(): RawQueryFragment;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
|
|
13
|
+
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
|
|
14
|
+
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
|
|
15
|
+
* This adds a runtime safety to the raw query fragments.
|
|
16
|
+
*
|
|
17
|
+
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* // as a value
|
|
21
|
+
* await em.find(User, { time: raw('now()') });
|
|
22
|
+
*
|
|
23
|
+
* // as a key
|
|
24
|
+
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
|
|
25
|
+
*
|
|
26
|
+
* // value can be empty array
|
|
27
|
+
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
52
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
53
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
54
|
+
* @Entity({ schema: 'library' })
|
|
55
|
+
* export class Author { ... }
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
62
|
+
* @Entity({ schema: 'library' })
|
|
63
|
+
* export class Author { ... }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function raw<R = RawQueryFragment & symbol, T extends object = any>(sql: QueryBuilderLike | KyselySelectQueryBuilder<any, any, any> | EntityKey<T> | EntityKey<T>[] | AnyString | ((alias: string) => string) | RawQueryFragment, params?: readonly unknown[] | Dictionary<unknown>): R;
|
|
67
|
+
export {};
|
package/raw.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { raw as raw_, Utils, } from '@mikro-orm/sql';
|
|
2
|
+
/**
|
|
3
|
+
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
|
|
4
|
+
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
|
|
5
|
+
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
|
|
6
|
+
* This adds a runtime safety to the raw query fragments.
|
|
7
|
+
*
|
|
8
|
+
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // as a value
|
|
12
|
+
* await em.find(User, { time: raw('now()') });
|
|
13
|
+
*
|
|
14
|
+
* // as a key
|
|
15
|
+
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
|
|
16
|
+
*
|
|
17
|
+
* // value can be empty array
|
|
18
|
+
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
43
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
44
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
45
|
+
* @Entity({ schema: 'library' })
|
|
46
|
+
* export class Author { ... }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
53
|
+
* @Entity({ schema: 'library' })
|
|
54
|
+
* export class Author { ... }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function raw(sql, params) {
|
|
58
|
+
if (Utils.isObject(sql) && 'compile' in sql) {
|
|
59
|
+
const query = sql.compile();
|
|
60
|
+
const processed = query.sql.replaceAll(/\$\d+/g, '?');
|
|
61
|
+
return raw_(processed, query.parameters);
|
|
62
|
+
}
|
|
63
|
+
return raw_(sql, params);
|
|
64
|
+
}
|