Update model relation definition

This commit is contained in:
Alexandre Bodin 2021-06-18 12:27:47 +02:00
parent 6ac2c0f9b4
commit a992a73b2e
16 changed files with 370 additions and 276 deletions

View File

@ -8,10 +8,7 @@
"options": {
"draftAndPublish": false,
"increments": true,
"timestamps": [
"created_at",
"updated_at"
],
"timestamps": ["created_at", "updated_at"],
"comment": ""
},
"pluginOptions": {
@ -29,18 +26,15 @@
}
},
"categories": {
"collection": "category",
"via": "addresses",
"dominant": true
"type": "relation",
"relation": "manyToMany",
"target": "application::category.category",
"inversedBy": "addresses"
},
"cover": {
"model": "file",
"via": "related",
"allowedTypes": [
"files",
"images",
"videos"
],
"allowedTypes": ["files", "images", "videos"],
"plugin": "upload",
"required": false,
"pluginOptions": {
@ -52,9 +46,7 @@
"images": {
"collection": "file",
"via": "related",
"allowedTypes": [
"images"
],
"allowedTypes": ["images"],
"plugin": "upload",
"required": false,
"pluginOptions": {
@ -74,8 +66,10 @@
}
},
"likes": {
"collection": "like",
"via": "address"
"type": "relation",
"relation": "oneToMany",
"target": "application::like.like",
"mappedBy": "address"
},
"json": {
"type": "json",

View File

@ -16,8 +16,10 @@
"type": "string"
},
"addresses": {
"via": "categories",
"collection": "address"
"type": "relation",
"relation": "manyToMany",
"target": "application::address.address",
"mappedBy": "categories"
}
}
}

View File

@ -12,17 +12,22 @@
"comment": ""
},
"attributes": {
"authore": {
"plugin": "users-permissions",
"model": "user"
"author": {
"type": "relation",
"relation": "oneToOne",
"target": "plugins::users-permissions.user"
},
"review": {
"model": "review",
"via": "likes"
"type": "relation",
"relation": "manyToOne",
"target": "application::review.review",
"inversedBy": "likes"
},
"address": {
"via": "likes",
"model": "address"
"type": "relation",
"relation": "manyToOne",
"target": "application::address.address",
"inversedBy": "likes"
}
}
}

View File

@ -16,12 +16,16 @@
"type": "text"
},
"menusections": {
"via": "menu",
"collection": "menusection"
"type": "relation",
"relation": "oneToMany",
"target": "application::menusection.menusection",
"mappedBy": "menu"
},
"restaurant": {
"via": "menu",
"model": "restaurant"
"type": "relation",
"relation": "oneToOne",
"target": "application::restaurant.restaurant",
"mappedBy": "menu"
}
}
}

View File

@ -24,8 +24,10 @@
"required": true
},
"menu": {
"model": "menu",
"via": "menusections"
"type": "relation",
"relation": "manyToOne",
"target": "application::menu.menu",
"inversedBy": "menusections"
}
}
}

View File

@ -75,7 +75,9 @@
"max": 35.12
},
"address": {
"model": "address"
"type": "relation",
"relation": "oneToOne",
"target": "application::address.address"
},
"cover": {
"model": "file",
@ -109,7 +111,9 @@
}
},
"categories": {
"collection": "category"
"type": "relation",
"relation": "oneToMany",
"target": "application::category.category"
},
"description": {
"type": "richtext",
@ -133,8 +137,10 @@
}
},
"menu": {
"model": "menu",
"via": "restaurant"
"type": "relation",
"relation": "oneToOne",
"target": "application::menu.menu",
"inversedBy": "restaurant"
},
"opening_times": {
"component": "default.openingtimes",

View File

@ -22,15 +22,20 @@
"max": 5
},
"likes": {
"via": "review",
"collection": "like"
"type": "relation",
"relation": "oneToMany",
"target": "application::like.like",
"mappedBy": "review"
},
"author": {
"model": "user",
"plugin": "users-permissions"
"type": "relation",
"relation": "oneToOne",
"target": "plugins::users-permissions.user"
},
"restaurant": {
"model": "restaurant"
"type": "relation",
"relation": "oneToOne",
"target": "application::restaurant.restaurant"
}
}
}

View File

