import clone from 'clone' ; import { EntityRepository } from '../entity' ; import type { NamingStrategy } from '../naming-strategy' ; import { UnderscoreNamingStrategy } from '../naming-strategy' ; import type { AnyEntity , Constructor , EntityProperty , IEntityGenerator , IMigrator , IPrimaryKey , ISchemaGenerator , PopulateOptions , Primary , EntityMetadata } from '../typings' ; import { ExceptionConverter } from './ExceptionConverter' ; import type { EntityManager } from '../EntityManager' ; import type { Configuration } from '../utils/Configuration' ; import { ArrayType , BigIntType , BlobType , BooleanType , DateType , DecimalType , DoubleType , JsonType , SmallIntType , TimeType , TinyIntType , Type , UuidType , StringType , IntegerType , FloatType , DateTimeType , TextType , EnumType , UnknownType , } from '../types' ; import { Utils } from '../utils/Utils' ; import { ReferenceType } from '../enums' ; export const JsonProperty = Symbol ( 'JsonProperty' ) ; export abstract class Platform { protected readonly exceptionConverter = new ExceptionConverter ( ) ; protected config ! : Configuration ; protected namingStrategy ! : NamingStrategy ; protected timezone ? : string ; usesPivotTable ( ) { return false ; } supportsTransactions ( ) { return true ; } usesImplicitTransactions ( ) { return true ; } getNamingStrategy ( ) { return UnderscoreNamingStrategy ; } usesReturningStatement ( ) { return false ; } usesCascadeStatement ( ) { return false ; } getSchemaHelper ( ) { return undefined ; } indexForeignKeys ( ) { return false ; } allowsMultiInsert ( ) { return true ; } /**
     * Whether or not the driver supports retuning list of created PKs back when multi-inserting
     */ usesBatchInserts ( ) { return true ; } /**
     * Whether or not the driver supports updating many records at once
     */ usesBatchUpdates ( ) { return true ; } usesDefaultKeyword ( ) { return true ; } /**
     * Normalizes primary key wrapper to scalar value (e.g. mongodb's ObjectId to string)
     */ normalizePrimaryKey < T extends number | string = number | string > ( data ) { return data as T ; } /**
     * Converts scalar primary key representation to native driver wrapper (e.g. string to mongodb's ObjectId)
     */ denormalizePrimaryKey ( data ) { return data ; } /**
     * Used when serializing via toObject and toJSON methods, allows to use different PK field name (like `id` instead of `_id`)
     */ getSerializedPrimaryKeyField ( field ) { return field ; } usesDifferentSerializedPrimaryKey ( ) { return false ; } /**
     * Returns the SQL specific for the platform to get the current timestamp
     */ getCurrentTimestampSQL ( length ? ) { return 'current_timestamp' + ( length ? `(${ length })` : '' ) ; } getDateTimeTypeDeclarationSQL ( column ) { return 'datetime' + ( column . length ? `(${ column . length })` : '' ) ; } getDateTypeDeclarationSQL ( length ? ) { return 'date' + ( length ? `(${ length })` : '' ) ; } getTimeTypeDeclarationSQL ( length ? ) { return 'time' + ( length ? `(${ length })` : '' ) ; } getRegExpOperator ( ) { return 'regexp' ; } quoteVersionValue ( value , prop ) { return value ; } getDefaultVersionLength ( ) { return 3 ; } requiresValuesKeyword ( ) { return false ; } allowsComparingTuples ( ) { return true ; } allowsUniqueBatchUpdates ( ) { return true ; } isBigIntProperty ( prop ) { return prop . columnTypes && prop . columnTypes [ 0 ] === 'bigint' ; } isRaw ( value ) { return typeof value === 'object' && value !== null && '__raw' in value ; } getDefaultSchemaName ( ) { return undefined ; } getBooleanTypeDeclarationSQL ( ) { return 'boolean' ; } getIntegerTypeDeclarationSQL ( column ) { return 'int' ; } getSmallIntTypeDeclarationSQL ( column ) { return 'smallint' ; } getTinyIntTypeDeclarationSQL ( column ) { return 'tinyint' ; } getBigIntTypeDeclarationSQL ( column ) { return 'bigint' ; } getVarcharTypeDeclarationSQL ( column ) { return `varchar(${ column . length ?? 255 })` ; } getTextTypeDeclarationSQL ( _column ) { return `text` ; } getEnumTypeDeclarationSQL ( column ) { if ( column . items ?. every ( item => Utils . isString ( item ) ) ) { return `enum('${ column . items . join ( "', '" ) }')` ; } return this . getTinyIntTypeDeclarationSQL ( column ) ; } getFloatDeclarationSQL ( ) { return 'float' ; } getDoubleDeclarationSQL ( ) { return 'double' ; } getDecimalTypeDeclarationSQL ( column ) { const precision = column . precision ?? 10 ; const scale = column . scale ?? 0 ; return `numeric(${ precision },${ scale })` ; } getUuidTypeDeclarationSQL ( column ) { column . length ??= 36 ; return this . getVarcharTypeDeclarationSQL ( column ) ; } extractSimpleType ( type ) { return type . toLowerCase ( ) . match ( /[^(), ]+/ ) ! [ 0 ] ; } getMappedType ( type ) { if ( type . endsWith ( '[]' ) ) { return Type . getType ( ArrayType ) ; } switch ( this . extractSimpleType ( type ) ) { case 'string' : return Type . getType ( StringType ) ; case 'varchar' : return Type . getType ( StringType ) ; case 'text' : return Type . getType ( TextType ) ; case 'number' : return Type . getType ( IntegerType ) ; case 'bigint' : return Type . getType ( BigIntType ) ; case 'smallint' : return Type . getType ( SmallIntType ) ; case 'tinyint' : return Type . getType ( TinyIntType ) ; case 'float' : return Type . getType ( FloatType ) ; case 'double' : return Type . getType ( DoubleType ) ; case 'integer' : return Type . getType ( IntegerType ) ; case 'decimal' : case 'numeric' : return Type . getType ( DecimalType ) ; case 'boolean' : return Type . getType ( BooleanType ) ; case 'blob' : case 'buffer' : return Type . getType ( BlobType ) ; case 'uuid' : return Type . getType ( UuidType ) ; case 'date' : return Type . getType ( DateType ) ; case 'datetime' : return Type . getType ( DateTimeType ) ; case 'time' : return Type . getType ( TimeType ) ; case 'object' : case 'json' : return Type . getType ( JsonType ) ; case 'enum' : return Type . getType ( EnumType ) ; default : return Type . getType ( UnknownType ) ; } } getArrayDeclarationSQL ( ) { return 'text' ; } getDefaultIntegrityRule ( ) { return 'restrict' ; } marshallArray ( values ) { return values . join ( ',' ) ; } unmarshallArray ( value ) { if ( value === '' ) { return [ ] ; } return value . split ( ',' ) as string [ ] ; } getBlobDeclarationSQL ( ) { return 'blob' ; } getJsonDeclarationSQL ( ) { return 'json' ; } getSearchJsonPropertySQL ( path , type ) { return path ; } getSearchJsonPropertyKey ( path , type ) { return path . join ( '.' ) ; } convertsJsonAutomatically ( marshall = false ) { return ! marshall ; } getRepositoryClass < T > ( ) { return EntityRepository ; } getDefaultCharset ( ) { return 'utf8' ; } getExceptionConverter ( ) { return this . exceptionConverter ; } getSchemaGenerator ( em ) { throw new Error ( `${ this . constructor . name } does not support SchemaGenerator` ) ; } getEntityGenerator ( em ) { throw new Error ( `${ this . constructor . name } does not support EntityGenerator` ) ; } getMigrator ( em ) { throw new Error ( `${ this . constructor . name } does not support Migrator` ) ; } processDateProperty ( value ) { return value as string ; } quoteIdentifier ( id , quote = '`' ) { return `${ quote }${ id . replace ( '.' , `${ quote }.${ quote }` ) }${ quote }` ; } quoteValue ( value ) { return value ; } cloneEmbeddable < T > ( data ) { const copy = clone ( data ) ; Object . defineProperty ( copy , JsonProperty , { enumerable : false , value : true } ) ; return copy ; } setConfig ( config ) { this . config = config ; this . namingStrategy = config . getNamingStrategy ( ) ; if ( this . config . get ( 'forceUtcTimezone' ) ) { this . timezone = 'Z' ; } else { this . timezone = this . config . get ( 'timezone' ) ; } } isNumericColumn ( mappedType ) { return [ IntegerType , SmallIntType , BigIntType ] . some ( t => mappedType instanceof t ) ; } supportsUnsigned ( ) { return false ; } /**
     * Returns the default name of index for the given columns
     */ getIndexName ( tableName , columns , type ) { return this . namingStrategy . indexName ( tableName , columns , type ) ; } shouldHaveColumn < T extends AnyEntity < T > > ( prop , populate , includeFormulas = true ) { if ( prop . formula ) { return includeFormulas && ( ! prop . lazy || populate === true || ( populate !== false && populate . some ( p => p . field === prop . name ) ) ) ; } if ( prop . persist === false ) { return false ; } if ( prop . lazy && ( populate === false || ( populate !== true && ! populate . some ( p => p . field === prop . name ) ) ) ) { return false ; } return [ ReferenceType . SCALAR , ReferenceType . MANY_TO_ONE ] . includes ( prop . reference ) || ( prop . reference === ReferenceType . ONE_TO_ONE && prop . owner ) ; } /**
     * Currently not supported due to how knex does complex sqlite diffing (always based on current schema)
     */ supportsDownMigrations ( ) { return true ; } validateMetadata ( meta ) { return ; } /**
     * Generates a custom order by statement given a set of in order values, eg.
     * ORDER BY (CASE WHEN priority = 'low' THEN 1 WHEN priority = 'medium' THEN 2 ELSE NULL END)
     */ generateCustomOrder ( escapedColumn , values ) { throw new Error ( 'Not supported' ) ; } }