mirror of
https://github.com/strapi/strapi.git
synced 2025-08-31 20:33:03 +00:00
use columnName snake casing and rename timestamp attributes
This commit is contained in:
parent
872e7317ca
commit
58e024d3ad
@ -5,12 +5,14 @@
|
||||
"displayName": "Category",
|
||||
"singularName": "category",
|
||||
"pluralName": "categories",
|
||||
"description": ""
|
||||
"description": "",
|
||||
"name": "Category"
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": true,
|
||||
"comment": ""
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 ==
|
||||
|
@ -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();
|
||||
|
@ -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');
|
||||
|
@ -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 }));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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') {
|
||||
|
@ -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: {
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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({
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ describe('Content types utils', () => {
|
||||
|
||||
expect(getNonWritableAttributes(model)).toEqual([
|
||||
'id',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'non_writable_field',
|
||||
]);
|
||||
});
|
||||
|
@ -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';
|
||||
|
@ -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 = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user