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,363 @@
import { ALIAS_REPLACEMENT, ARRAY_OPERATORS, raw, RawQueryFragment, Type, Utils } from '@mikro-orm/core';
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
import { PostgreSqlNativeQueryBuilder } from './PostgreSqlNativeQueryBuilder.js';
import { PostgreSqlSchemaHelper } from './PostgreSqlSchemaHelper.js';
import { PostgreSqlExceptionConverter } from './PostgreSqlExceptionConverter.js';
import { FullTextType } from './FullTextType.js';
export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
schemaHelper = new PostgreSqlSchemaHelper(this);
exceptionConverter = new PostgreSqlExceptionConverter();
/** Maps JS runtime type names to PostgreSQL cast types for JSON property access. @internal */
#jsonTypeCasts = { number: 'float8', bigint: 'int8', boolean: 'bool' };
createNativeQueryBuilder() {
return new PostgreSqlNativeQueryBuilder(this);
}
usesReturningStatement() {
return true;
}
usesCascadeStatement() {
return true;
}
supportsNativeEnums() {
return true;
}
usesEnumCheckConstraints() {
return true;
}
supportsMaterializedViews() {
return true;
}
supportsCustomPrimaryKeyNames() {
return true;
}
getCurrentTimestampSQL(length) {
return `current_timestamp(${length})`;
}
getDateTimeTypeDeclarationSQL(column) {
/* v8 ignore next */
return 'timestamptz' + (column.length != null ? `(${column.length})` : '');
}
getDefaultDateTimeLength() {
return 6;
}
getTimeTypeDeclarationSQL() {
return 'time(0)';
}
getIntegerTypeDeclarationSQL(column) {
if (column.autoincrement && !column.generated) {
return 'serial';
}
return 'int';
}
getBigIntTypeDeclarationSQL(column) {
/* v8 ignore next */
if (column.autoincrement) {
return `bigserial`;
}
return 'bigint';
}
getTinyIntTypeDeclarationSQL(column) {
return 'smallint';
}
getUuidTypeDeclarationSQL(column) {
return `uuid`;
}
getFullTextWhereClause(prop) {
if (prop.customType instanceof FullTextType) {
return `:column: @@ plainto_tsquery('${prop.customType.regconfig}', :query)`;
}
/* v8 ignore next */
if (prop.columnTypes[0] === 'tsvector') {
return `:column: @@ plainto_tsquery('simple', :query)`;
}
return `to_tsvector('simple', :column:) @@ plainto_tsquery('simple', :query)`;
}
supportsCreatingFullTextIndex() {
return true;
}
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);
if (columns.length === 1 && columns[0].type === 'tsvector') {
return `create index ${quotedIndexName} on ${quotedTableName} using gin(${quotedColumnNames[0]})`;
}
return `create index ${quotedIndexName} on ${quotedTableName} using gin(to_tsvector('simple', ${quotedColumnNames.join(` || ' ' || `)}))`;
}
normalizeColumnType(type, options) {
const simpleType = this.extractSimpleType(type);
if (['int', 'int4', 'integer'].includes(simpleType)) {
return this.getIntegerTypeDeclarationSQL({});
}
if (['bigint', 'int8'].includes(simpleType)) {
return this.getBigIntTypeDeclarationSQL({});
}
if (['smallint', 'int2'].includes(simpleType)) {
return this.getSmallIntTypeDeclarationSQL({});
}
if (['boolean', 'bool'].includes(simpleType)) {
return this.getBooleanTypeDeclarationSQL();
}
if (['varchar', 'character varying'].includes(simpleType)) {
return this.getVarcharTypeDeclarationSQL(options);
}
if (['char', 'bpchar'].includes(simpleType)) {
return this.getCharTypeDeclarationSQL(options);
}
if (['decimal', 'numeric'].includes(simpleType)) {
return this.getDecimalTypeDeclarationSQL(options);
}
if (['interval'].includes(simpleType)) {
return this.getIntervalTypeDeclarationSQL(options);
}
return super.normalizeColumnType(type, options);
}
getMappedType(type) {
switch (this.extractSimpleType(type)) {
case 'tsvector':
return Type.getType(FullTextType);
default:
return super.getMappedType(type);
}
}
getRegExpOperator(val, flags) {
/* v8 ignore next */
if ((val instanceof RegExp && val.flags.includes('i')) || flags?.includes('i')) {
return '~*';
}
return '~';
}
/* v8 ignore next */
getRegExpValue(val) {
if (val.flags.includes('i')) {
return { $re: val.source, $flags: val.flags };
}
return { $re: val.source };
}
isBigIntProperty(prop) {
return super.isBigIntProperty(prop) || ['bigserial', 'int8'].includes(prop.columnTypes?.[0]);
}
getArrayDeclarationSQL() {
return 'text[]';
}
getFloatDeclarationSQL() {
return 'real';
}
getDoubleDeclarationSQL() {
return 'double precision';
}
getEnumTypeDeclarationSQL(column) {
/* v8 ignore next */
if (column.nativeEnumName) {
return column.nativeEnumName;
}
if (column.items?.every(item => typeof item === 'string')) {
return 'text';
}
return `smallint`;
}
supportsMultipleStatements() {
return true;
}
getBeginTransactionSQL(options) {
if (options?.isolationLevel || options?.readOnly) {
let sql = 'start transaction';
sql += options.isolationLevel ? ` isolation level ${options.isolationLevel}` : '';
sql += options.readOnly ? ` read only` : '';
return [sql];
}
return ['begin'];
}
marshallArray(values) {
const quote = v => (v === '' || /["{},\\]/.exec(v) ? JSON.stringify(v) : v);
return `{${values.map(v => quote('' + v)).join(',')}}`;
}
/* v8 ignore next */
unmarshallArray(value) {
if (value === '{}') {
return [];
}
return value
.substring(1, value.length - 1)
.split(',')
.map(v => {
if (v === `""`) {
return '';
}
if (/"(.*)"/.exec(v)) {
return v.substring(1, v.length - 1).replaceAll('\\"', '"');
}
return v;
});
}
getVarcharTypeDeclarationSQL(column) {
if (column.length === -1) {
return 'varchar';
}
return super.getVarcharTypeDeclarationSQL(column);
}
getCharTypeDeclarationSQL(column) {
if (column.length === -1) {
return 'char';
}
return super.getCharTypeDeclarationSQL(column);
}
getIntervalTypeDeclarationSQL(column) {
return 'interval' + (column.length != null ? `(${column.length})` : '');
}
getBlobDeclarationSQL() {
return 'bytea';
}
getJsonDeclarationSQL() {
return 'jsonb';
}
getSearchJsonPropertyKey(path, type, aliased, value) {
const first = path.shift();
const last = path.pop();
const root = this.quoteIdentifier(aliased ? `${ALIAS_REPLACEMENT}.${first}` : first);
type = typeof type === 'string' ? this.getMappedType(type).runtimeType : String(type);
const cast = key => raw(type in this.#jsonTypeCasts ? `(${key})::${this.#jsonTypeCasts[type]}` : key);
let lastOperator = '->>';
// force `->` for operator payloads with array values
if (
Utils.isPlainObject(value) &&
Object.keys(value).every(key => ARRAY_OPERATORS.includes(key) && Array.isArray(value[key]))
) {
lastOperator = '->';
}
if (path.length === 0) {
return cast(`${root}${lastOperator}'${last}'`);
}
return cast(`${root}->${path.map(a => this.quoteValue(a)).join('->')}${lastOperator}'${last}'`);
}
getJsonIndexDefinition(index) {
return index.columnNames.map(column => {
if (!column.includes('.')) {
return column;
}
const path = column.split('.');
const first = path.shift();
const last = path.pop();
if (path.length === 0) {
return `(${this.quoteIdentifier(first)}->>${this.quoteValue(last)})`;
}
return `(${this.quoteIdentifier(first)}->${path.map(c => this.quoteValue(c)).join('->')}->>${this.quoteValue(last)})`;
});
}
quoteIdentifier(id, quote = '"') {
if (RawQueryFragment.isKnownFragment(id)) {
return super.quoteIdentifier(id);
}
return `${quote}${id.toString().replace('.', `${quote}.${quote}`)}${quote}`;
}
pad(number, digits) {
return String(number).padStart(digits, '0');
}
/** @internal */
formatDate(date) {
if (this.timezone === 'Z') {
return date.toISOString();
}
let offset = -date.getTimezoneOffset();
let year = date.getFullYear();
const isBCYear = year < 1;
/* v8 ignore next */
if (isBCYear) {
year = Math.abs(year) + 1;
}
const datePart = `${this.pad(year, 4)}-${this.pad(date.getMonth() + 1, 2)}-${this.pad(date.getDate(), 2)}`;
const timePart = `${this.pad(date.getHours(), 2)}:${this.pad(date.getMinutes(), 2)}:${this.pad(date.getSeconds(), 2)}.${this.pad(date.getMilliseconds(), 3)}`;
let ret = `${datePart}T${timePart}`;
/* v8 ignore next */
if (offset < 0) {
ret += '-';
offset *= -1;
} else {
ret += '+';
}
ret += this.pad(Math.floor(offset / 60), 2) + ':' + this.pad(offset % 60, 2);
/* v8 ignore next */
if (isBCYear) {
ret += ' BC';
}
return ret;
}
indexForeignKeys() {
return false;
}
getDefaultMappedType(type) {
const normalizedType = this.extractSimpleType(type);
const map = {
int2: 'smallint',
smallserial: 'smallint',
int: 'integer',
int4: 'integer',
serial: 'integer',
serial4: 'integer',
int8: 'bigint',
bigserial: 'bigint',
serial8: 'bigint',
numeric: 'decimal',
bool: 'boolean',
real: 'float',
float4: 'float',
float8: 'double',
timestamp: 'datetime',
timestamptz: 'datetime',
bytea: 'blob',
jsonb: 'json',
'character varying': 'varchar',
bpchar: 'character',
};
return super.getDefaultMappedType(map[normalizedType] ?? type);
}
supportsSchemas() {
return true;
}
getDefaultSchemaName() {
return 'public';
}
/**
* Returns the default name of index for the given columns
* cannot go past 63 character length for identifiers in MySQL
*/
getIndexName(tableName, columns, type) {
const indexName = super.getIndexName(tableName, columns, type);
if (indexName.length > 63) {
const suffix = type === 'primary' ? 'pkey' : type;
return `${indexName.substring(0, 55 - type.length)}_${Utils.hash(indexName, 5)}_${suffix}`;
}
return indexName;
}
getDefaultPrimaryName(tableName, columns) {
const indexName = `${tableName}_pkey`;
if (indexName.length > 63) {
return `${indexName.substring(0, 55 - 'pkey'.length)}_${Utils.hash(indexName, 5)}_pkey`;
}
return indexName;
}
/**
* @inheritDoc
*/
castColumn(prop) {
switch (prop?.columnTypes?.[0]) {
case this.getUuidTypeDeclarationSQL({}):
return '::text';
case this.getBooleanTypeDeclarationSQL():
return '::int';
default:
return '';
}
}
getJsonArrayFromSQL(column, alias, _properties) {
return `jsonb_array_elements(${column}) as ${this.quoteIdentifier(alias)}`;
}
getJsonArrayElementPropertySQL(alias, property, type) {
const expr = `${this.quoteIdentifier(alias)}->>${this.quoteValue(property)}`;
return type in this.#jsonTypeCasts ? `(${expr})::${this.#jsonTypeCasts[type]}` : expr;
}
getDefaultClientUrl() {
return 'postgresql://postgres@127.0.0.1:5432';
}
}