@ -27,7 +27,9 @@
"type": "richtext"
},
"categories": {
"collection": "category"
"type": "relation",
"relation": "oneToOne",
"target": "application::category.category"
}
}
}

View File

@ -1,5 +1,5 @@
{
"collectionName": "users-permissions_role",
"collectionName": "up_roles",
"info": {
"name": "role",
"description": ""
@ -25,16 +25,18 @@
"configurable": false
},
"permissions": {
"collection": "permission",
"via": "role",
"plugin": "users-permissions",
"configurable": false,
"isVirtual": true
"type": "relation",
"relation": "oneToMany",
"target": "plugins::users-permissions.permission",
"mappedBy": "role",
"configurable": false
},
"users": {
"collection": "user",
"via": "role",
"plugin": "users-permissions"
"type": "relation",
"relation": "oneToMany",
"target": "plugins::users-permissions.user",
"mappedBy": "role",
"configurable": false
}
}
}

View File

@ -1,5 +1,5 @@
{
"collectionName": "users-permissions_user",
"collectionName": "up_users",
"info": {
"name": "user",
"description": ""
@ -53,9 +53,10 @@
"configurable": false
},
"role": {
"model": "role",
"via": "users",
"plugin": "users-permissions",
"type": "relation",
"relation": "manyToOne",
"target": "plugins::users-permissions.role",
"inversedBy": "users",
"configurable": false
},
"picture": {

View File

@ -4,9 +4,9 @@ const _ = require('lodash');
const { Database } = require('../lib/index');
const category = {
singularName: 'category',
modelName: 'category',
uid: 'category',
tableName: 'categories',
collectionName: 'categories',
attributes: {
title: {
type: 'string',
@ -26,7 +26,7 @@ const category = {
relation: 'oneToMany',
target: 'article',
mappedBy: 'category',
useJoinTable: false,
// useJoinTable: false,
},
compo: {
type: 'component',
@ -36,9 +36,9 @@ const category = {
};
const article = {
singularName: 'article',
modelName: 'article',
uid: 'article',
tableName: 'articles',
collectionName: 'articles',
attributes: {
title: {
type: 'string',
@ -73,9 +73,9 @@ const article = {
};
const tags = {
singularName: 'tag',
modelName: 'tag',
uid: 'tag',
tableName: 'tags',
collectionName: 'tags',
attributes: {
name: {
type: 'string',
@ -90,9 +90,9 @@ const tags = {
};
const compo = {
singularName: 'compo',
modelName: 'compo',
uid: 'compo',
tableName: 'compos',
collectionName: 'compos',
attributes: {
key: {
type: 'string',
@ -104,9 +104,9 @@ const compo = {
};
const user = {
singularName: 'user',
modelName: 'user',
uid: 'user',
tableName: 'users',
collectionName: 'users',
attributes: {
address: {
type: 'relation',
@ -119,9 +119,9 @@ const user = {
};
const address = {
singularName: 'address',
modelName: 'address',
uid: 'address',
tableName: 'addresses',
collectionName: 'addresses',
attributes: {
name: {
type: 'string',
@ -148,9 +148,9 @@ const address = {
// });
const file = {
singularName: 'file',
modelName: 'file',
uid: 'file',
tableName: 'files',
collectionName: 'files',
attributes: {
name: {
type: 'string',
@ -208,9 +208,9 @@ const file = {
};
const fileMorph = {
singularName: 'file-morph',
modelName: 'file-morph',
uid: 'file-morph',
tableName: 'file_morphs',
collectionName: 'file_morphs',
attributes: {
// file: {
// type: 'relation',
@ -233,7 +233,7 @@ const orm = new Database({
},
// debug: true,
},
models: Database.transfomrContentType([
models: Database.transformContentTypes([
category,
article,
compo,
@ -294,7 +294,7 @@ async function main() {
// const r = await orm.entityManager
// .createQueryBuilder('article')
// .select(['*'])
// .select('*')
// .join({
// rootColumn: 'id',
// alias: 'ac',
@ -308,6 +308,12 @@ async function main() {
// referencedTable: 'categories',
// referencedColumn: 'id',
// })
// .where({
// $and: [],
// })
// .populate({
// category: true,
// })
// .execute();
// console.log(r);
@ -535,25 +541,71 @@ async function main() {
limit: 5,
});
// const articleCategory = orm.query('article').load(article, 'category', {
// select: ['id', 'title'],
// limit: 5,
// offset: 2,
// orderBy: 'title',
// where: {},
// });
// const article = await orm.query('article').populate(article, {
// category: true,
// tags: true
// });
await orm.query('article').findMany({
limit: 5,
where: {
category: {
title: {
$contains: '09',
},
// category: {
// title: {
// $contains: '09',
// },
// },
// tags: {
// title: {
// $contains: 'xxx'
// }
// },
compo: {
key: 'xx',
},
// $and: [],
// $or: [],
// $not: {},
// field: {
// $not: {
// $contains: 'title',
// },
// },
},
populate: {
category: {
select: ['id', 'title'],
limit: 5,
offset: 2,
orderBy: 'title',
where: {
title: {
$contains: '7',
// title: {
// $contains: '7',
// },
// article: {
// title: {
// $contains: 'test'
// }
// }
},
populate: {
articles: {
populate: {
tags: true,
},
},
},
},
tags: true,
// tags: true,
compo: true,
},
orderBy: { compo: { key: 'DESC' } },

View File

@ -158,9 +158,8 @@ const createMetadata = (models = []) => {
// init pass
for (const model of models) {
if (!model.tableName) {
console.log(model)
console.log(model);
}
metadata.add({
@ -186,188 +185,48 @@ const createMetadata = (models = []) => {
}
for (const [attributeName, attribute] of Object.entries(meta.attributes)) {
if (types.isComponent(attribute.type)) {
// convert component to relation
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',
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,
},
},
inverseJoinColumn: {
name: 'component_id',
referencedColumn: 'id',
},
on: ['field', '=', attributeName],
},
});
});
continue;
}
if (types.isDynamicZone(attribute.type)) {
continue;
}
if (types.isRelation(attribute.type)) {
// NOTE: also validate
switch (attribute.relation) {
case 'oneToOne': {
/*
if one to one then
if owner then
if with join table then
create join table
else
create joinColumn
if bidirectional then
set inverse attribute joinCol or joinTable info correctly
else
this property must be set by the owner side
verify the owner side is valid // should be done before or at the same time ?
*/
if (isOwner(attribute)) {
if (shouldUseJoinTable(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
createJoinColum(metadata, {
attribute,
attributeName,
meta,
});
}
} else {
// verify other side is valid
}
break;
}
case 'oneToMany': {
/*
if one to many then
if unidirectional then
create join table
if bidirectional then
cannot be owning side
do nothing
*/
if (!isBidirectional(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
if (isOwner(attribute)) {
throw new Error(
'one side of a oneToMany cannot be the owner side in a bidirectional relation'
);
}
}
break;
}
case 'manyToOne': {
/*
if many to one then
if unidirectional then
if with join table then
create join table
else
create join column
else
must be the owner side
if with join table then
create join table
else
create join column
set inverse attribute joinCol or joinTable info correctly
*/
if (isBidirectional(attribute) && !isOwner(attribute)) {
throw new Error('The many side of a manyToOne must be the owning side');
}
if (shouldUseJoinTable(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
createJoinColum(metadata, {
attribute,
attributeName,
meta,
});
}
break;
}
case 'manyToMany': {
/*
if many to many then
if unidirectional
create join table
else
if owner then
if with join table then
create join table
else
do nothing
*/
if (!isBidirectional(attribute) || isOwner(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
}
break;
}
default: {
throw new Error(`Unknow relation ${attribute.relation}`);
}
continue;
}
/*
if (types.isDynamicZone(attribute.type)) {
continue;
}
if (types.isRelation(attribute.type)) {
// NOTE: also validate
createRelation(attributeName, attribute, meta, metadata);
polymorphic relations
OneToOneX
ManyToOneX
OnetoManyX
ManytoManyX
XOneToOne
XManyToOne
XOnetoMany
XManytoMany
XOneToOneX
XManyToOneX
XOnetoManyX
XManytoManyX
*/
continue;
}
} catch (error) {
throw new Error(
`Error on attribute ${attributeName} in model ${meta.singularName}(${meta.uid}): ${error.message}`
);
}
}
}
@ -375,6 +234,160 @@ const createMetadata = (models = []) => {
return metadata;
};
const createRelation = (attributeName, attribute, meta, metadata) => {
switch (attribute.relation) {
case 'oneToOne': {
/*
if one to one then
if owner then
if with join table then
create join table
else
create joinColumn
if bidirectional then
set inverse attribute joinCol or joinTable info correctly
else
this property must be set by the owner side
verify the owner side is valid // should be done before or at the same time ?
*/
if (isOwner(attribute)) {
if (shouldUseJoinTable(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
createJoinColum(metadata, {
attribute,
attributeName,
meta,
});
}
} else {
// verify other side is valid
}
break;
}
case 'oneToMany': {
/*
if one to many then
if unidirectional then
create join table
if bidirectional then
cannot be owning side
do nothing
*/
if (!isBidirectional(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
if (isOwner(attribute)) {
throw new Error(
'one side of a oneToMany cannot be the owner side in a bidirectional relation'
);
}
}
break;
}
case 'manyToOne': {
/*
if many to one then
if unidirectional then
if with join table then
create join table
else
create join column
else
must be the owner side
if with join table then
create join table
else
create join column
set inverse attribute joinCol or joinTable info correctly
*/
if (isBidirectional(attribute) && !isOwner(attribute)) {
throw new Error('The many side of a manyToOne must be the owning side');
}
if (shouldUseJoinTable(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
} else {
createJoinColum(metadata, {
attribute,
attributeName,
meta,
});
}
break;
}
case 'manyToMany': {
/*
if many to many then
if unidirectional
create join table
else
if owner then
if with join table then
create join table
else
do nothing
*/
if (!isBidirectional(attribute) || isOwner(attribute)) {
createJoinTable(metadata, {
attribute,
attributeName,
meta,
});
}
break;
}
default: {
throw new Error(`Unknow relation ${attribute.relation}`);
}
}
/*
polymorphic relations
OneToOneX
ManyToOneX
OnetoManyX
ManytoManyX
XOneToOne
XManyToOne
XOnetoMany
XManytoMany
XOneToOneX
XManyToOneX
XOnetoManyX
XManytoManyX
*/
};
// NOTE: we might just move the compo logic outside this layer too at some point
const createCompoLinkModelMeta = baseModelMeta => {
return {

View File

@ -376,7 +376,9 @@ const applyJoin = (qb, join) => {
inner.on(`${rootTable}.${rootColumn}`, `${alias}.${referencedColumn}`);
if (on) {
inner.onVal(...on);
for (const key in on) {
inner.onVal(`${alias}.${key}`, on[key]);
}
}
});
};

View File

@ -1,4 +1,5 @@
{
"collectionName": "up_permissions",
"info": {
"name": "permission",
"description": ""
@ -34,9 +35,10 @@
"configurable": false
},
"role": {
"model": "role",
"via": "permissions",
"plugin": "users-permissions",
"type": "relation",
"relation": "manyToOne",
"target": "plugins::users-permissions.role",
"inversedBy": "permissions",
"configurable": false
}
}

View File

@ -1,4 +1,5 @@
{
"collectionName": "up_roles",
"info": {
"name": "role",
"description": ""
@ -25,18 +26,18 @@
"configurable": false
},
"permissions": {
"collection": "permission",
"via": "role",
"plugin": "users-permissions",
"configurable": false,
"isVirtual": true
"type": "relation",
"relation": "oneToMany",
"target": "plugins::users-permissions.permission",
"mappedBy": "role",
"configurable": false
},
"users": {
"collection": "user",
"via": "role",
"configurable": false,
"plugin": "users-permissions"
"type": "relation",
"relation": "oneToMany",
"target": "plugins::users-permissions.user",
"mappedBy": "role",
"configurable": false
}
},
"collectionName": "users-permissions_role"
}
}

View File

@ -1,5 +1,5 @@
{
"collectionName": "users-permissions_user",
"collectionName": "up_users",
"info": {
"name": "user",
"description": ""
@ -53,9 +53,10 @@
"configurable": false
},
"role": {
"model": "role",
"via": "users",
"plugin": "users-permissions",
"type": "relation",
"relation": "manyToOne",
"target": "plugins::users-permissions.role",
"inversedBy": "users",
"configurable": false
}
}