Initial commit - Event Planner application
This commit is contained in:
11
node_modules/@mikro-orm/sql/query/ArrayCriteriaNode.d.ts
generated
vendored
Normal file
11
node_modules/@mikro-orm/sql/query/ArrayCriteriaNode.d.ts
generated
vendored
Normal 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
24
node_modules/@mikro-orm/sql/query/ArrayCriteriaNode.js
generated
vendored
Normal 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
43
node_modules/@mikro-orm/sql/query/CriteriaNode.d.ts
generated
vendored
Normal 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
150
node_modules/@mikro-orm/sql/query/CriteriaNode.js
generated
vendored
Normal 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)}`;
|
||||
}
|
||||
}
|
||||
55
node_modules/@mikro-orm/sql/query/CriteriaNodeFactory.d.ts
generated
vendored
Normal file
55
node_modules/@mikro-orm/sql/query/CriteriaNodeFactory.d.ts
generated
vendored
Normal 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>;
|
||||
}
|
||||
111
node_modules/@mikro-orm/sql/query/CriteriaNodeFactory.js
generated
vendored
Normal file
111
node_modules/@mikro-orm/sql/query/CriteriaNodeFactory.js
generated
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
137
node_modules/@mikro-orm/sql/query/NativeQueryBuilder.d.ts
generated
vendored
Normal file
137
node_modules/@mikro-orm/sql/query/NativeQueryBuilder.d.ts
generated
vendored
Normal 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
490
node_modules/@mikro-orm/sql/query/NativeQueryBuilder.js
generated
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
19
node_modules/@mikro-orm/sql/query/ObjectCriteriaNode.d.ts
generated
vendored
Normal file
19
node_modules/@mikro-orm/sql/query/ObjectCriteriaNode.d.ts
generated
vendored
Normal 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
324
node_modules/@mikro-orm/sql/query/ObjectCriteriaNode.js
generated
vendored
Normal 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
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
2312
node_modules/@mikro-orm/sql/query/QueryBuilder.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
node_modules/@mikro-orm/sql/query/QueryBuilderHelper.d.ts
generated
vendored
Normal file
166
node_modules/@mikro-orm/sql/query/QueryBuilderHelper.d.ts
generated
vendored
Normal 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
1113
node_modules/@mikro-orm/sql/query/QueryBuilderHelper.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
node_modules/@mikro-orm/sql/query/ScalarCriteriaNode.d.ts
generated
vendored
Normal file
10
node_modules/@mikro-orm/sql/query/ScalarCriteriaNode.d.ts
generated
vendored
Normal 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;
|
||||
}
|
||||
65
node_modules/@mikro-orm/sql/query/ScalarCriteriaNode.js
generated
vendored
Normal file
65
node_modules/@mikro-orm/sql/query/ScalarCriteriaNode.js
generated
vendored
Normal 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
22
node_modules/@mikro-orm/sql/query/enums.d.ts
generated
vendored
Normal 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
24
node_modules/@mikro-orm/sql/query/enums.js
generated
vendored
Normal 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
10
node_modules/@mikro-orm/sql/query/index.d.ts
generated
vendored
Normal 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
10
node_modules/@mikro-orm/sql/query/index.js
generated
vendored
Normal 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
77
node_modules/@mikro-orm/sql/query/raw.d.ts
generated
vendored
Normal 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
67
node_modules/@mikro-orm/sql/query/raw.js
generated
vendored
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user