Initial commit - Event Planner application

This commit is contained in:
mberlin
2026-03-18 14:55:56 -03:00
commit 86d779eb4d
7548 changed files with 1006324 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
import { CriteriaNode } from './CriteriaNode.js';
import type { IQueryBuilder, ICriteriaNodeProcessOptions } from '../typings.js';
/**
* @internal
*/
export declare class ArrayCriteriaNode<T extends object> extends CriteriaNode<T> {
process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
unwrap(): any;
willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
isStrict(): boolean;
}

24
node_modules/@mikro-orm/sql/query/ArrayCriteriaNode.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { CriteriaNode } from './CriteriaNode.js';
/**
* @internal
*/
export class ArrayCriteriaNode extends CriteriaNode {
process(qb, options) {
return this.payload.map(node => {
return node.process(qb, options);
});
}
unwrap() {
return this.payload.map(node => {
return node.unwrap();
});
}
willAutoJoin(qb, alias, options) {
return this.payload.some(node => {
return node.willAutoJoin(qb, alias, options);
});
}
isStrict() {
return this.strict || this.payload.some(node => node.isStrict());
}
}

43
node_modules/@mikro-orm/sql/query/CriteriaNode.d.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import {
type EntityKey,
type EntityProperty,
type MetadataStorage,
type RawQueryFragmentSymbol,
type EntityName,
} from '@mikro-orm/core';
import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
/**
* Helper for working with deeply nested where/orderBy/having criteria. Uses composite pattern to build tree from the payload.
* Auto-joins relations and converts payload from { books: { publisher: { name: '...' } } } to { 'publisher_alias.name': '...' }
* @internal
*/
export declare class CriteriaNode<T extends object> implements ICriteriaNode<T> {
protected readonly metadata: MetadataStorage;
readonly entityName: EntityName<T>;
readonly parent?: ICriteriaNode<T> | undefined;
readonly key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined;
readonly validate: boolean;
readonly strict: boolean;
payload: any;
prop?: EntityProperty<T>;
index?: number;
constructor(
metadata: MetadataStorage,
entityName: EntityName<T>,
parent?: ICriteriaNode<T> | undefined,
key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined,
validate?: boolean,
strict?: boolean,
);
process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
unwrap(): any;
shouldInline(payload: any): boolean;
willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
shouldRename(payload: any): boolean;
renameFieldToPK<T>(qb: IQueryBuilder<T>, ownerAlias?: string): string;
getPath(opts?: { addIndex?: boolean; parentPath?: string }): string;
private isPivotJoin;
getPivotPath(path: string): string;
aliased(field: string, alias?: string): string;
isStrict(): boolean;
}

150
node_modules/@mikro-orm/sql/query/CriteriaNode.js generated vendored Normal file
View File

@@ -0,0 +1,150 @@
import { RawQueryFragment, ReferenceKind, Utils, inspect } from '@mikro-orm/core';
/**
* Helper for working with deeply nested where/orderBy/having criteria. Uses composite pattern to build tree from the payload.
* Auto-joins relations and converts payload from { books: { publisher: { name: '...' } } } to { 'publisher_alias.name': '...' }
* @internal
*/
export class CriteriaNode {
metadata;
entityName;
parent;
key;
validate;
strict;
payload;
prop;
index;
constructor(metadata, entityName, parent, key, validate = true, strict = false) {
this.metadata = metadata;
this.entityName = entityName;
this.parent = parent;
this.key = key;
this.validate = validate;
this.strict = strict;
const meta = parent && metadata.find(parent.entityName);
if (meta && key && !RawQueryFragment.isKnownFragmentSymbol(key)) {
const pks = Utils.splitPrimaryKeys(key);
if (pks.length > 1) {
return;
}
for (const k of pks) {
this.prop = meta.props.find(
prop =>
prop.name === k || (prop.fieldNames?.length === 1 && prop.fieldNames[0] === k && prop.persist !== false),
);
const isProp = this.prop || meta.props.find(prop => (prop.fieldNames || []).includes(k));
// do not validate if the key is prefixed or type casted (e.g. `k::text`)
if (validate && !isProp && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k)) {
throw new Error(`Trying to query by not existing property ${Utils.className(entityName)}.${k}`);
}
}
}
}
process(qb, options) {
return this.payload;
}
unwrap() {
return this.payload;
}
shouldInline(payload) {
return false;
}
willAutoJoin(qb, alias, options) {
return false;
}
shouldRename(payload) {
const type = this.prop ? this.prop.kind : null;
const composite = this.prop?.joinColumns ? this.prop.joinColumns.length > 1 : false;
const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
const scalar =
payload === null ||
Utils.isPrimaryKey(payload) ||
payload instanceof RegExp ||
payload instanceof Date ||
rawField;
const operator =
Utils.isPlainObject(payload) && Utils.getObjectQueryKeys(payload).every(k => Utils.isOperator(k, false));
if (composite) {
return true;
}
switch (type) {
case ReferenceKind.MANY_TO_ONE:
return false;
case ReferenceKind.ONE_TO_ONE:
return !this.prop.owner;
case ReferenceKind.ONE_TO_MANY:
return scalar || operator;
case ReferenceKind.MANY_TO_MANY:
return scalar || operator;
default:
return false;
}
}
renameFieldToPK(qb, ownerAlias) {
const joinAlias = qb.getAliasForJoinPath(this.getPath(), { matchPopulateJoins: true });
if (
!joinAlias &&
this.parent &&
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind) &&
this.prop.owner
) {
const alias = qb.getAliasForJoinPath(this.parent.getPath()) ?? ownerAlias ?? qb.alias;
return Utils.getPrimaryKeyHash(this.prop.joinColumns.map(col => `${alias}.${col}`));
}
const alias = joinAlias ?? ownerAlias ?? qb.alias;
if (this.prop.kind === ReferenceKind.MANY_TO_MANY) {
return Utils.getPrimaryKeyHash(this.prop.inverseJoinColumns.map(col => `${alias}.${col}`));
}
return Utils.getPrimaryKeyHash(this.prop.referencedColumnNames.map(col => `${alias}.${col}`));
}
getPath(opts) {
// use index on parent only if we are processing to-many relation
const addParentIndex =
this.prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(this.prop.kind);
const parentPath =
opts?.parentPath ?? this.parent?.getPath({ addIndex: addParentIndex }) ?? Utils.className(this.entityName);
const index = opts?.addIndex && this.index != null ? `[${this.index}]` : '';
// ignore group operators to allow easier mapping (e.g. for orderBy)
const key =
this.key && !RawQueryFragment.isKnownFragmentSymbol(this.key) && !['$and', '$or', '$not'].includes(this.key)
? '.' + this.key
: '';
const ret = parentPath + index + key;
if (this.isPivotJoin()) {
// distinguish pivot table join from target entity join
return this.getPivotPath(ret);
}
return ret;
}
isPivotJoin() {
if (!this.key || !this.prop) {
return false;
}
const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
const scalar =
this.payload === null ||
Utils.isPrimaryKey(this.payload) ||
this.payload instanceof RegExp ||
this.payload instanceof Date ||
rawField;
const operator =
Utils.isObject(this.payload) && Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
return this.prop.kind === ReferenceKind.MANY_TO_MANY && (scalar || operator);
}
getPivotPath(path) {
return `${path}[pivot]`;
}
aliased(field, alias) {
return alias ? `${alias}.${field}` : field;
}
isStrict() {
return this.strict;
}
/** @ignore */
/* v8 ignore next */
[Symbol.for('nodejs.util.inspect.custom')]() {
const o = {};
['entityName', 'key', 'index', 'payload'].filter(k => this[k] !== undefined).forEach(k => (o[k] = this[k]));
return `${this.constructor.name} ${inspect(o)}`;
}
}

