From 58e024d3ad6ea682f2aa28a28ebe6589cc06c4ce Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Wed, 22 Sep 2021 10:49:43 +0200 Subject: [PATCH] use columnName snake casing and rename timestamp attributes --- .../content-types/category/schema.json | 4 +- .../content-types/restaurant/schema.json | 10 +- .../admin/server/tests/admin-role.test.e2e.js | 2 +- .../admin/server/tests/admin-user.test.e2e.js | 2 +- .../content-manager/tests/index.test.e2e.js | 2 - packages/core/database/lib/entity-manager.js | 13 +- .../lib/lifecycles/subscribers/timestamps.js | 16 +- packages/core/database/lib/metadata/index.js | 171 ++++++++---------- .../database/lib/query/helpers/order-by.js | 12 +- .../core/database/lib/query/helpers/search.js | 38 ++-- .../database/lib/query/helpers/transform.js | 60 ++++-- .../core/database/lib/query/helpers/where.js | 17 +- .../core/database/lib/query/query-builder.js | 20 +- packages/core/database/lib/schema/schema.js | 10 +- .../strapi/lib/migrations/draft-publish.js | 2 +- .../utils/lib/__tests__/content-types.test.js | 4 +- packages/core/utils/lib/content-types.js | 4 +- .../plugins/i18n/tests/locales.test.e2e.js | 2 +- 18 files changed, 205 insertions(+), 184 deletions(-) diff --git a/examples/getstarted/src/api/category/content-types/category/schema.json b/examples/getstarted/src/api/category/content-types/category/schema.json index 56edad7ff4..ae853d7983 100755 --- a/examples/getstarted/src/api/category/content-types/category/schema.json +++ b/examples/getstarted/src/api/category/content-types/category/schema.json @@ -5,12 +5,14 @@ "displayName": "Category", "singularName": "category", "pluralName": "categories", - "description": "" + "description": "", + "name": "Category" }, "options": { "draftAndPublish": true, "comment": "" }, + "pluginOptions": {}, "attributes": { "name": { "type": "string" diff --git a/examples/getstarted/src/api/restaurant/content-types/restaurant/schema.json b/examples/getstarted/src/api/restaurant/content-types/restaurant/schema.json index add651456e..5658d6b517 100755 --- a/examples/getstarted/src/api/restaurant/content-types/restaurant/schema.json +++ b/examples/getstarted/src/api/restaurant/content-types/restaurant/schema.json @@ -34,7 +34,7 @@ "targetField": "name", "pluginOptions": {} }, - "price_range": { + "priceRange": { "enum": [ "very_cheap", "cheap", @@ -49,7 +49,7 @@ } } }, - "closing_period": { + "closingPeriod": { "component": "default.closingperiod", "type": "component", "pluginOptions": { @@ -58,7 +58,7 @@ } } }, - "contact_email": { + "contactEmail": { "type": "email", "pluginOptions": { "i18n": { @@ -115,7 +115,7 @@ } } }, - "short_description": { + "shortDescription": { "type": "text", "pluginOptions": { "i18n": { @@ -163,7 +163,7 @@ "target": "api::menu.menu", "inversedBy": "restaurant" }, - "opening_times": { + "openingTimes": { "component": "default.openingtimes", "type": "component", "repeatable": true, diff --git a/packages/core/admin/server/tests/admin-role.test.e2e.js b/packages/core/admin/server/tests/admin-role.test.e2e.js index 49a71fda1d..d156c24a80 100644 --- a/packages/core/admin/server/tests/admin-role.test.e2e.js +++ b/packages/core/admin/server/tests/admin-role.test.e2e.js @@ -17,7 +17,7 @@ const data = { editorRole: undefined, }; -const omitTimestamps = obj => _.omit(obj, ['updatedAt', 'createdAt', 'updated_at', 'created_at']); +const omitTimestamps = obj => _.omit(obj, ['updatedAt', 'createdAt']); describe('Role CRUD End to End', () => { let rq; diff --git a/packages/core/admin/server/tests/admin-user.test.e2e.js b/packages/core/admin/server/tests/admin-user.test.e2e.js index 59b0724733..fb8ceba5a7 100644 --- a/packages/core/admin/server/tests/admin-user.test.e2e.js +++ b/packages/core/admin/server/tests/admin-user.test.e2e.js @@ -7,7 +7,7 @@ const { createUtils } = require('../../../../../test/helpers/utils'); const edition = process.env.STRAPI_DISABLE_EE === 'true' ? 'CE' : 'EE'; -const omitTimestamps = obj => _.omit(obj, ['updatedAt', 'createdAt', 'updated_at', 'created_at']); +const omitTimestamps = obj => _.omit(obj, ['updatedAt', 'createdAt']); /** * == Test Suite Overview == diff --git a/packages/core/content-manager/tests/index.test.e2e.js b/packages/core/content-manager/tests/index.test.e2e.js index f986055c64..a784d9d778 100644 --- a/packages/core/content-manager/tests/index.test.e2e.js +++ b/packages/core/content-manager/tests/index.test.e2e.js @@ -9,8 +9,6 @@ const { createAuthRequest } = require('../../../../test/helpers/request'); const cleanDate = entry => { delete entry.updatedAt; delete entry.createdAt; - delete entry.created_at; - delete entry.updated_at; }; const builder = createTestBuilder(); diff --git a/packages/core/database/lib/entity-manager.js b/packages/core/database/lib/entity-manager.js index 3596adf053..5bc7a98176 100644 --- a/packages/core/database/lib/entity-manager.js +++ b/packages/core/database/lib/entity-manager.js @@ -29,7 +29,7 @@ const toAssocs = data => { }); }; -const toRow = (metadata, data = {}, { withDefaults = false } = {}) => { +const processData = (metadata, data = {}, { withDefaults = false } = {}) => { const { attributes } = metadata; const obj = {}; @@ -37,11 +37,9 @@ const toRow = (metadata, data = {}, { withDefaults = false } = {}) => { for (const attributeName in attributes) { const attribute = attributes[attributeName]; - // TODO: convert to column name if (types.isScalar(attribute.type)) { const field = createField(attribute); - // TODO: move application level default to entity service if (_.isUndefined(data[attributeName])) { if (!_.isUndefined(attribute.default) && withDefaults) { if (typeof attribute.default === 'function') { @@ -65,7 +63,6 @@ const toRow = (metadata, data = {}, { withDefaults = false } = {}) => { if (types.isRelation(attribute.type)) { // oneToOne & manyToOne if (attribute.joinColumn && attribute.owner) { - // TODO: ensure joinColumn name respect convention ? const joinColumnName = attribute.joinColumn.name; // allow setting to null @@ -167,7 +164,7 @@ const createEntityManager = db => { throw new Error('Create expects a data object'); } - const dataToInsert = toRow(metadata, data, { withDefaults: true }); + const dataToInsert = processData(metadata, data, { withDefaults: true }); const [id] = await this.createQueryBuilder(uid) .insert(dataToInsert) @@ -199,7 +196,7 @@ const createEntityManager = db => { throw new Error('CreateMany expects data to be an array'); } - const dataToInsert = data.map(datum => toRow(metadata, datum, { withDefaults: true })); + const dataToInsert = data.map(datum => processData(metadata, datum, { withDefaults: true })); if (_.isEmpty(dataToInsert)) { throw new Error('Nothing to insert'); @@ -242,7 +239,7 @@ const createEntityManager = db => { const { id } = entity; - const dataToUpdate = toRow(metadata, data); + const dataToUpdate = processData(metadata, data); if (!_.isEmpty(dataToUpdate)) { await this.createQueryBuilder(uid) @@ -272,7 +269,7 @@ const createEntityManager = db => { const metadata = db.metadata.get(uid); const { where, data } = params; - const dataToUpdate = toRow(metadata, data); + const dataToUpdate = processData(metadata, data); if (_.isEmpty(dataToUpdate)) { throw new Error('Update requires data'); diff --git a/packages/core/database/lib/lifecycles/subscribers/timestamps.js b/packages/core/database/lib/lifecycles/subscribers/timestamps.js index b314aee5ba..637f943dbe 100644 --- a/packages/core/database/lib/lifecycles/subscribers/timestamps.js +++ b/packages/core/database/lib/lifecycles/subscribers/timestamps.js @@ -14,18 +14,18 @@ const _ = require('lodash'); */ const timestampsLifecyclesSubscriber = { /** - * Init created_at & updated_at before create + * Init createdAt & updatedAt before create * @param {Event} event */ beforeCreate(event) { const { data } = event.params; const now = new Date(); - _.defaults(data, { created_at: now, updated_at: now }); + _.defaults(data, { createdAt: now, updatedAt: now }); }, /** - * Init created_at & updated_at before create + * Init createdAt & updatedAt before create * @param {Event} event */ beforeCreateMany(event) { @@ -33,23 +33,23 @@ const timestampsLifecyclesSubscriber = { const now = new Date(); if (_.isArray(data)) { - data.forEach(data => _.defaults(data, { created_at: now, updated_at: now })); + data.forEach(data => _.defaults(data, { createdAt: now, updatedAt: now })); } }, /** - * Update updated_at before update + * Update updatedAt before update * @param {Event} event */ beforeUpdate(event) { const { data } = event.params; const now = new Date(); - _.assign(data, { updated_at: now }); + _.assign(data, { updatedAt: now }); }, /** - * Update updated_at before update + * Update updatedAt before update * @param {Event} event */ beforeUpdateMany(event) { @@ -57,7 +57,7 @@ const timestampsLifecyclesSubscriber = { const now = new Date(); if (_.isArray(data)) { - data.forEach(data => _.assign(data, { updated_at: now })); + data.forEach(data => _.assign(data, { updatedAt: now })); } }, }; diff --git a/packages/core/database/lib/metadata/index.js b/packages/core/database/lib/metadata/index.js index b3ff626ff8..ccc3ac50a3 100644 --- a/packages/core/database/lib/metadata/index.js +++ b/packages/core/database/lib/metadata/index.js @@ -1,8 +1,3 @@ -/** - * @module metadata - * - */ - 'use strict'; const _ = require('lodash/fp'); @@ -16,43 +11,13 @@ class Metadata extends Map { } } +// TODO: check if there isn't an attribute with an id already /** * Create Metadata from models configurations - * - * timestamps => not optional anymore but auto added. Auto added on the content type or in the db layer ? - * - * options => options are handled on the layer above. Options convert to fields on the CT - * - * filters => not in v1 - * - * attributes - * - * - type - * - mapping field name - column name - * - mapping field type - column type - * - formatter / parser => coming from field type so no - * - indexes / checks / contstraints - * - relations => reference to the target model (function or string to avoid circular deps ?) - * - name of the LEFT/RIGHT side foreign keys - * - name of join table - * - * - compo/dz => reference to the components - * - validators - * - hooks - * - default value - * - required -> should add a not null option instead of the API required - * - unique -> should add a DB unique option instead of the unique in the API (Unique by locale or something else for example) - * - * lifecycles - * - * private fields ? => handled on a different layer * @param {object[]} models * @returns {Metadata} */ const createMetadata = (models = []) => { - // TODO: reorder to make sure we can create everything or delete everything in the right order - // TODO: allow passing the join config in the attribute - // TODO: allow passing column config in the attribute const metadata = new Metadata(); // init pass @@ -62,7 +27,6 @@ const createMetadata = (models = []) => { uid: model.uid, tableName: model.tableName, attributes: { - // TODO: check if there isn't an attribute with an id already id: { type: 'increments', }, @@ -83,67 +47,12 @@ const createMetadata = (models = []) => { for (const [attributeName, attribute] of Object.entries(meta.attributes)) { try { if (types.isComponent(attribute.type)) { - // convert component to relation - - Object.assign(attribute, { - type: 'relation', - relation: attribute.repeatable === true ? 'oneToMany' : 'oneToOne', - target: attribute.component, - joinTable: { - name: meta.componentLink.tableName, - joinColumn: { - name: 'entity_id', - referencedColumn: 'id', - }, - inverseJoinColumn: { - name: 'component_id', - referencedColumn: 'id', - }, - on: { - field: attributeName, - }, - orderBy: { - order: 'asc', - }, - }, - }); - + createComponent(attributeName, attribute, meta, metadata); continue; } if (types.isDynamicZone(attribute.type)) { - // - - Object.assign(attribute, { - type: 'relation', - relation: 'morphToMany', - // TODO: handle restrictions at some point - // target: attribute.components, - joinTable: { - name: meta.componentLink.tableName, - joinColumn: { - name: 'entity_id', - referencedColumn: 'id', - }, - morphColumn: { - idColumn: { - name: 'component_id', - referencedColumn: 'id', - }, - typeColumn: { - name: 'component_type', - }, - typeField: '__component', - }, - on: { - field: attributeName, - }, - orderBy: { - order: 'asc', - }, - }, - }); - + createDynamicZone(attributeName, attribute, meta, metadata); continue; } @@ -151,7 +60,10 @@ const createMetadata = (models = []) => { createRelation(attributeName, attribute, meta, metadata); continue; } + + createAttribute(attributeName, attribute, meta, metadata); } catch (error) { + console.log(error); throw new Error( `Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}` ); @@ -159,6 +71,15 @@ const createMetadata = (models = []) => { } } + for (const meta of metadata.values()) { + const columnToAttribute = Object.keys(meta.attributes).reduce((acc, key) => { + const attribute = meta.attributes[key]; + return Object.assign(acc, { [attribute.columnName || key]: key }); + }, {}); + + meta.columnToAttribute = columnToAttribute; + } + return metadata; }; @@ -233,4 +154,66 @@ const createCompoLinkModelMeta = baseModelMeta => { }; }; +const createDynamicZone = (attributeName, attribute, meta) => { + Object.assign(attribute, { + type: 'relation', + relation: 'morphToMany', + // TODO: handle restrictions at some point + // target: attribute.components, + joinTable: { + name: meta.componentLink.tableName, + joinColumn: { + name: 'entity_id', + referencedColumn: 'id', + }, + morphColumn: { + idColumn: { + name: 'component_id', + referencedColumn: 'id', + }, + typeColumn: { + name: 'component_type', + }, + typeField: '__component', + }, + on: { + field: attributeName, + }, + orderBy: { + order: 'asc', + }, + }, + }); +}; + +const createComponent = (attributeName, attribute, meta) => { + Object.assign(attribute, { + type: 'relation', + relation: attribute.repeatable === true ? 'oneToMany' : 'oneToOne', + target: attribute.component, + joinTable: { + name: meta.componentLink.tableName, + joinColumn: { + name: 'entity_id', + referencedColumn: 'id', + }, + inverseJoinColumn: { + name: 'component_id', + referencedColumn: 'id', + }, + on: { + field: attributeName, + }, + orderBy: { + order: 'asc', + }, + }, + }); +}; + +const createAttribute = (attributeName, attribute) => { + const columnName = _.snakeCase(attributeName); + Object.assign(attribute, { columnName }); +}; + module.exports = createMetadata; diff --git a/packages/core/database/lib/query/helpers/order-by.js b/packages/core/database/lib/query/helpers/order-by.js index 1c2a6978a4..31c92a2cb5 100644 --- a/packages/core/database/lib/query/helpers/order-by.js +++ b/packages/core/database/lib/query/helpers/order-by.js @@ -4,10 +4,12 @@ const _ = require('lodash/fp'); const types = require('../../types'); const { createJoin } = require('./join'); +const { toColumnName } = require('./transform'); const processOrderBy = (orderBy, ctx) => { const { db, uid, qb, alias } = ctx; - const { attributes } = db.metadata.get(uid); + const meta = db.metadata.get(uid); + const { attributes } = meta; if (typeof orderBy === 'string') { const attribute = attributes[orderBy]; @@ -16,7 +18,9 @@ const processOrderBy = (orderBy, ctx) => { throw new Error(`Attribute ${orderBy} not found on model ${uid}`); } - return [{ column: qb.aliasColumn(orderBy, alias) }]; + const columnName = toColumnName(meta, orderBy); + + return [{ column: qb.aliasColumn(columnName, alias) }]; } if (Array.isArray(orderBy)) { @@ -33,7 +37,9 @@ const processOrderBy = (orderBy, ctx) => { } if (types.isScalar(attribute.type)) { - return { column: qb.aliasColumn(key, alias), order: direction }; + const columnName = toColumnName(meta, key); + + return { column: qb.aliasColumn(columnName, alias), order: direction }; } if (attribute.type === 'relation') { diff --git a/packages/core/database/lib/query/helpers/search.js b/packages/core/database/lib/query/helpers/search.js index 19ebb64cbf..ff5c686efd 100644 --- a/packages/core/database/lib/query/helpers/search.js +++ b/packages/core/database/lib/query/helpers/search.js @@ -3,11 +3,13 @@ const _ = require('lodash/fp'); const types = require('../../types'); +const { toColumnName } = require('./transform'); -const applySearch = (qb, query, ctx) => { - const { alias, uid, db } = ctx; +const applySearch = (knex, query, ctx) => { + const { qb, uid, db } = ctx; + const meta = db.metadata.get(uid); - const { attributes } = db.metadata.get(uid); + const { attributes } = meta; const searchColumns = ['id']; @@ -29,22 +31,34 @@ const applySearch = (qb, query, ctx) => { switch (db.dialect.client) { case 'postgres': { - searchColumns.forEach(attr => - qb.orWhereRaw(`"${alias}"."${attr}"::text ILIKE ?`, `%${escapeQuery(query, '*%\\')}%`) - ); + searchColumns.forEach(attr => { + const columnName = toColumnName(meta, attr); + return knex.orWhereRaw(`??::text ILIKE ?`, [ + qb.aliasColumn(columnName), + `%${escapeQuery(query, '*%\\')}%`, + ]); + }); break; } case 'sqlite': { - searchColumns.forEach(attr => - qb.orWhereRaw(`"${alias}"."${attr}" LIKE ? ESCAPE '\\'`, `%${escapeQuery(query, '*%\\')}%`) - ); + searchColumns.forEach(attr => { + const columnName = toColumnName(meta, attr); + return knex.orWhereRaw(`?? LIKE ? ESCAPE '\\'`, [ + qb.aliasColumn(columnName), + `%${escapeQuery(query, '*%\\')}%`, + ]); + }); break; } case 'mysql': { - searchColumns.forEach(attr => - qb.orWhereRaw(`\`${alias}\`.\`${attr}\` LIKE ?`, `%${escapeQuery(query, '*%\\')}%`) - ); + searchColumns.forEach(attr => { + const columnName = toColumnName(meta, attr); + return knex.orWhereRaw(`?? LIKE ?`, [ + qb.aliasColumn(columnName), + `%${escapeQuery(query, '*%\\')}%`, + ]); + }); break; } default: { diff --git a/packages/core/database/lib/query/helpers/transform.js b/packages/core/database/lib/query/helpers/transform.js index 8711ebe485..277d7d34da 100644 --- a/packages/core/database/lib/query/helpers/transform.js +++ b/packages/core/database/lib/query/helpers/transform.js @@ -5,12 +5,12 @@ const _ = require('lodash/fp'); const types = require('../../types'); const { createField } = require('../../fields'); -const fromRow = (metadata, row) => { +const fromRow = (meta, row) => { if (Array.isArray(row)) { - return row.map(singleRow => fromRow(metadata, singleRow)); + return row.map(singleRow => fromRow(meta, singleRow)); } - const { attributes } = metadata; + const { attributes } = meta; if (_.isNil(row)) { return null; @@ -19,25 +19,16 @@ const fromRow = (metadata, row) => { const obj = {}; for (const column in row) { - // to field Name - const attributeName = column; - - if (!attributes[attributeName]) { - // ignore value that are not related to an attribute (join columns ...) + if (!_.has(column, meta.columnToAttribute)) { continue; } + const attributeName = meta.columnToAttribute[column]; const attribute = attributes[attributeName]; if (types.isScalar(attribute.type)) { - // TODO: we convert to column name - // TODO: handle default value too - // TODO: format data & use dialect to know which type they support (json particularly) - const field = createField(attribute); - // TODO: validate data on creation - // field.validate(data[attributeName]); const val = row[column] === null ? null : field.fromDB(row[column]); obj[attributeName] = val; @@ -51,6 +42,43 @@ const fromRow = (metadata, row) => { return obj; }; -module.exports = { - fromRow, +const toRow = (meta, data = {}) => { + if (_.isNil(data)) { + return data; + } + + if (_.isArray(data)) { + return data.map(datum => toRow(meta, datum)); + } + + const { attributes } = meta; + + for (const key in data) { + const attribute = attributes[key]; + + if (!attribute || attribute.columnName === key) { + continue; + } + + data[attribute.columnName] = data[key]; + delete data[key]; + } + + return data; +}; + +const toColumnName = (meta, name) => { + const attribute = meta.attributes[name]; + + if (!attribute) { + return name; + } + + return attribute.columnName || name; +}; + +module.exports = { + toRow, + fromRow, + toColumnName, }; diff --git a/packages/core/database/lib/query/helpers/where.js b/packages/core/database/lib/query/helpers/where.js index 41c48461fb..e129da8f4d 100644 --- a/packages/core/database/lib/query/helpers/where.js +++ b/packages/core/database/lib/query/helpers/where.js @@ -4,6 +4,7 @@ const _ = require('lodash/fp'); const types = require('../../types'); const { createJoin } = require('./join'); +const { toColumnName } = require('./transform'); const GROUP_OPERATORS = ['$and', '$or']; const OPERATORS = [ @@ -56,13 +57,14 @@ const processWhere = (where, ctx, depth = 0) => { }; const { db, uid, qb, alias } = ctx; + const meta = db.metadata.get(uid); const filters = {}; // for each key in where for (const key in where) { const value = where[key]; - const attribute = db.metadata.get(uid).attributes[key]; + const attribute = meta.attributes[key]; // if operator $and $or then loop over them if (GROUP_OPERATORS.includes(key)) { @@ -87,14 +89,8 @@ const processWhere = (where, ctx, depth = 0) => { } if (!attribute) { - // TODO: if targeting a column name instead of an attribute + filters[qb.aliasColumn(key, alias)] = processNested(value, ctx); - // if key as an alias don't add one - if (key.indexOf('.') >= 0) { - filters[key] = processNested(value, ctx); - } else { - filters[qb.aliasColumn(key, alias)] = processNested(value, ctx); - } continue; // throw new Error(`Attribute ${key} not found on model ${uid}`); @@ -130,9 +126,10 @@ const processWhere = (where, ctx, depth = 0) => { } if (types.isScalar(attribute.type)) { - // TODO: convert attribute name to column name + const columnName = toColumnName(meta, key); + // TODO: cast to DB type - filters[qb.aliasColumn(key, alias)] = processNested(value, ctx); + filters[qb.aliasColumn(columnName, alias)] = processNested(value, ctx); continue; } diff --git a/packages/core/database/lib/query/query-builder.js b/packages/core/database/lib/query/query-builder.js index a205e7589d..0d674a0bb5 100644 --- a/packages/core/database/lib/query/query-builder.js +++ b/packages/core/database/lib/query/query-builder.js @@ -57,7 +57,7 @@ const createQueryBuilder = (uid, db) => { }, ref(name) { - return db.connection.ref(name); + return db.connection.ref(helpers.toColumnName(meta, name)); }, update(data) { @@ -168,20 +168,20 @@ const createQueryBuilder = (uid, db) => { return ['select', 'count'].includes(state.type); }, - aliasColumn(columnName, alias) { - if (typeof columnName !== 'string') { - return columnName; + aliasColumn(key, alias) { + if (typeof key !== 'string') { + return key; } - if (columnName.indexOf('.') >= 0) { - return columnName; + if (key.indexOf('.') >= 0) { + return key; } if (!_.isNil(alias)) { - return `${alias}.${columnName}`; + return `${alias}.${key}`; } - return this.mustUseAlias() ? `${this.alias}.${columnName}` : columnName; + return this.mustUseAlias() ? `${this.alias}.${key}` : key; }, raw(...args) { @@ -205,9 +205,11 @@ const createQueryBuilder = (uid, db) => { }, processState() { + state.select = state.select.map(field => helpers.toColumnName(meta, field)); state.orderBy = helpers.processOrderBy(state.orderBy, { qb: this, uid, db }); state.where = helpers.processWhere(state.where, { qb: this, uid, db }); state.populate = helpers.processPopulate(state.populate, { qb: this, uid, db }); + state.data = helpers.toRow(meta, state.data); }, getKnexQuery() { @@ -299,7 +301,7 @@ const createQueryBuilder = (uid, db) => { // if there are joins and it is a delete or update use a sub query if (state.search) { qb.where(subQb => { - helpers.applySearch(subQb, state.search, { alias: this.alias, db, uid }); + helpers.applySearch(subQb, state.search, { qb: this, db, uid }); }); } diff --git a/packages/core/database/lib/schema/schema.js b/packages/core/database/lib/schema/schema.js index b0387075fe..b312fef9d5 100644 --- a/packages/core/database/lib/schema/schema.js +++ b/packages/core/database/lib/schema/schema.js @@ -14,17 +14,11 @@ const createColumn = (name, attribute) => { unsigned: false, ...opts, ...(attribute.column || {}), - // TODO: allow passing custom params to the DB from the model definition }; }; -const shouldCreateColumn = attribute => { - return types.isScalar(attribute.type); -}; - const createTable = meta => { const table = { - // TODO: allow passing custom params to the DB from the model definition name: meta.tableName, indexes: meta.indexes || [], foreignKeys: meta.foreignKeys || [], @@ -76,8 +70,8 @@ const createTable = meta => { columns: [columnName], }); } - } else if (shouldCreateColumn(attribute)) { - const column = createColumn(key, meta.attributes[key]); + } else if (types.isScalar(attribute.type)) { + const column = createColumn(attribute.columnName || key, attribute); if (column.unique) { table.indexes.push({ diff --git a/packages/core/strapi/lib/migrations/draft-publish.js b/packages/core/strapi/lib/migrations/draft-publish.js index 3defeae94d..ad2792681b 100644 --- a/packages/core/strapi/lib/migrations/draft-publish.js +++ b/packages/core/strapi/lib/migrations/draft-publish.js @@ -20,7 +20,7 @@ const enableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => { if (!hasDraftAndPublish(oldContentType) && hasDraftAndPublish(contentType)) { const qb = strapi.db.queryBuilder(uid); await qb - .update({ published_at: qb.ref('created_at') }) + .update({ published_at: qb.ref('createdAt') }) .where({ published_at: null }) .execute(); } diff --git a/packages/core/utils/lib/__tests__/content-types.test.js b/packages/core/utils/lib/__tests__/content-types.test.js index 24d53865c4..61f5f38926 100644 --- a/packages/core/utils/lib/__tests__/content-types.test.js +++ b/packages/core/utils/lib/__tests__/content-types.test.js @@ -64,8 +64,8 @@ describe('Content types utils', () => { expect(getNonWritableAttributes(model)).toEqual([ 'id', - 'created_at', - 'updated_at', + 'createdAt', + 'updatedAt', 'non_writable_field', ]); }); diff --git a/packages/core/utils/lib/content-types.js b/packages/core/utils/lib/content-types.js index ee10b77428..4d066f8f7c 100644 --- a/packages/core/utils/lib/content-types.js +++ b/packages/core/utils/lib/content-types.js @@ -10,8 +10,8 @@ const PUBLISHED_AT_ATTRIBUTE = 'published_at'; const CREATED_BY_ATTRIBUTE = 'created_by'; const UPDATED_BY_ATTRIBUTE = 'updated_by'; -const CREATED_AT_ATTRIBUTE = 'created_at'; -const UPDATED_AT_ATTRIBUTE = 'updated_at'; +const CREATED_AT_ATTRIBUTE = 'createdAt'; +const UPDATED_AT_ATTRIBUTE = 'updatedAt'; const DP_PUB_STATE_LIVE = 'live'; const DP_PUB_STATE_PREVIEW = 'preview'; diff --git a/packages/plugins/i18n/tests/locales.test.e2e.js b/packages/plugins/i18n/tests/locales.test.e2e.js index 50f95b5bdf..5b6a5ed2d5 100644 --- a/packages/plugins/i18n/tests/locales.test.e2e.js +++ b/packages/plugins/i18n/tests/locales.test.e2e.js @@ -11,7 +11,7 @@ const data = { deletedLocales: [], }; -const omitTimestamps = omit(['updatedAt', 'createdAt', 'updated_at', 'created_at']); +const omitTimestamps = omit(['updatedAt', 'createdAt']); const compareLocales = (a, b) => (a.code < b.code ? -1 : 1); const productModel = {