Files
evento/node_modules/@mikro-orm/sql/dialects/mysql/BaseMySqlPlatform.js
2026-03-18 14:55:56 -03:00

141 lines
4.9 KiB
JavaScript

import { Utils, QueryOrder, DecimalType, DoubleType } from '@mikro-orm/core';
import { MySqlSchemaHelper } from './MySqlSchemaHelper.js';
import { MySqlExceptionConverter } from './MySqlExceptionConverter.js';
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
import { MySqlNativeQueryBuilder } from './MySqlNativeQueryBuilder.js';
export class BaseMySqlPlatform extends AbstractSqlPlatform {
schemaHelper = new MySqlSchemaHelper(this);
exceptionConverter = new MySqlExceptionConverter();
#jsonTypeCasts = {
string: 'text',
number: 'double',
bigint: 'bigint',
boolean: 'unsigned',
};
ORDER_BY_NULLS_TRANSLATE = {
[QueryOrder.asc_nulls_first]: 'is not null',
[QueryOrder.asc_nulls_last]: 'is null',
[QueryOrder.desc_nulls_first]: 'is not null',
[QueryOrder.desc_nulls_last]: 'is null',
};
/** @internal */
createNativeQueryBuilder() {
return new MySqlNativeQueryBuilder(this);
}
getDefaultCharset() {
return 'utf8mb4';
}
init(orm) {
super.init(orm);
orm.config.get('schemaGenerator').disableForeignKeysForClear ??= true;
}
getBeginTransactionSQL(options) {
if (options?.isolationLevel || options?.readOnly) {
const parts = [];
if (options.isolationLevel) {
parts.push(`isolation level ${options.isolationLevel}`);
}
if (options.readOnly) {
parts.push('read only');
}
const sql = `set transaction ${parts.join(', ')}`;
return [sql, 'begin'];
}
return ['begin'];
}
convertJsonToDatabaseValue(value, context) {
if (context?.mode === 'query') {
return value;
}
return JSON.stringify(value);
}
getJsonIndexDefinition(index) {
return index.columnNames.map(column => {
if (!column.includes('.')) {
return column;
}
const [root, ...path] = column.split('.');
return `(json_value(${this.quoteIdentifier(root)}, '$.${path.join('.')}' returning ${index.options?.returning ?? 'char(255)'}))`;
});
}
getBooleanTypeDeclarationSQL() {
return 'tinyint(1)';
}
normalizeColumnType(type, options) {
const simpleType = this.extractSimpleType(type);
if (['decimal', 'numeric'].includes(simpleType)) {
return this.getDecimalTypeDeclarationSQL(options);
}
return type;
}
getDefaultMappedType(type) {
if (type === 'tinyint(1)') {
return super.getDefaultMappedType('boolean');
}
return super.getDefaultMappedType(type);
}
isNumericColumn(mappedType) {
return super.isNumericColumn(mappedType) || [DecimalType, DoubleType].some(t => mappedType instanceof t);
}
supportsUnsigned() {
return true;
}
/**
* Returns the default name of index for the given columns
* cannot go past 64 character length for identifiers in MySQL
*/
getIndexName(tableName, columns, type) {
if (type === 'primary') {
return this.getDefaultPrimaryName(tableName, columns);
}
const indexName = super.getIndexName(tableName, columns, type);
if (indexName.length > 64) {
return `${indexName.substring(0, 56 - type.length)}_${Utils.hash(indexName, 5)}_${type}`;
}
return indexName;
}
getDefaultPrimaryName(tableName, columns) {
return 'PRIMARY'; // https://dev.mysql.com/doc/refman/8.0/en/create-table.html#create-table-indexes-keys
}
supportsCreatingFullTextIndex() {
return true;
}
getFullTextWhereClause() {
return `match(:column:) against (:query in boolean mode)`;
}
getFullTextIndexExpression(indexName, schemaName, tableName, columns) {
/* v8 ignore next */
const quotedTableName = this.quoteIdentifier(schemaName ? `${schemaName}.${tableName}` : tableName);
const quotedColumnNames = columns.map(c => this.quoteIdentifier(c.name));
const quotedIndexName = this.quoteIdentifier(indexName);
return `alter table ${quotedTableName} add fulltext index ${quotedIndexName}(${quotedColumnNames.join(',')})`;
}
getOrderByExpression(column, direction, collation) {
const ret = [];
const dir = direction.toLowerCase();
const col = collation ? `${column} collate ${this.quoteCollation(collation)}` : column;
if (dir in this.ORDER_BY_NULLS_TRANSLATE) {
ret.push(`${col} ${this.ORDER_BY_NULLS_TRANSLATE[dir]}`);
}
ret.push(`${col} ${dir.replace(/(\s|nulls|first|last)*/gi, '')}`);
return ret;
}
getJsonArrayFromSQL(column, alias, properties) {
const columns = properties
.map(
p =>
`${this.quoteIdentifier(p.name)} ${this.#jsonTypeCasts[p.type] ?? 'text'} path '$.${this.quoteJsonKey(p.name)}'`,
)
.join(', ');
return `json_table(${column}, '$[*]' columns (${columns})) as ${this.quoteIdentifier(alias)}`;
}
// MySQL does not support correlated json_table inside EXISTS subqueries,
// so we use a semi-join via the comma-join pattern instead.
getJsonArrayExistsSQL(from, where) {
return `(select 1 from ${from} where ${where} limit 1) is not null`;
}
getDefaultClientUrl() {
return 'mysql://root@127.0.0.1:3306';
}
}