UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

119 lines (116 loc) 5.42 kB
import crypto from 'node:crypto'; import { getDefaultIndexName } from '../../../../utils/get-default-index-name.js'; import { SchemaHelper } from '../types.js'; import { prepQueryParams } from '../utils/prep-query-params.js'; export class SchemaHelperOracle extends SchemaHelper { generateIndexName(type, collection, fields) { // Backwards compatibility with oracle requires no hash added to the name. let indexName = getDefaultIndexName(type, collection, fields, { maxLength: Infinity }); // Knex generates a hash of the name if it is above the allowed value // https://github.com/knex/knex/blob/master/lib/dialects/oracle/utils.js#L20 if (indexName.length > 128) { // generates the sha1 of the name and encode it with base64 indexName = crypto.createHash('sha1').update(indexName).digest('base64').replace('=', ''); } return indexName; } async changeToType(table, column, type, options = {}) { await this.changeToTypeByCopy(table, column, type, options); } castA2oPrimaryKey() { return 'CAST(?? AS VARCHAR2(255))'; } preRelationChange(relation) { if (relation.collection === relation.related_collection) { // Constraints are not allowed on self referencing relationships // Setting NO ACTION throws - ORA-00905: missing keyword if (relation.schema?.on_delete) { relation.schema.on_delete = null; } } } processFieldType(field) { if (field.type === 'integer') { if (field.schema?.numeric_precision === 20) { return 'bigInteger'; } else if (field.schema?.numeric_precision === 1) { return 'boolean'; } else if (field.schema?.numeric_precision || field.schema?.numeric_scale) { return 'decimal'; } } return field.type; } async getDatabaseSize() { try { const result = await this.knex.raw('select SUM(bytes) from dba_segments'); return result[0]?.['SUM(BYTES)'] ? Number(result[0]?.['SUM(BYTES)']) : null; } catch { return null; } } /** * Oracle throws an error when overwriting the nullable option for an existing column with the same value. */ setNullable(column, field, existing) { if (!existing) { super.setNullable(column, field, existing); return; } if (field.schema?.is_nullable === false && existing.is_nullable === true) { column.notNullable(); } else if (field.schema?.is_nullable === true && existing.is_nullable === false) { column.nullable(); } } prepQueryParams(queryParams) { return prepQueryParams(queryParams, { format: (index) => `:${index + 1}` }); } prepBindings(bindings) { // Create an object with keys 1, 2, 3, ... and the bindings as values // This will use the "named" binding syntax in the oracledb driver instead of the positional binding return Object.fromEntries(bindings.map((binding, index) => [index + 1, binding])); } addInnerSortFieldsToGroupBy(groupByFields, sortRecords, _hasRelationalSort) { /* Oracle requires all selected columns that are not aggregated over to be present in the GROUP BY clause aliases can not be used before version 23c. > If you also specify a group_by_clause in this statement, then this select list can contain only the following types of expressions: * Constants * Aggregate functions and the functions USER, UID, and SYSDATE * Expressions identical to those in the group_by_clause. If the group_by_clause is in a subquery, then all columns in the select list of the subquery must match the GROUP BY columns in the subquery. If the select list and GROUP BY columns of a top-level query or of a subquery do not match, then the statement results in ORA-00979. * Expressions involving the preceding expressions that evaluate to the same value for all rows in a group https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html */ if (sortRecords.length > 0) { groupByFields.push(...sortRecords.map(({ column }) => column)); } } getColumnNameMaxLength() { return 128; } getTableNameMaxLength() { return 128; } async createIndex(collection, field, options = {}) { const isUnique = Boolean(options.unique); const constraintName = this.generateIndexName(isUnique ? 'unique' : 'index', collection, field); if (options.attemptConcurrentIndex) { // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-INDEX.html#GUID-1F89BBC0-825F-4215-AF71-7588E31D8BFE__GUID-041E5429-065B-43D5-AC7F-66810140842C return this.knex.raw(`CREATE ${isUnique ? 'UNIQUE ' : ''}INDEX ?? ON ?? (??) ONLINE`, [ constraintName, collection, field, ]); } return this.knex.raw(`CREATE ${isUnique ? 'UNIQUE ' : ''}INDEX ?? ON ?? (??)`, [constraintName, collection, field]); } }