View File

@@ -0,0 +1,55 @@
import {
type Dictionary,
type EntityKey,
type EntityMetadata,
type EntityName,
type MetadataStorage,
type RawQueryFragmentSymbol,
} from '@mikro-orm/core';
import type { ICriteriaNode } from '../typings.js';
/**
* @internal
*/
export declare class CriteriaNodeFactory {
static createNode<T extends object>(
metadata: MetadataStorage,
entityName: EntityName<T>,
payload: any,
parent?: ICriteriaNode<T>,
key?: EntityKey<T> | RawQueryFragmentSymbol,
validate?: boolean,
): ICriteriaNode<T>;
static createScalarNode<T extends object>(
metadata: MetadataStorage,
entityName: EntityName<T>,
payload: any,
parent?: ICriteriaNode<T>,
key?: EntityKey<T> | RawQueryFragmentSymbol,
validate?: boolean,
): ICriteriaNode<T>;
static createArrayNode<T extends object>(
metadata: MetadataStorage,
entityName: EntityName<T>,
payload: any[],
parent?: ICriteriaNode<T>,
key?: EntityKey<T>,
validate?: boolean,
): ICriteriaNode<T>;
static createObjectNode<T extends object>(
metadata: MetadataStorage,
entityName: EntityName<T>,
payload: Dictionary,
parent?: ICriteriaNode<T>,
key?: EntityKey<T>,
validate?: boolean,
): ICriteriaNode<T>;
static createObjectItemNode<T extends object>(
metadata: MetadataStorage,
entityName: EntityName<T>,
node: ICriteriaNode<T>,
payload: Dictionary,
key: EntityKey<T> | RawQueryFragmentSymbol,
meta?: EntityMetadata<T>,
validate?: boolean,
): ICriteriaNode<T>;
}

View File

