use columnName snake casing and rename timestamp attributes

This commit is contained in:
Alexandre Bodin 2021-09-22 10:49:43 +02:00
parent 872e7317ca
commit 58e024d3ad
18 changed files with 205 additions and 184 deletions

View File

@ -5,12 +5,14 @@
"displayName": "Category", "displayName": "Category",
"singularName": "category", "singularName": "category",
"pluralName": "categories", "pluralName": "categories",
"description": "" "description": "",
"name": "Category"
}, },
"options": { "options": {
"draftAndPublish": true, "draftAndPublish": true,
"comment": "" "comment": ""
}, },
"pluginOptions": {},
"attributes": { "attributes": {
"name": { "name": {
"type": "string" "type": "string"

View File

@ -34,7 +34,7 @@
"targetField": "name", "targetField": "name",
"pluginOptions": {} "pluginOptions": {}
}, },
"price_range": { "priceRange": {
"enum": [ "enum": [
"very_cheap", "very_cheap",
"cheap", "cheap",
@ -49,7 +49,7 @@
} }
} }
}, },
"closing_period": { "closingPeriod": {
"component": "default.closingperiod", "component": "default.closingperiod",
"type": "component", "type": "component",
"pluginOptions": { "pluginOptions": {
@ -58,7 +58,7 @@
} }
} }
}, },
"contact_email": { "contactEmail": {
"type": "email", "type": "email",
"pluginOptions": { "pluginOptions": {
"i18n": { "i18n": {
@ -115,7 +115,7 @@
} }
} }
}, },
"short_description": { "shortDescription": {
"type": "text", "type": "text",
"pluginOptions": { "pluginOptions": {
"i18n": { "i18n": {
@ -163,7 +163,7 @@
"target": "api::menu.menu", "target": "api::menu.menu",
"inversedBy": "restaurant" "inversedBy": "restaurant"
}, },
"opening_times": { "openingTimes": {
"component": "default.openingtimes", "component": "default.openingtimes",
"type": "component", "type": "component",
"repeatable": true, "repeatable": true,

View File

@ -17,7 +17,7 @@ const data = {
editorRole: undefined, 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', () => { describe('Role CRUD End to End', () => {
let rq; let rq;

View File

@ -7,7 +7,7 @@ const { createUtils } = require('../../../../../test/helpers/utils');
const edition = process.env.STRAPI_DISABLE_EE === 'true' ? 'CE' : 'EE'; 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 == * == Test Suite Overview ==

View File

@ -9,8 +9,6 @@ const { createAuthRequest } = require('../../../../test/helpers/request');
const cleanDate = entry => { const cleanDate = entry => {
delete entry.updatedAt; delete entry.updatedAt;
delete entry.createdAt; delete entry.createdAt;
delete entry.created_at;
delete entry.updated_at;
}; };
const builder = createTestBuilder(); const builder = createTestBuilder();

View File

@ -29,7 +29,7 @@ const toAssocs = data => {
}); });
}; };
const toRow = (metadata, data = {}, { withDefaults = false } = {}) => { const processData = (metadata, data = {}, { withDefaults = false } = {}) => {
const { attributes } = metadata; const { attributes } = metadata;
const obj = {}; const obj = {};
@ -37,11 +37,9 @@ const toRow = (metadata, data = {}, { withDefaults = false } = {}) => {
for (const attributeName in attributes) { for (const attributeName in attributes) {
const attribute = attributes[attributeName]; const attribute = attributes[attributeName];
// TODO: convert to column name
if (types.isScalar(attribute.type)) { if (types.isScalar(attribute.type)) {
const field = createField(attribute); const field = createField(attribute);
// TODO: move application level default to entity service
if (_.isUndefined(data[attributeName])) { if (_.isUndefined(data[attributeName])) {
if (!_.isUndefined(attribute.default) && withDefaults) { if (!_.isUndefined(attribute.default) && withDefaults) {
if (typeof attribute.default === 'function') { if (typeof attribute.default === 'function') {
@ -65,7 +63,6 @@ const toRow = (metadata, data = {}, { withDefaults = false } = {}) => {
if (types.isRelation(attribute.type)) { if (types.isRelation(attribute.type)) {
// oneToOne & manyToOne // oneToOne & manyToOne
if (attribute.joinColumn && attribute.owner) { if (attribute.joinColumn && attribute.owner) {
// TODO: ensure joinColumn name respect convention ?
const joinColumnName = attribute.joinColumn.name; const joinColumnName = attribute.joinColumn.name;
// allow setting to null // allow setting to null
@ -167,7 +164,7 @@ const createEntityManager = db => {
throw new Error('Create expects a data object'); 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) const [id] = await this.createQueryBuilder(uid)
.insert(dataToInsert) .insert(dataToInsert)
@ -199,7 +196,7 @@ const createEntityManager = db => {
throw new Error('CreateMany expects data to be an array'); 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)) { if (_.isEmpty(dataToInsert)) {
throw new Error('Nothing to insert'); throw new Error('Nothing to insert');
@ -242,7 +239,7 @@ const createEntityManager = db => {
const { id } = entity; const { id } = entity;
const dataToUpdate = toRow(metadata, data); const dataToUpdate = processData(metadata, data);
if (!_.isEmpty(dataToUpdate)) { if (!_.isEmpty(dataToUpdate)) {
await this.createQueryBuilder(uid) await this.createQueryBuilder(uid)
@ -272,7 +269,7 @@ const createEntityManager = db => {
const metadata = db.metadata.get(uid); const metadata = db.metadata.get(uid);
const { where, data } = params; const { where, data } = params;
const dataToUpdate = toRow(metadata, data); const dataToUpdate = processData(metadata, data);
if (_.isEmpty(dataToUpdate)) { if (_.isEmpty(dataToUpdate)) {
throw new Error('Update requires data'); throw new Error('Update requires data');

View File

@ -14,18 +14,18 @@ const _ = require('lodash');
*/ */
const timestampsLifecyclesSubscriber = { const timestampsLifecyclesSubscriber = {
/** /**
* Init created_at & updated_at before create * Init createdAt & updatedAt before create
* @param {Event} event * @param {Event} event
*/ */
beforeCreate(event) { beforeCreate(event) {
const { data } = event.params; const { data } = event.params;
const now = new Date(); 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 * @param {Event} event
*/ */
beforeCreateMany(event) { beforeCreateMany(event) {
@ -33,23 +33,23 @@ const timestampsLifecyclesSubscriber = {
const now = new Date(); const now = new Date();
if (_.isArray(data)) { 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 * @param {Event} event
*/ */
beforeUpdate(event) { beforeUpdate(event) {
const { data } = event.params; const { data } = event.params;
const now = new Date(); 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 * @param {Event} event
*/ */
beforeUpdateMany(event) { beforeUpdateMany(event) {
@ -57,7 +57,7 @@ const timestampsLifecyclesSubscriber = {
const now = new Date(); const now = new Date();
if (_.isArray(data)) { if (_.isArray(data)) {
data.forEach(data => _.assign(data, { updated_at: now })); data.forEach(data => _.assign(data, { updatedAt: now }));
} }
}, },
}; };

View File

@ -1,8 +1,3 @@
/**
* @module metadata
*
*/
'use strict'; 'use strict';
const _ = require('lodash/fp'); 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 * 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 * @param {object[]} models
* @returns {Metadata} * @returns {Metadata}
*/ */
const createMetadata = (models = []) => { 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(); const metadata = new Metadata();
// init pass // init pass
@ -62,7 +27,6 @@ const createMetadata = (models = []) => {
uid: model.uid, uid: model.uid,
tableName: model.tableName, tableName: model.tableName,
attributes: { attributes: {
// TODO: check if there isn't an attribute with an id already
id: { id: {
type: 'increments', type: 'increments',
}, },
@ -83,67 +47,12 @@ const createMetadata = (models = []) => {
for (const [attributeName, attribute] of Object.entries(meta.attributes)) { for (const [attributeName, attribute] of Object.entries(meta.attributes)) {
try { try {
if (types.isComponent(attribute.type)) { if (types.isComponent(attribute.type)) {
// convert component to relation createComponent(attributeName, attribute, meta, metadata);
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',
},
},
});
continue; continue;
} }
if (types.isDynamicZone(attribute.type)) { if (types.isDynamicZone(attribute.type)) {
// createDynamicZone(attributeName, attribute, meta, metadata);
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',
},
},
});
continue; continue;
} }
@ -151,7 +60,10 @@ const createMetadata = (models = []) => {
createRelation(attributeName, attribute, meta, metadata); createRelation(attributeName, attribute, meta, metadata);
continue; continue;
} }
createAttribute(attributeName, attribute, meta, metadata);
} catch (error) { } catch (error) {
console.log(error);
throw new Error( throw new Error(
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}` `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; 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; module.exports = createMetadata;

View File

@ -4,10 +4,12 @@ const _ = require('lodash/fp');
const types = require('../../types'); const types = require('../../types');
const { createJoin } = require('./join'); const { createJoin } = require('./join');
const { toColumnName } = require('./transform');
const processOrderBy = (orderBy, ctx) => { const processOrderBy = (orderBy, ctx) => {
const { db, uid, qb, alias } = 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') { if (typeof orderBy === 'string') {
const attribute = attributes[orderBy]; const attribute = attributes[orderBy];
@ -16,7 +18,9 @@ const processOrderBy = (orderBy, ctx) => {
throw new Error(`Attribute ${orderBy} not found on model ${uid}`); 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)) { if (Array.isArray(orderBy)) {
@ -33,7 +37,9 @@ const processOrderBy = (orderBy, ctx) => {
} }
if (types.isScalar(attribute.type)) { 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') { if (attribute.type === 'relation') {

View File

@ -3,11 +3,13 @@
const _ = require('lodash/fp'); const _ = require('lodash/fp');
const types = require('../../types'); const types = require('../../types');
const { toColumnName } = require('./transform');
const applySearch = (qb, query, ctx) => { const applySearch = (knex, query, ctx) => {
const { alias, uid, db } = ctx; const { qb, uid, db } = ctx;
const meta = db.metadata.get(uid);
const { attributes } = db.metadata.get(uid); const { attributes } = meta;
const searchColumns = ['id']; const searchColumns = ['id'];
@ -29,22 +31,34 @@ const applySearch = (qb, query, ctx) => {
switch (db.dialect.client) { switch (db.dialect.client) {
case 'postgres': { case 'postgres': {
searchColumns.forEach(attr => searchColumns.forEach(attr => {
qb.orWhereRaw(`"${alias}"."${attr}"::text ILIKE ?`, `%${escapeQuery(query, '*%\\')}%`) const columnName = toColumnName(meta, attr);
); return knex.orWhereRaw(`??::text ILIKE ?`, [
qb.aliasColumn(columnName),
`%${escapeQuery(query, '*%\\')}%`,
]);
});
break; break;
} }
case 'sqlite': { case 'sqlite': {
searchColumns.forEach(attr => searchColumns.forEach(attr => {
qb.orWhereRaw(`"${alias}"."${attr}" LIKE ? ESCAPE '\\'`, `%${escapeQuery(query, '*%\\')}%`) const columnName = toColumnName(meta, attr);
); return knex.orWhereRaw(`?? LIKE ? ESCAPE '\\'`, [
qb.aliasColumn(columnName),
`%${escapeQuery(query, '*%\\')}%`,
]);
});
break; break;
} }
case 'mysql': { case 'mysql': {
searchColumns.forEach(attr => searchColumns.forEach(attr => {
qb.orWhereRaw(`\`${alias}\`.\`${attr}\` LIKE ?`, `%${escapeQuery(query, '*%\\')}%`) const columnName = toColumnName(meta, attr);
); return knex.orWhereRaw(`?? LIKE ?`, [
qb.aliasColumn(columnName),
`%${escapeQuery(query, '*%\\')}%`,
]);
});
break; break;
} }
default: { default: {

View File

@ -5,12 +5,12 @@ const _ = require('lodash/fp');
const types = require('../../types'); const types = require('../../types');
const { createField } = require('../../fields'); const { createField } = require('../../fields');
const fromRow = (metadata, row) => { const fromRow = (meta, row) => {
if (Array.isArray(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)) { if (_.isNil(row)) {
return null; return null;
@ -19,25 +19,16 @@ const fromRow = (metadata, row) => {
const obj = {}; const obj = {};
for (const column in row) { for (const column in row) {
// to field Name if (!_.has(column, meta.columnToAttribute)) {
const attributeName = column;
if (!attributes[attributeName]) {
// ignore value that are not related to an attribute (join columns ...)
continue; continue;
} }
const attributeName = meta.columnToAttribute[column];
const attribute = attributes[attributeName]; const attribute = attributes[attributeName];
if (types.isScalar(attribute.type)) { 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); const field = createField(attribute);
// TODO: validate data on creation
// field.validate(data[attributeName]);
const val = row[column] === null ? null : field.fromDB(row[column]); const val = row[column] === null ? null : field.fromDB(row[column]);
obj[attributeName] = val; obj[attributeName] = val;
@ -51,6 +42,43 @@ const fromRow = (metadata, row) => {
return obj; return obj;
}; };
module.exports = { const toRow = (meta, data = {}) => {
fromRow, 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,
}; };

View File

@ -4,6 +4,7 @@ const _ = require('lodash/fp');
const types = require('../../types'); const types = require('../../types');
const { createJoin } = require('./join'); const { createJoin } = require('./join');
const { toColumnName } = require('./transform');
const GROUP_OPERATORS = ['$and', '$or']; const GROUP_OPERATORS = ['$and', '$or'];
const OPERATORS = [ const OPERATORS = [
@ -56,13 +57,14 @@ const processWhere = (where, ctx, depth = 0) => {
}; };
const { db, uid, qb, alias } = ctx; const { db, uid, qb, alias } = ctx;
const meta = db.metadata.get(uid);
const filters = {}; const filters = {};
// for each key in where // for each key in where
for (const key in where) { for (const key in where) {
const value = where[key]; 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 operator $and $or then loop over them
if (GROUP_OPERATORS.includes(key)) { if (GROUP_OPERATORS.includes(key)) {
@ -87,14 +89,8 @@ const processWhere = (where, ctx, depth = 0) => {
} }
if (!attribute) { 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; continue;
// throw new Error(`Attribute ${key} not found on model ${uid}`); // 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)) { if (types.isScalar(attribute.type)) {
// TODO: convert attribute name to column name const columnName = toColumnName(meta, key);
// TODO: cast to DB type // TODO: cast to DB type
filters[qb.aliasColumn(key, alias)] = processNested(value, ctx); filters[qb.aliasColumn(columnName, alias)] = processNested(value, ctx);
continue; continue;
} }

View File

@ -57,7 +57,7 @@ const createQueryBuilder = (uid, db) => {
}, },
ref(name) { ref(name) {
return db.connection.ref(name); return db.connection.ref(helpers.toColumnName(meta, name));
}, },
update(data) { update(data) {
@ -168,20 +168,20 @@ const createQueryBuilder = (uid, db) => {
return ['select', 'count'].includes(state.type); return ['select', 'count'].includes(state.type);
}, },
aliasColumn(columnName, alias) { aliasColumn(key, alias) {
if (typeof columnName !== 'string') { if (typeof key !== 'string') {
return columnName; return key;
} }
if (columnName.indexOf('.') >= 0) { if (key.indexOf('.') >= 0) {
return columnName; return key;
} }
if (!_.isNil(alias)) { 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) { raw(...args) {
@ -205,9 +205,11 @@ const createQueryBuilder = (uid, db) => {
}, },
processState() { processState() {
state.select = state.select.map(field => helpers.toColumnName(meta, field));
state.orderBy = helpers.processOrderBy(state.orderBy, { qb: this, uid, db }); state.orderBy = helpers.processOrderBy(state.orderBy, { qb: this, uid, db });
state.where = helpers.processWhere(state.where, { 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.populate = helpers.processPopulate(state.populate, { qb: this, uid, db });
state.data = helpers.toRow(meta, state.data);
}, },
getKnexQuery() { 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 there are joins and it is a delete or update use a sub query
if (state.search) { if (state.search) {
qb.where(subQb => { qb.where(subQb => {
helpers.applySearch(subQb, state.search, { alias: this.alias, db, uid }); helpers.applySearch(subQb, state.search, { qb: this, db, uid });
}); });
} }

View File

@ -14,17 +14,11 @@ const createColumn = (name, attribute) => {
unsigned: false, unsigned: false,
...opts, ...opts,
...(attribute.column || {}), ...(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 createTable = meta => {
const table = { const table = {
// TODO: allow passing custom params to the DB from the model definition
name: meta.tableName, name: meta.tableName,
indexes: meta.indexes || [], indexes: meta.indexes || [],
foreignKeys: meta.foreignKeys || [], foreignKeys: meta.foreignKeys || [],
@ -76,8 +70,8 @@ const createTable = meta => {
columns: [columnName], columns: [columnName],
}); });
} }
} else if (shouldCreateColumn(attribute)) { } else if (types.isScalar(attribute.type)) {
const column = createColumn(key, meta.attributes[key]); const column = createColumn(attribute.columnName || key, attribute);
if (column.unique) { if (column.unique) {
table.indexes.push({ table.indexes.push({

View File

@ -20,7 +20,7 @@ const enableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => {
if (!hasDraftAndPublish(oldContentType) && hasDraftAndPublish(contentType)) { if (!hasDraftAndPublish(oldContentType) && hasDraftAndPublish(contentType)) {
const qb = strapi.db.queryBuilder(uid); const qb = strapi.db.queryBuilder(uid);
await qb await qb
.update({ published_at: qb.ref('created_at') }) .update({ published_at: qb.ref('createdAt') })
.where({ published_at: null }) .where({ published_at: null })
.execute(); .execute();
} }

View File

@ -64,8 +64,8 @@ describe('Content types utils', () => {
expect(getNonWritableAttributes(model)).toEqual([ expect(getNonWritableAttributes(model)).toEqual([
'id', 'id',
'created_at', 'createdAt',
'updated_at', 'updatedAt',
'non_writable_field', 'non_writable_field',
]); ]);
}); });

View File

@ -10,8 +10,8 @@ const PUBLISHED_AT_ATTRIBUTE = 'published_at';
const CREATED_BY_ATTRIBUTE = 'created_by'; const CREATED_BY_ATTRIBUTE = 'created_by';
const UPDATED_BY_ATTRIBUTE = 'updated_by'; const UPDATED_BY_ATTRIBUTE = 'updated_by';
const CREATED_AT_ATTRIBUTE = 'created_at'; const CREATED_AT_ATTRIBUTE = 'createdAt';
const UPDATED_AT_ATTRIBUTE = 'updated_at'; const UPDATED_AT_ATTRIBUTE = 'updatedAt';
const DP_PUB_STATE_LIVE = 'live'; const DP_PUB_STATE_LIVE = 'live';
const DP_PUB_STATE_PREVIEW = 'preview'; const DP_PUB_STATE_PREVIEW = 'preview';

View File

@ -11,7 +11,7 @@ const data = {
deletedLocales: [], 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 compareLocales = (a, b) => (a.code < b.code ? -1 : 1);
const productModel = { const productModel = {