@@ -0,0 +1,111 @@
import {
GroupOperator,
isRaw,
JsonType,
RawQueryFragment,
ReferenceKind,
Utils,
ValidationError,
} from '@mikro-orm/core';
import { ObjectCriteriaNode } from './ObjectCriteriaNode.js';
import { ArrayCriteriaNode } from './ArrayCriteriaNode.js';
import { ScalarCriteriaNode } from './ScalarCriteriaNode.js';
import { EMBEDDABLE_ARRAY_OPS } from './enums.js';
/**
* @internal
*/
export class CriteriaNodeFactory {
static createNode(metadata, entityName, payload, parent, key, validate = true) {
const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
const scalar =
Utils.isPrimaryKey(payload) || isRaw(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
if (Array.isArray(payload) && !scalar) {
return this.createArrayNode(metadata, entityName, payload, parent, key, validate);
}
if (Utils.isPlainObject(payload) && !scalar) {
return this.createObjectNode(metadata, entityName, payload, parent, key, validate);
}
return this.createScalarNode(metadata, entityName, payload, parent, key, validate);
}
static createScalarNode(metadata, entityName, payload, parent, key, validate = true) {
const node = new ScalarCriteriaNode(metadata, entityName, parent, key, validate);
node.payload = payload;
return node;
}
static createArrayNode(metadata, entityName, payload, parent, key, validate = true) {
const node = new ArrayCriteriaNode(metadata, entityName, parent, key, validate);
node.payload = payload.map((item, index) => {
const n = this.createNode(metadata, entityName, item, node, undefined, validate);
// we care about branching only for $and
if (key === '$and' && payload.length > 1) {
n.index = index;
}
return n;
});
return node;
}
static createObjectNode(metadata, entityName, payload, parent, key, validate = true) {
const meta = metadata.find(entityName);
const node = new ObjectCriteriaNode(metadata, entityName, parent, key, validate, payload.__strict);
node.payload = {};
for (const k of Utils.getObjectQueryKeys(payload)) {
node.payload[k] = this.createObjectItemNode(metadata, entityName, node, payload, k, meta, validate);
}
return node;
}
static createObjectItemNode(metadata, entityName, node, payload, key, meta, validate = true) {
const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
const prop = rawField ? null : meta?.properties[key];
const childEntity = prop && prop.kind !== ReferenceKind.SCALAR ? prop.targetMeta.class : entityName;
const isNotEmbedded = rawField || prop?.kind !== ReferenceKind.EMBEDDED;
const val = payload[key];
if (isNotEmbedded && prop?.customType instanceof JsonType) {
return this.createScalarNode(metadata, childEntity, val, node, key, validate);
}
if (prop?.kind === ReferenceKind.SCALAR && val != null && Object.keys(val).some(f => f in GroupOperator)) {
throw ValidationError.cannotUseGroupOperatorsInsideScalars(entityName, prop.name, payload);
}
if (isNotEmbedded) {
return this.createNode(metadata, childEntity, val, node, key, validate);
}
if (val == null) {
const map = Object.keys(prop.embeddedProps).reduce((oo, k) => {
oo[prop.embeddedProps[k].name] = null;
return oo;
}, {});
return this.createNode(metadata, entityName, map, node, key, validate);
}
// For array embeddeds stored as real columns, route property-level queries
// as scalar nodes so QueryBuilderHelper generates EXISTS subqueries with
// JSON array iteration. Keys containing `~` indicate the property lives
// inside a parent's object-mode JSON column (MetadataDiscovery uses `~` as
// the glue for object embeds), where JSON path access is used instead.
if (prop.array && !String(key).includes('~')) {
const keys = Object.keys(val);
const hasOnlyArrayOps = keys.every(k => EMBEDDABLE_ARRAY_OPS.includes(k));
if (!hasOnlyArrayOps) {
return this.createScalarNode(metadata, entityName, val, node, key, validate);
}
}
// array operators can be used on embedded properties
const operator = Object.keys(val).some(f => Utils.isOperator(f) && !EMBEDDABLE_ARRAY_OPS.includes(f));
if (operator) {
throw ValidationError.cannotUseOperatorsInsideEmbeddables(entityName, prop.name, payload);
}
const map = Object.keys(val).reduce((oo, k) => {
const embeddedProp = prop.embeddedProps[k] ?? Object.values(prop.embeddedProps).find(p => p.name === k);
if (!embeddedProp && !EMBEDDABLE_ARRAY_OPS.includes(k)) {
throw ValidationError.invalidEmbeddableQuery(entityName, k, prop.type);
}
if (embeddedProp) {
oo[embeddedProp.name] = val[k];
} else if (typeof val[k] === 'object') {
oo[k] = JSON.stringify(val[k]);
} else {
oo[k] = val[k];
}
return oo;
}, {});
return this.createNode(metadata, entityName, map, node, key, validate);
}
}

View File

@@ -0,0 +1,137 @@
import { type Dictionary, LockMode, type QueryFlag, RawQueryFragment, type Subquery } from '@mikro-orm/core';
import { QueryType } from './enums.js';
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
/** Options for Common Table Expression (CTE) definitions. */
export interface CteOptions {
/** Column names for the CTE. */
columns?: string[];
/** PostgreSQL: MATERIALIZED / NOT MATERIALIZED */
materialized?: boolean;
}
interface CteClause extends CteOptions {
name: string;
sql: string;
params: unknown[];
recursive?: boolean;
}
interface Options {
tableName?: string | RawQueryFragment;
indexHint?: string;
select?: (string | RawQueryFragment)[];
distinct?: boolean;
distinctOn?: string[];
joins?: {
sql: string;
params: unknown[];
}[];
groupBy?: (string | RawQueryFragment)[];
where?: {
sql: string;
params: unknown[];
};
having?: {
sql: string;
params: unknown[];
};
orderBy?: string;
limit?: number;
offset?: number;
data?: Dictionary;
onConflict?: OnConflictClause;
lockMode?: LockMode;
lockTables?: string[];
returning?: (string | RawQueryFragment | [name: string, type: unknown])[];
comment?: string[];
hintComment?: string[];
flags?: Set<QueryFlag>;
wrap?: [prefix: string, suffix: string];
ctes?: CteClause[];
}
/** Options for specifying the target table in FROM/INTO clauses. */
export interface TableOptions {
schema?: string;
indexHint?: string;
alias?: string;
}
interface OnConflictClause {
fields: string[] | RawQueryFragment;
ignore?: boolean;
merge?: Dictionary | (string | RawQueryFragment)[];
where?: {
sql: string;
params: unknown[];
};
}
/** @internal */
export declare class NativeQueryBuilder implements Subquery {
protected readonly platform: AbstractSqlPlatform;
readonly __subquery: true;
protected type?: QueryType;
protected parts: string[];
protected params: unknown[];
protected options: Options;
constructor(platform: AbstractSqlPlatform);
select(fields: string | RawQueryFragment | (string | RawQueryFragment)[]): this;
count(fields?: string | RawQueryFragment | (string | RawQueryFragment)[], distinct?: boolean): this;
into(tableName: string | RawQueryFragment | NativeQueryBuilder, options?: TableOptions): this;
from(tableName: string | RawQueryFragment | NativeQueryBuilder, options?: TableOptions): this;
where(sql: string, params: unknown[]): this;
having(sql: string, params: unknown[]): this;
groupBy(groupBy: (string | RawQueryFragment)[]): this;
join(sql: string, params: unknown[]): this;
orderBy(orderBy: string): this;
/**
* The sub-query is compiled eagerly at call time — later mutations to the
* sub-query builder will not be reflected in this CTE.
*/
with(name: string, query: NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
/**
* Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
* The sub-query is compiled eagerly — later mutations will not be reflected.
*/
withRecursive(name: string, query: NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
private addCte;
toString(): string;
compile(): {
sql: string;
params: unknown[];
};
protected addLockClause(): void;
protected addOnConflictClause(): void;
protected combineParts(): {
sql: string;
params: unknown[];
};
limit(limit: number): this;
offset(offset: number): this;
insert(data: Dictionary): this;
update(data: Dictionary): this;
delete(): this;
truncate(): this;
distinct(): this;
distinctOn(fields: string[]): this;
onConflict(options: OnConflictClause): OnConflictClause;
returning(fields: (string | RawQueryFragment | [name: string, type: unknown])[]): this;
lockMode(lockMode: LockMode, lockTables?: string[]): this;
comment(comment: string | string[]): this;
hintComment(comment: string | string[]): this;
setFlags(flags: Set<QueryFlag>): this;
clear(clause: keyof Options): this;
wrap(prefix: string, suffix: string): this;
as(alias: string): this;
toRaw(): RawQueryFragment;
protected compileSelect(): void;
protected getFields(): string;
protected compileInsert(): void;
protected addOutputClause(type: 'inserted' | 'deleted'): void;
protected processInsertData(): string[];
protected compileUpdate(): void;
protected compileDelete(): void;
protected compileTruncate(): void;
protected addHintComment(): void;
protected compileCtes(): void;
protected getCteKeyword(hasRecursive: boolean): string;
protected getTableName(): string;
protected quote(id: string | RawQueryFragment | NativeQueryBuilder): string;
}
export {};

490
node_modules/@mikro-orm/sql/query/NativeQueryBuilder.js generated vendored Normal file
View File

@@ -0,0 +1,490 @@
import { LockMode, raw, RawQueryFragment, Utils } from '@mikro-orm/core';
import { QueryType } from './enums.js';
/** @internal */
export class NativeQueryBuilder {
platform;
type;
parts = [];
params = [];
options = {};
constructor(platform) {
this.platform = platform;
}
select(fields) {
this.type = QueryType.SELECT;
this.options.select ??= [];
this.options.select.push(...Utils.asArray(fields));
return this;
}
count(fields = '*', distinct) {
this.type = QueryType.COUNT;
this.options.select = Utils.asArray(fields);
this.options.distinct = distinct;
return this;
}
into(tableName, options) {
return this.from(tableName, options);
}
from(tableName, options) {
if (tableName instanceof NativeQueryBuilder) {
tableName = tableName.toRaw();
}
if (typeof tableName === 'string') {
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
const alias = options?.alias ? `${asKeyword}${this.platform.quoteIdentifier(options.alias)}` : '';
const schema =
options?.schema && options.schema !== this.platform.getDefaultSchemaName() ? `${options.schema}.` : '';
tableName = this.quote(schema + tableName) + alias;
}
this.options.tableName = tableName;
this.options.indexHint = options?.indexHint;
return this;
}
where(sql, params) {
this.options.where = { sql, params };
return this;
}
having(sql, params) {
this.options.having = { sql, params };
return this;
}
groupBy(groupBy) {
this.options.groupBy = groupBy;
return this;
}
join(sql, params) {
this.options.joins ??= [];
this.options.joins.push({ sql, params });
return this;
}
orderBy(orderBy) {
this.options.orderBy = orderBy;
return this;
}
/**
* The sub-query is compiled eagerly at call time — later mutations to the
* sub-query builder will not be reflected in this CTE.
*/
with(name, query, options) {
return this.addCte(name, query, options);
}
/**
* Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
* The sub-query is compiled eagerly — later mutations will not be reflected.
*/
withRecursive(name, query, options) {
return this.addCte(name, query, options, true);
}
addCte(name, query, options, recursive) {
this.options.ctes ??= [];
if (this.options.ctes.some(cte => cte.name === name)) {
throw new Error(`CTE with name '${name}' already exists`);
}
const { sql, params } =
query instanceof NativeQueryBuilder ? query.compile() : { sql: query.sql, params: [...query.params] };
this.options.ctes.push({
name,
sql,
params,
recursive,
columns: options?.columns,
materialized: options?.materialized,
});
return this;
}
toString() {
const { sql, params } = this.compile();
return this.platform.formatQuery(sql, params);
}
compile() {
if (!this.type) {
throw new Error('No query type provided');
}
this.parts.length = 0;
this.params.length = 0;
if (this.options.comment) {
this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
}
this.compileCtes();
switch (this.type) {
case QueryType.SELECT:
case QueryType.COUNT:
this.compileSelect();
break;
case QueryType.INSERT:
this.compileInsert();
break;
case QueryType.UPDATE:
this.compileUpdate();
break;
case QueryType.DELETE:
this.compileDelete();
break;
case QueryType.TRUNCATE:
this.compileTruncate();
break;
}
this.addOnConflictClause();
if (this.options.returning && this.platform.usesReturningStatement()) {
const fields = this.options.returning.map(field => this.quote(field));
this.parts.push(`returning ${fields.join(', ')}`);
}
this.addLockClause();
return this.combineParts();
}
addLockClause() {
if (!this.options.lockMode) {
return;
}
if (
[LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_READ_OR_FAIL].includes(
this.options.lockMode,
)
) {
this.parts.push('for share');
}
if (
[LockMode.PESSIMISTIC_WRITE, LockMode.PESSIMISTIC_PARTIAL_WRITE, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(
this.options.lockMode,
)
) {
this.parts.push('for update');
}
if (this.options.lockTables?.length) {
const fields = this.options.lockTables.map(field => this.quote(field));
this.parts.push(`of ${fields.join(', ')}`);
}
if ([LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_PARTIAL_WRITE].includes(this.options.lockMode)) {
this.parts.push('skip locked');
}
if ([LockMode.PESSIMISTIC_READ_OR_FAIL, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(this.options.lockMode)) {
this.parts.push('nowait');
}
}
addOnConflictClause() {
const clause = this.options.onConflict;
if (!clause) {
return;
}
this.parts.push('on conflict');
if (clause.fields instanceof RawQueryFragment) {
this.parts.push(clause.fields.sql);
this.params.push(...clause.fields.params);
} else if (clause.fields.length > 0) {
const fields = clause.fields.map(field => this.quote(field));
this.parts.push(`(${fields.join(', ')})`);
}
if (clause.ignore) {
this.parts.push('do nothing');
}
if (Utils.isObject(clause.merge)) {
this.parts.push('do update set');
const fields = Object.keys(clause.merge).map(field => {
this.params.push(clause.merge[field]);
return `${this.quote(field)} = ?`;
});
this.parts.push(fields.join(', '));
} else if (clause.merge) {
this.parts.push('do update set');
if (clause.merge.length) {
const fields = clause.merge.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
this.parts.push(fields.join(', '));
} else {
const dataAsArray = Utils.asArray(this.options.data);
const keys = Object.keys(dataAsArray[0]);
const fields = keys.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
this.parts.push(fields.join(', '));
}
}
if (clause.where) {
this.parts.push(`where ${clause.where.sql}`);
this.params.push(...clause.where.params);
}
}
combineParts() {
let sql = this.parts.join(' ');
if (this.options.wrap) {
const [a, b] = this.options.wrap;
sql = `${a}${sql}${b}`;
}
return { sql, params: this.params };
}
limit(limit) {
this.options.limit = limit;
return this;
}
offset(offset) {
this.options.offset = offset;
return this;
}
insert(data) {
this.type = QueryType.INSERT;
this.options.data = data;
return this;
}
update(data) {
this.type = QueryType.UPDATE;
this.options.data ??= {};
Object.assign(this.options.data, data);
return this;
}
delete() {
this.type = QueryType.DELETE;
return this;
}
truncate() {
this.type = QueryType.TRUNCATE;
return this;
}
distinct() {
this.options.distinct = true;
return this;
}
distinctOn(fields) {
this.options.distinctOn = fields;
return this;
}
onConflict(options) {
this.options.onConflict = options;
return options;
}
returning(fields) {
this.options.returning = fields;
return this;
}
lockMode(lockMode, lockTables) {
this.options.lockMode = lockMode;
this.options.lockTables = lockTables;
return this;
}
comment(comment) {
this.options.comment ??= [];
this.options.comment.push(...Utils.asArray(comment));
return this;
}
hintComment(comment) {
this.options.hintComment ??= [];
this.options.hintComment.push(...Utils.asArray(comment));
return this;
}
setFlags(flags) {
this.options.flags = flags;
return this;
}
clear(clause) {
delete this.options[clause];
return this;
}
wrap(prefix, suffix) {
this.options.wrap = [prefix, suffix];
return this;
}
as(alias) {
this.wrap('(', `) as ${this.platform.quoteIdentifier(alias)}`);
return this;
}
toRaw() {
const { sql, params } = this.compile();
return raw(sql, params);
}
compileSelect() {
this.parts.push('select');
this.addHintComment();
this.parts.push(`${this.getFields()} from ${this.getTableName()}`);
if (this.options.joins) {
for (const join of this.options.joins) {
this.parts.push(join.sql);
this.params.push(...join.params);
}
}
if (this.options.where?.sql.trim()) {
this.parts.push(`where ${this.options.where.sql}`);
this.options.where.params.forEach(p => this.params.push(p));
}
if (this.options.groupBy) {
const fields = this.options.groupBy.map(field => this.quote(field));
this.parts.push(`group by ${fields.join(', ')}`);
}
if (this.options.having) {
this.parts.push(`having ${this.options.having.sql}`);
this.params.push(...this.options.having.params);
}
if (this.options.orderBy) {
this.parts.push(`order by ${this.options.orderBy}`);
}
if (this.options.limit != null) {
this.parts.push(`limit ?`);
this.params.push(this.options.limit);
}
if (this.options.offset != null) {
this.parts.push(`offset ?`);
this.params.push(this.options.offset);
}
}
getFields() {
if (!this.options.select || this.options.select.length === 0) {
throw new Error('No fields selected');
}
let fields = this.options.select.map(field => this.quote(field)).join(', ');
if (this.options.distinct) {
fields = `distinct ${fields}`;
} else if (this.options.distinctOn) {
fields = `distinct on (${this.options.distinctOn.map(field => this.quote(field)).join(', ')}) ${fields}`;
}
if (this.type === QueryType.COUNT) {
fields = `count(${fields}) as ${this.quote('count')}`;
}
return fields;
}
compileInsert() {
if (!this.options.data) {
throw new Error('No data provided');
}
this.parts.push('insert');
this.addHintComment();
this.parts.push(`into ${this.getTableName()}`);
if (Object.keys(this.options.data).length === 0) {
this.addOutputClause('inserted');
this.parts.push('default values');
return;
}
const parts = this.processInsertData();
this.parts.push(parts.join(', '));
}
addOutputClause(type) {
if (this.options.returning && this.platform.usesOutputStatement()) {
const fields = this.options.returning.map(field => `${type}.${this.quote(field)}`);
this.parts.push(`output ${fields.join(', ')}`);
}
}
processInsertData() {
const dataAsArray = Utils.asArray(this.options.data);
const keys = Object.keys(dataAsArray[0]);
const values = keys.map(() => '?');
const parts = [];
this.parts.push(`(${keys.map(key => this.quote(key)).join(', ')})`);
this.addOutputClause('inserted');
this.parts.push('values');
for (const data of dataAsArray) {
for (const key of keys) {
if (typeof data[key] === 'undefined') {
this.params.push(this.platform.usesDefaultKeyword() ? raw('default') : null);
} else {
this.params.push(data[key]);
}
}
parts.push(`(${values.join(', ')})`);
}
return parts;
}
compileUpdate() {
if (!this.options.data || Object.keys(this.options.data).length === 0) {
throw new Error('No data provided');
}
this.parts.push('update');
this.addHintComment();
this.parts.push(this.getTableName());
if (this.options.joins) {
for (const join of this.options.joins) {
this.parts.push(join.sql);
this.params.push(...join.params);
}
}
this.parts.push('set');
if (this.options.data) {
const parts = [];
for (const key of Object.keys(this.options.data)) {
parts.push(`${this.quote(key)} = ?`);
this.params.push(this.options.data[key]);
}
this.parts.push(parts.join(', '));
}
this.addOutputClause('inserted');
if (this.options.where?.sql.trim()) {
this.parts.push(`where ${this.options.where.sql}`);
this.params.push(...this.options.where.params);
}
}
compileDelete() {
this.parts.push('delete');
this.addHintComment();
this.parts.push(`from ${this.getTableName()}`);
this.addOutputClause('deleted');
if (this.options.where?.sql.trim()) {
this.parts.push(`where ${this.options.where.sql}`);
this.params.push(...this.options.where.params);
}
}
compileTruncate() {
const sql = `truncate table ${this.getTableName()}`;
this.parts.push(sql);
}
addHintComment() {
if (this.options.hintComment) {
this.parts.push(`/*+ ${this.options.hintComment.join(' ')} */`);
}
}
compileCtes() {
const ctes = this.options.ctes;
if (!ctes || ctes.length === 0) {
return;
}
const hasRecursive = ctes.some(cte => cte.recursive);
const keyword = this.getCteKeyword(hasRecursive);
const cteParts = [];
for (const cte of ctes) {
let part = this.quote(cte.name);
if (cte.columns?.length) {
part += ` (${cte.columns.map(c => this.quote(c)).join(', ')})`;
}
part += ' as';
if (cte.materialized === true) {
part += ' materialized';
} else if (cte.materialized === false) {
part += ' not materialized';
}
part += ` (${cte.sql})`;
this.params.push(...cte.params);
cteParts.push(part);
}
this.parts.push(`${keyword} ${cteParts.join(', ')}`);
}
getCteKeyword(hasRecursive) {
return hasRecursive ? 'with recursive' : 'with';
}
getTableName() {
if (!this.options.tableName) {
throw new Error('No table name provided');
}
const indexHint = this.options.indexHint ? ' ' + this.options.indexHint : '';
if (this.options.tableName instanceof RawQueryFragment) {
this.params.push(...this.options.tableName.params);
return this.options.tableName.sql + indexHint;
}
return this.options.tableName + indexHint;
}
quote(id) {
if (id instanceof RawQueryFragment) {
return this.platform.formatQuery(id.sql, id.params);
}
if (id instanceof NativeQueryBuilder) {
const { sql, params } = id.compile();
return this.platform.formatQuery(sql, params);
}
if (id.endsWith('.*')) {
const schema = this.platform.quoteIdentifier(id.substring(0, id.indexOf('.')));
return schema + '.*';
}
if (id.toLowerCase().includes(' as ')) {
const parts = id.split(/ as /i);
const a = this.platform.quoteIdentifier(parts[0]);
const b = this.platform.quoteIdentifier(parts[1]);
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
return `${a}${asKeyword}${b}`;
}
if (id === '*') {
return id;
}
return this.platform.quoteIdentifier(id);
}
}

View File

@@ -0,0 +1,19 @@
import { CriteriaNode } from './CriteriaNode.js';
import type { ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
/**
* @internal
*/
export declare class ObjectCriteriaNode<T extends object> extends CriteriaNode<T> {
process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
isStrict(): boolean;
unwrap(): any;
willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
shouldInline(payload: any): boolean;
private getChildKey;
private inlineArrayChildPayload;
private inlineChildPayload;
private inlineCondition;
private shouldAutoJoin;
private autoJoin;
private isPrefixed;
}

324
node_modules/@mikro-orm/sql/query/ObjectCriteriaNode.js generated vendored Normal file
View File

@@ -0,0 +1,324 @@
import {
ALIAS_REPLACEMENT,
GroupOperator,
QueryFlag,
raw,
RawQueryFragment,
ReferenceKind,
Utils,
} from '@mikro-orm/core';
import { CriteriaNode } from './CriteriaNode.js';
import { JoinType, QueryType } from './enums.js';
const COLLECTION_OPERATORS = ['$some', '$none', '$every', '$size'];
/**
* @internal
*/
export class ObjectCriteriaNode extends CriteriaNode {
process(qb, options) {
const matchPopulateJoins =
options?.matchPopulateJoins ||
(this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
const nestedAlias = qb.getAliasForJoinPath(this.getPath(options), { ...options, matchPopulateJoins });
const ownerAlias = options?.alias || qb.alias;
const keys = Utils.getObjectQueryKeys(this.payload);
let alias = options?.alias;
if (nestedAlias) {
alias = nestedAlias;
}
if (this.shouldAutoJoin(qb, nestedAlias)) {
if (keys.some(k => COLLECTION_OPERATORS.includes(k))) {
if (![ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(this.prop.kind)) {
// ignore collection operators when used on a non-relational property - this can happen when they get into
// populateWhere via `infer` on m:n properties with select-in strategy
if (this.parent?.parent) {
// we validate only usage on top level
return {};
}
throw new Error(
`Collection operators can be used only inside a collection property context, but it was used for ${this.getPath()}.`,
);
}
const $and = [];
const knownKey =
[ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) ||
(this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
const parentMeta = this.metadata.find(this.parent.entityName);
const primaryKeys = parentMeta.primaryKeys.map(pk => {
return [QueryType.SELECT, QueryType.COUNT].includes(qb.type) ? `${knownKey ? alias : ownerAlias}.${pk}` : pk;
});
for (const key of keys) {
if (typeof key !== 'string' || !COLLECTION_OPERATORS.includes(key)) {
throw new Error('Mixing collection operators with other filters is not allowed.');
}
const payload = this.payload[key].unwrap();
const qb2 = qb.clone(true, ['schema']);
const joinAlias = qb2.getNextAlias(this.prop.targetMeta.class);
const sub = qb2
.from(parentMeta.class)
// eslint-disable-next-line no-unexpected-multiline
[key === '$size' ? 'leftJoin' : 'innerJoin'](this.key, joinAlias)
.select(parentMeta.primaryKeys);
if (key === '$size') {
const sizeCondition = typeof payload === 'number' ? { $eq: payload } : payload;
const pks = this.prop.referencedColumnNames;
const countExpr = raw(
`count(${pks.map(() => '??').join(', ')})`,
pks.map(pk => `${joinAlias}.${pk}`),
);
sub.groupBy(parentMeta.primaryKeys);
sub.having({
$and: Object.keys(sizeCondition).map(op => ({ [countExpr]: { [op]: sizeCondition[op] } })),
});
} else if (key === '$every') {
sub.where({ $not: { [this.key]: payload } });
} else {
sub.where({ [this.key]: payload });
}
const op = ['$size', '$some'].includes(key) ? '$in' : '$nin';
$and.push({
[Utils.getPrimaryKeyHash(primaryKeys)]: { [op]: sub.getNativeQuery().toRaw() },
});
}
if ($and.length === 1) {
return $and[0];
}
return { $and };
}
alias = this.autoJoin(qb, ownerAlias, options);
}
if (this.prop && nestedAlias) {
const toOneProperty = [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind);
// if the property is nullable and the filter is strict, we need to use left join, so we mimic the inner join behaviour
// with an exclusive condition on the join columns:
// - if the owning column is null, the row is missing, we don't apply the filter
// - if the target column is not null, the row is matched, we apply the filter
if (toOneProperty && this.prop.nullable && this.isStrict()) {
const key = this.prop.owner ? this.prop.name : this.prop.referencedPKs;
qb.andWhere({
$or: [
{ [ownerAlias + '.' + key]: null },
{ [nestedAlias + '.' + Utils.getPrimaryKeyHash(this.prop.referencedPKs)]: { $ne: null } },
],
});
}
}
return keys.reduce((o, field) => {
const childNode = this.payload[field];
const payload = childNode.process(qb, { ...options, alias: this.prop ? alias : ownerAlias });
const operator = Utils.isOperator(field);
const isRawField = RawQueryFragment.isKnownFragmentSymbol(field);
// we need to keep the prefixing for formulas otherwise we would lose aliasing context when nesting inside group operators
const virtual = childNode.prop?.persist === false && !childNode.prop?.formula && !!options?.type;
// if key is missing, we are inside group operator and we need to prefix with alias
const primaryKey = this.key && this.metadata.find(this.entityName)?.primaryKeys.includes(field);
const isToOne =
childNode.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(childNode.prop.kind);
if (childNode.shouldInline(payload)) {
const childAlias = qb.getAliasForJoinPath(childNode.getPath(), { preferNoBranch: isToOne, ...options });
const a = qb.helper.isTableNameAliasRequired(qb.type) ? alias : undefined;
this.inlineChildPayload(o, payload, field, a, childAlias);
} else if (childNode.shouldRename(payload)) {
this.inlineCondition(childNode.renameFieldToPK(qb, alias), o, payload);
} else if (isRawField) {
const rawField = RawQueryFragment.getKnownFragment(field);
o[raw(rawField.sql.replaceAll(ALIAS_REPLACEMENT, alias), rawField.params)] = payload;
} else if (!childNode.validate && !childNode.prop && !field.includes('.') && !operator) {
// wrap unknown fields in raw() to prevent alias prefixing (e.g. raw SQL aliases in HAVING)
// use '??' placeholder to properly quote the identifier
o[raw('??', [field])] = payload;
} else if (
primaryKey ||
virtual ||
operator ||
field.includes('.') ||
![QueryType.SELECT, QueryType.COUNT].includes(qb.type)
) {
this.inlineCondition(field.replaceAll(ALIAS_REPLACEMENT, alias), o, payload);
} else {
this.inlineCondition(`${alias ?? qb.alias}.${field}`, o, payload);
}
return o;
}, {});
}
isStrict() {
return (
this.strict ||
Utils.getObjectQueryKeys(this.payload).some(key => {
return this.payload[key].isStrict();
})
);
}
unwrap() {
return Utils.getObjectQueryKeys(this.payload).reduce((o, field) => {
o[field] = this.payload[field].unwrap();
return o;
}, {});
}
willAutoJoin(qb, alias, options) {
const nestedAlias = qb.getAliasForJoinPath(this.getPath(options), options);
const ownerAlias = alias || qb.alias;
const keys = Utils.getObjectQueryKeys(this.payload);
if (nestedAlias) {
alias = nestedAlias;
}
if (this.shouldAutoJoin(qb, nestedAlias)) {
return !keys.some(k => COLLECTION_OPERATORS.includes(k));
}
return keys.some(field => {
const childNode = this.payload[field];
return childNode.willAutoJoin(qb, this.prop ? alias : ownerAlias, options);
});
}
shouldInline(payload) {
const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
const scalar = Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
const operator =
Utils.isObject(payload) &&
Utils.getObjectQueryKeys(payload).every(k => {
if (k === '$not' && Utils.isPlainObject(payload[k])) {
// $not wrapping non-operator conditions (entity props) should be inlined
return Utils.getObjectQueryKeys(payload[k]).every(ik => Utils.isOperator(ik, false));
}
return Utils.isOperator(k, false);
});
return !!this.prop && this.prop.kind !== ReferenceKind.SCALAR && !scalar && !operator;
}
getChildKey(k, prop, childAlias, alias) {
const idx = prop.referencedPKs.indexOf(k);
return idx !== -1 && !childAlias && ![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)
? this.aliased(prop.joinColumns[idx], alias)
: k;
}
inlineArrayChildPayload(obj, payload, k, prop, childAlias, alias) {
const key = this.getChildKey(k, prop, childAlias);
const value = payload.map(child =>
Utils.getObjectQueryKeys(child).reduce((inner, childKey) => {
const key =
RawQueryFragment.isKnownFragmentSymbol(childKey) || this.isPrefixed(childKey) || Utils.isOperator(childKey)
? childKey
: this.aliased(childKey, childAlias);
inner[key] = child[childKey];
return inner;
}, {}),
);
this.inlineCondition(key, obj, value);
}
inlineChildPayload(o, payload, field, alias, childAlias) {
const prop = this.metadata.find(this.entityName).properties[field];
for (const k of Utils.getObjectQueryKeys(payload)) {
if (RawQueryFragment.isKnownFragmentSymbol(k)) {
o[k] = payload[k];
} else if (
k === '$not' &&
Utils.isPlainObject(payload[k]) &&
Utils.getObjectQueryKeys(payload[k]).some(ik => !Utils.isOperator(ik, false))
) {
// $not wraps entity conditions (from auto-join), inline at current level
this.inlineCondition(k, o, payload[k]);
} else if (Utils.isOperator(k, false)) {
const tmp = payload[k];
delete payload[k];
o[this.aliased(field, alias)] = { [k]: tmp, ...o[this.aliased(field, alias)] };
} else if (k in GroupOperator && Array.isArray(payload[k])) {
this.inlineArrayChildPayload(o, payload[k], k, prop, childAlias, alias);
} else if (this.isPrefixed(k) || Utils.isOperator(k) || !childAlias) {
const key = this.getChildKey(k, prop, childAlias, alias);
this.inlineCondition(key, o, payload[k]);
} else {
o[this.aliased(k, childAlias)] = payload[k];
}
}
}
inlineCondition(key, o, value) {
if (!(key in o)) {
o[key] = value;
return;
}
/* v8 ignore next */
if (key === '$and') {
o.$and.push({ [key]: value });
return;
}
const $and = o.$and ?? [];
$and.push({ [key]: o[key] }, { [key]: value });
delete o[key];
o.$and = $and;
}
shouldAutoJoin(qb, nestedAlias) {
if (!this.prop || !this.parent) {
return false;
}
const keys = Utils.getObjectQueryKeys(this.payload);
if (keys.every(k => typeof k === 'string' && k.includes('.') && k.startsWith(`${qb.alias}.`))) {
return false;
}
if (keys.some(k => COLLECTION_OPERATORS.includes(k))) {
return true;
}
const meta = this.metadata.find(this.entityName);
const embeddable = this.prop.kind === ReferenceKind.EMBEDDED;
const knownKey =
[ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) ||
(this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
const operatorKeys =
knownKey &&
keys.every(key => {
if (key === '$not') {
// $not wraps conditions like $and/$or, check if it wraps entity property conditions (needs auto-join)
// vs simple operator conditions on the FK (doesn't need auto-join)
const childPayload = this.payload[key].payload;
if (Utils.isPlainObject(childPayload)) {
return Utils.getObjectQueryKeys(childPayload).every(k => Utils.isOperator(k, false));
}
}
return Utils.isOperator(key, false);
});
const primaryKeys =
knownKey &&
keys.every(key => {
if (typeof key !== 'string' || !meta.primaryKeys.includes(key)) {
return false;
}
if (
!Utils.isPlainObject(this.payload[key].payload) ||
![ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(meta.properties[key].kind)
) {
return true;
}
return Utils.getObjectQueryKeys(this.payload[key].payload).every(
k => typeof k === 'string' && meta.properties[key].targetMeta.primaryKeys.includes(k),
);
});
return !primaryKeys && !nestedAlias && !operatorKeys && !embeddable;
}
autoJoin(qb, alias, options) {
const nestedAlias = qb.getNextAlias(this.prop?.pivotEntity ?? this.entityName);
const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
const scalar =
Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || rawField;
const operator =
Utils.isPlainObject(this.payload) &&
Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
const field = `${alias}.${this.prop.name}`;
const method = qb.hasFlag(QueryFlag.INFER_POPULATE) ? 'joinAndSelect' : 'join';
const path = this.getPath();
if (this.prop.kind === ReferenceKind.MANY_TO_MANY && (scalar || operator)) {
qb.join(field, nestedAlias, undefined, JoinType.pivotJoin, path);
} else {
const prev = qb.state.fields?.slice();
const toOneProperty = [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind);
const joinType = toOneProperty && !this.prop.nullable ? JoinType.innerJoin : JoinType.leftJoin;
qb[method](field, nestedAlias, undefined, joinType, path);
if (!qb.hasFlag(QueryFlag.INFER_POPULATE)) {
qb.state.fields = prev;
}
}
if (options?.type !== 'orderBy') {
qb.scheduleFilterCheck(path);
}
return nestedAlias;
}
isPrefixed(field) {
return !!/\w+\./.exec(field);
}
}

1646
node_modules/@mikro-orm/sql/query/QueryBuilder.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

2312
node_modules/@mikro-orm/sql/query/QueryBuilder.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
import {
type Dictionary,
type EntityData,
type EntityKey,
type EntityMetadata,
type EntityName,
type EntityProperty,
type FilterQuery,
type FlatQueryOrderMap,
type FormulaTable,
LockMode,
type QueryOrderMap,
Raw,
type RawQueryFragment,
type RawQueryFragmentSymbol,
} from '@mikro-orm/core';
import { JoinType, QueryType } from './enums.js';
import type { InternalField, JoinOptions } from '../typings.js';
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
import type { NativeQueryBuilder } from './NativeQueryBuilder.js';
/**
* @internal
*/
export declare class QueryBuilderHelper {
#private;
constructor(
entityName: EntityName,
alias: string,
aliasMap: Dictionary<Alias<any>>,
subQueries: Dictionary<string>,
driver: AbstractSqlDriver,
tptAliasMap?: Dictionary<string>,
);
/**
* For TPT inheritance, finds the correct alias for a property based on which entity owns it.
* Returns the main alias if not a TPT property or if the property belongs to the main entity.
*/
getTPTAliasForProperty(propName: string, defaultAlias: string): string;
mapper(field: string | Raw | RawQueryFragmentSymbol, type?: QueryType): string;
mapper(
field: string | Raw | RawQueryFragmentSymbol,
type?: QueryType,
value?: any,
alias?: string | null,
schema?: string,
): string;
processData(data: Dictionary, convertCustomTypes: boolean, multi?: boolean): any;
joinOneToReference(
prop: EntityProperty,
ownerAlias: string,
alias: string,
type: JoinType,
cond?: Dictionary,
schema?: string,
): JoinOptions;
joinManyToOneReference(
prop: EntityProperty,
ownerAlias: string,
alias: string,
type: JoinType,
cond?: Dictionary,
schema?: string,
): JoinOptions;
joinManyToManyReference(
prop: EntityProperty,
ownerAlias: string,
alias: string,
pivotAlias: string,
type: JoinType,
cond: Dictionary,
path: string,
schema?: string,
): Dictionary<JoinOptions>;
processJoins(qb: NativeQueryBuilder, joins: Dictionary<JoinOptions>, schema?: string, schemaOverride?: string): void;
createJoinExpression(
join: JoinOptions,
joins: Dictionary<JoinOptions>,
schema?: string,
schemaOverride?: string,
): {
sql: string;
params: unknown[];
};
mapJoinColumns(type: QueryType, join: JoinOptions): (string | Raw)[];
isOneToOneInverse(field: string, meta?: EntityMetadata): boolean;
getTableName(entityName: EntityName): string;
/**
* Checks whether the RE can be rewritten to simple LIKE query
*/
isSimpleRegExp(re: any): re is RegExp;
getRegExpParam(re: RegExp): string;
appendOnConflictClause<T>(type: QueryType, onConflict: OnConflictClause<T>[], qb: NativeQueryBuilder): void;
appendQueryCondition(
type: QueryType,
cond: any,
qb: NativeQueryBuilder,
operator?: '$and' | '$or',
method?: 'where' | 'having',
): void;
_appendQueryCondition(
type: QueryType,
cond: any,
operator?: '$and' | '$or',
): {
sql: string;
params: unknown[];
};
private append;
private appendQuerySubCondition;
private processObjectSubCondition;
private getValueReplacement;
private getOperatorReplacement;
validateQueryOrder<T>(orderBy: QueryOrderMap<T>): void;
getQueryOrder(
type: QueryType,
orderBy: FlatQueryOrderMap | FlatQueryOrderMap[],
populate: Dictionary<string>,
collation?: string,
): string[];
getQueryOrderFromObject(
type: QueryType,
orderBy: FlatQueryOrderMap,
populate: Dictionary<string>,
collation?: string,
): string[];
splitField<T>(field: EntityKey<T>, greedyAlias?: boolean): [string, EntityKey<T>, string | undefined];
getLockSQL(
qb: NativeQueryBuilder,
lockMode: LockMode,
lockTables?: string[],
joinsMap?: Dictionary<JoinOptions>,
): void;
updateVersionProperty(qb: NativeQueryBuilder, data: Dictionary): void;
private prefix;
private appendGroupCondition;
private isPrefixed;
private fieldName;
getProperty(field: string, alias?: string): EntityProperty | undefined;
isTableNameAliasRequired(type: QueryType): boolean;
private processEmbeddedArrayCondition;
private buildJsonArrayExists;
private resolveEmbeddedProp;
private buildEmbeddedArrayOperatorCondition;
private processJsonElemMatch;
/**
* Shared logic for building WHERE conditions inside JSON array EXISTS subqueries.
* Used by both embedded array queries (metadata-driven) and $elemMatch (type-inferred).
*/
private buildArrayElementWhere;
private inferJsonValueType;
processOnConflictCondition(cond: FilterQuery<any>, schema?: string): FilterQuery<any>;
createFormulaTable(alias: string, meta: EntityMetadata, schema?: string): FormulaTable;
}
export interface Alias<T> {
aliasName: string;
entityName: EntityName<T>;
meta: EntityMetadata<T>;
subQuery?: NativeQueryBuilder | RawQueryFragment;
rawTableName?: string;
}
export interface OnConflictClause<T> {
fields: string[] | Raw;
ignore?: boolean;
merge?: EntityData<T> | InternalField<T>[];
where?: FilterQuery<T>;
}

1113
node_modules/@mikro-orm/sql/query/QueryBuilderHelper.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
import { CriteriaNode } from './CriteriaNode.js';
import type { ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
/**
* @internal
*/
export declare class ScalarCriteriaNode<T extends object> extends CriteriaNode<T> {
process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
private shouldJoin;
}

View File

@@ -0,0 +1,65 @@
import { ARRAY_OPERATORS, ReferenceKind } from '@mikro-orm/core';
import { CriteriaNode } from './CriteriaNode.js';
import { JoinType, QueryType } from './enums.js';
import { QueryBuilder } from './QueryBuilder.js';
/**
* @internal
*/
export class ScalarCriteriaNode extends CriteriaNode {
process(qb, options) {
const matchPopulateJoins =
options?.matchPopulateJoins ||
(this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
const nestedAlias = qb.getAliasForJoinPath(this.getPath(options), { ...options, matchPopulateJoins });
if (this.shouldJoin(qb, nestedAlias)) {
const path = this.getPath();
const parentPath = this.parent.getPath(); // the parent is always there, otherwise `shouldJoin` would return `false`
const nestedAlias = qb.getAliasForJoinPath(path) || qb.getNextAlias(this.prop?.pivotEntity ?? this.entityName);
const field = this.aliased(this.prop.name, options?.alias);
const type = this.prop.kind === ReferenceKind.MANY_TO_MANY ? JoinType.pivotJoin : JoinType.leftJoin;
qb.join(field, nestedAlias, undefined, type, path);
// select the owner as virtual property when joining from 1:1 inverse side, but only if the parent is root entity
if (
this.prop.kind === ReferenceKind.ONE_TO_ONE &&
!parentPath.includes('.') &&
!qb.state.fields?.includes(field)
) {
qb.addSelect(field);
}
}
if (this.payload instanceof QueryBuilder) {
return this.payload.toRaw();
}
if (this.payload && typeof this.payload === 'object') {
const keys = Object.keys(this.payload).filter(
key => ARRAY_OPERATORS.includes(key) && Array.isArray(this.payload[key]),
);
for (const key of keys) {
this.payload[key] = JSON.stringify(this.payload[key]);
}
}
return this.payload;
}
willAutoJoin(qb, alias, options) {
return this.shouldJoin(qb, alias);
}
shouldJoin(qb, nestedAlias) {
if (
!this.parent ||
!this.prop ||
(nestedAlias && [QueryType.SELECT, QueryType.COUNT].includes(qb.type ?? QueryType.SELECT))
) {
return false;
}
switch (this.prop.kind) {
case ReferenceKind.ONE_TO_MANY:
return true;
case ReferenceKind.MANY_TO_MANY:
return true;
case ReferenceKind.ONE_TO_ONE:
return !this.prop.owner;
default:
return false; // SCALAR, MANY_TO_ONE
}
}
}

22
node_modules/@mikro-orm/sql/query/enums.d.ts generated vendored Normal file
View File

@@ -0,0 +1,22 @@
/** Type of SQL query to be generated. */
export declare enum QueryType {
TRUNCATE = 'TRUNCATE',
SELECT = 'SELECT',
COUNT = 'COUNT',
INSERT = 'INSERT',
UPDATE = 'UPDATE',
DELETE = 'DELETE',
UPSERT = 'UPSERT',
}
/** Operators that apply to the embedded array column itself, not to individual elements. */
export declare const EMBEDDABLE_ARRAY_OPS: string[];
/** Type of SQL JOIN clause. */
export declare enum JoinType {
leftJoin = 'left join',
innerJoin = 'inner join',
nestedLeftJoin = 'nested left join',
nestedInnerJoin = 'nested inner join',
pivotJoin = 'pivot join',
innerJoinLateral = 'inner join lateral',
leftJoinLateral = 'left join lateral',
}

24
node_modules/@mikro-orm/sql/query/enums.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
/** Type of SQL query to be generated. */
export var QueryType;
(function (QueryType) {
QueryType['TRUNCATE'] = 'TRUNCATE';
QueryType['SELECT'] = 'SELECT';
QueryType['COUNT'] = 'COUNT';
QueryType['INSERT'] = 'INSERT';
QueryType['UPDATE'] = 'UPDATE';
QueryType['DELETE'] = 'DELETE';
QueryType['UPSERT'] = 'UPSERT';
})(QueryType || (QueryType = {}));
/** Operators that apply to the embedded array column itself, not to individual elements. */
export const EMBEDDABLE_ARRAY_OPS = ['$contains', '$contained', '$overlap'];
/** Type of SQL JOIN clause. */
export var JoinType;
(function (JoinType) {
JoinType['leftJoin'] = 'left join';
JoinType['innerJoin'] = 'inner join';
JoinType['nestedLeftJoin'] = 'nested left join';
JoinType['nestedInnerJoin'] = 'nested inner join';
JoinType['pivotJoin'] = 'pivot join';
JoinType['innerJoinLateral'] = 'inner join lateral';
JoinType['leftJoinLateral'] = 'left join lateral';
})(JoinType || (JoinType = {}));

10
node_modules/@mikro-orm/sql/query/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
export * from './enums.js';
export * from './QueryBuilderHelper.js';
export * from './QueryBuilder.js';
export * from './CriteriaNode.js';
export * from './ArrayCriteriaNode.js';
export * from './ObjectCriteriaNode.js';
export * from './ScalarCriteriaNode.js';
export * from './CriteriaNodeFactory.js';
export * from './NativeQueryBuilder.js';
export * from './raw.js';

10
node_modules/@mikro-orm/sql/query/index.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
export * from './enums.js';
export * from './QueryBuilderHelper.js';
export * from './QueryBuilder.js';
export * from './CriteriaNode.js';
export * from './ArrayCriteriaNode.js';
export * from './ObjectCriteriaNode.js';
export * from './ScalarCriteriaNode.js';
export * from './CriteriaNodeFactory.js';
export * from './NativeQueryBuilder.js';
export * from './raw.js';

77
node_modules/@mikro-orm/sql/query/raw.d.ts generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import { type AnyString, type Dictionary, type EntityKey, type RawQueryFragment } from '@mikro-orm/core';
import type { SelectQueryBuilder as KyselySelectQueryBuilder } from 'kysely';
/** @internal Type for QueryBuilder instances passed to raw() - uses toRaw to distinguish from Kysely QueryBuilder */
type QueryBuilderLike = {
toQuery(): {
sql: string;
params: readonly unknown[];
};
toRaw(): RawQueryFragment;
};
/**
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
* This adds a runtime safety to the raw query fragments.
*
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
*
* ```ts
* // as a value
* await em.find(User, { time: raw('now()') });
*
* // as a key
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
*
* // value can be empty array
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
* ```
*
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
*
* ```ts
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
* ```
*
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
*
* ```ts
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
* ```
*
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
*
* ```ts
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
* ```
*
* 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:
*
* ```ts
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
* @Entity({ schema: 'library' })
* export class Author { ... }
* ```
*
* 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:
*
* ```ts
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
* @Entity({ schema: 'library' })
* export class Author { ... }
* ```
*/
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;
export {};

67
node_modules/@mikro-orm/sql/query/raw.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { raw as raw_, Utils } from '@mikro-orm/core';
/**
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
* This adds a runtime safety to the raw query fragments.
*
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
*
* ```ts
* // as a value
* await em.find(User, { time: raw('now()') });
*
* // as a key
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
*
* // value can be empty array
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
* ```
*
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
*
* ```ts
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
* ```
*
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
*
* ```ts
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
* ```
*
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
*
* ```ts
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
* ```
*
* 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:
*
* ```ts
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
* @Entity({ schema: 'library' })
* export class Author { ... }
* ```
*
* 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:
*
* ```ts
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
* @Entity({ schema: 'library' })
* export class Author { ... }
* ```
*/
export function raw(sql, params) {
if (Utils.isObject(sql) && 'compile' in sql) {
const query = sql.compile();
return raw_(query.sql, query.parameters);
}
if (Utils.isObject(sql) && 'toQuery' in sql) {
const query = sql.toQuery();
return raw_(query.sql, query.params);
}
return raw_(sql, params);
}