2019-09-20 12:44:24 +02:00
|
|
|
'use strict';
|
|
|
|
|
2021-05-10 15:36:09 +02:00
|
|
|
const util = require('util');
|
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
const knex = require('knex');
|
|
|
|
|
|
|
|
const createSchemaProvider = require('./schema');
|
|
|
|
const createMetadata = require('./metadata');
|
|
|
|
// const Configuration = require('./configuration');
|
|
|
|
// const { resolveConnector } = require('./connector');
|
2021-05-10 15:36:09 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
strapi.db = new Database({
|
|
|
|
connector: 'my-connector'
|
|
|
|
connection: {
|
|
|
|
client: 'sqlite',
|
|
|
|
settings: {},
|
|
|
|
...
|
|
|
|
},
|
|
|
|
models: [],
|
|
|
|
})
|
|
|
|
|
|
|
|
db.query('article').create();
|
|
|
|
|
|
|
|
|
|
|
|
db.migration.create();
|
|
|
|
db.migration.up();
|
|
|
|
db.migration.down();
|
|
|
|
|
|
|
|
db.seed.run();
|
|
|
|
db.seed.create();
|
|
|
|
|
|
|
|
db.exporter.dump()
|
|
|
|
db.importer.restore()
|
|
|
|
|
|
|
|
db.schema.addField
|
|
|
|
db.schema.removeField
|
|
|
|
db.schema.addCollection
|
|
|
|
db.schema.removeCollection
|
|
|
|
|
|
|
|
|
|
|
|
Init
|
|
|
|
---
|
|
|
|
new DB() -> new Config() -> new Connector()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sync
|
|
|
|
---
|
|
|
|
the database is not initialized (not created / or empty)
|
|
|
|
strapi schema:create schema:drop schema:update
|
|
|
|
auto create / initiliazed ? or a cli command ?
|
|
|
|
|
|
|
|
|
|
|
|
generate schema from entities
|
|
|
|
apply schema to db (programmaticaly or via CLI)
|
|
|
|
|
|
|
|
schema.sync()
|
|
|
|
for each collection
|
|
|
|
check if !exists
|
|
|
|
then create
|
|
|
|
else update -> Migration ???
|
|
|
|
|
|
|
|
clean -> delete non existing collections from db (sync force)
|
|
|
|
|
|
|
|
The database already exsits & has been initialized
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Schema
|
|
|
|
---
|
|
|
|
|
|
|
|
mutliple models -> schema
|
|
|
|
|
|
|
|
|
|
|
|
article:
|
|
|
|
seo:
|
|
|
|
type: component
|
|
|
|
content:
|
|
|
|
type: dynamiczone
|
|
|
|
cover:
|
|
|
|
type: media
|
|
|
|
category:
|
|
|
|
type: relation
|
|
|
|
relation: manyToOne
|
|
|
|
target: category
|
|
|
|
dominant: true
|
|
|
|
metadata:
|
|
|
|
type: json
|
|
|
|
title:
|
|
|
|
type: string
|
|
|
|
connectorOption:
|
|
|
|
type: decimal
|
|
|
|
|
|
|
|
|
|
|
|
category:
|
|
|
|
title: string
|
|
|
|
articles: relation(article)
|
|
|
|
|
|
|
|
core_store:
|
|
|
|
key: string
|
|
|
|
value: json
|
|
|
|
|
|
|
|
seo
|
|
|
|
key: string
|
|
|
|
value: string
|
|
|
|
|
|
|
|
|
|
|
|
SQL schema:
|
|
|
|
|
|
|
|
articles
|
|
|
|
articles_components
|
|
|
|
articles_category__categories_articles -> ???
|
|
|
|
|
|
|
|
files_morph
|
|
|
|
files
|
|
|
|
|
|
|
|
categories
|
|
|
|
|
|
|
|
components_seos
|
|
|
|
|
|
|
|
core_store
|
|
|
|
|
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
|
2021-05-10 15:36:09 +02:00
|
|
|
|
|
|
|
Scenarios for migrations
|
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
- user edit a CT in the Admin -> should we update the DB in place ? or dump a migration file
|
2021-05-10 15:36:09 +02:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
const createQueryBuilder = (uid, db) => {
|
|
|
|
const { tableName } = db.metadata.get(uid);
|
|
|
|
|
|
|
|
let query = db.connection(tableName).select();
|
|
|
|
|
|
|
|
return {
|
|
|
|
count(...args) {
|
|
|
|
query = query.count(...args);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
where() {
|
|
|
|
// smart conditions
|
|
|
|
// query = query.where()
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
select(args) {
|
|
|
|
query = query.select(args);
|
|
|
|
},
|
|
|
|
|
|
|
|
limit(args) {
|
|
|
|
query = query.limit(args);
|
|
|
|
},
|
|
|
|
|
|
|
|
offset(args) {
|
|
|
|
query = query.offset(args);
|
|
|
|
},
|
|
|
|
|
|
|
|
populate() {
|
|
|
|
// all the magic happens here
|
|
|
|
},
|
|
|
|
|
|
|
|
query(params) {
|
|
|
|
const { where, select, limit, offset, populate } = params;
|
|
|
|
|
|
|
|
if (where) {
|
|
|
|
this.where(where);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (select) {
|
|
|
|
this.select(select);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (limit) {
|
|
|
|
this.limit(limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset) {
|
|
|
|
this.offset(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
async execute() {
|
|
|
|
const results = await query();
|
|
|
|
|
|
|
|
// handle populate now
|
|
|
|
return results;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const createEntityManager = db => {
|
|
|
|
const repoMap = {};
|
|
|
|
|
|
|
|
return {
|
|
|
|
async findOne(...args) {
|
|
|
|
const results = await this.findMany(...args);
|
|
|
|
|
|
|
|
return results[0];
|
|
|
|
},
|
|
|
|
|
|
|
|
// should we name it findOne because people are used to it ?
|
|
|
|
async findMany(uid, params) {
|
|
|
|
const qb = this.createQueryBuilder(uid).query(params);
|
|
|
|
|
|
|
|
return await qb.execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
// support search directly in find & count -> a search param ? a different feature with a search tables rather
|
|
|
|
|
|
|
|
async findWithCount(...args) {
|
|
|
|
const entities = await this.findMany(args);
|
|
|
|
const count = await this.count(args);
|
|
|
|
|
|
|
|
return [entities, count];
|
|
|
|
},
|
|
|
|
|
|
|
|
async count(uid, params) {
|
|
|
|
const qb = this.createQueryBuilder(uid).query(params);
|
|
|
|
|
|
|
|
return qb.count().execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
create() {
|
|
|
|
// create entry in DB
|
|
|
|
// create relation associations or move this to the entity service & call attach on the repo instead
|
|
|
|
},
|
|
|
|
|
|
|
|
createMany() {},
|
|
|
|
|
|
|
|
update() {},
|
|
|
|
updateMany() {},
|
|
|
|
|
|
|
|
delete() {},
|
|
|
|
deleteMany() {},
|
|
|
|
|
|
|
|
// populate already loaded entry
|
|
|
|
populate() {},
|
|
|
|
|
|
|
|
// method to work with components & dynamic zones
|
|
|
|
addComponent() {},
|
|
|
|
removeComponent() {},
|
|
|
|
setComponent() {},
|
|
|
|
|
|
|
|
// method to work with relations
|
|
|
|
attachRelation() {},
|
|
|
|
detachRelation() {},
|
|
|
|
setRelation() {},
|
|
|
|
|
|
|
|
// cascading
|
|
|
|
// aggregations
|
|
|
|
// -> avg
|
|
|
|
// -> min
|
|
|
|
// -> max
|
|
|
|
// -> grouping
|
|
|
|
|
|
|
|
// formulas
|
|
|
|
// custom queries
|
|
|
|
|
|
|
|
// utilities
|
|
|
|
// -> format
|
|
|
|
// -> parse
|
|
|
|
// -> map result
|
|
|
|
// -> map input
|
|
|
|
// -> validation
|
|
|
|
|
|
|
|
// extra features
|
|
|
|
// -> virtuals
|
|
|
|
// -> private
|
|
|
|
getQueryBuilder(uid) {
|
|
|
|
return createQueryBuilder(uid, db);
|
|
|
|
},
|
|
|
|
|
|
|
|
getRepository(uid) {
|
|
|
|
if (!repoMap[uid]) {
|
|
|
|
repoMap[uid] = createRepository(uid, db);
|
|
|
|
}
|
|
|
|
|
|
|
|
return repoMap[uid];
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const createRepository = (uid, db) => {
|
|
|
|
return {
|
|
|
|
find(...args) {
|
|
|
|
return db.em.find(uid, ...args);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const entityService = () => {
|
|
|
|
// knows more about abstraction then the query layer
|
|
|
|
// will be moved in the core services not the db
|
|
|
|
// D&P should wrap some d&p logic
|
|
|
|
// i18N should wrapp some i18n logic etc etc
|
|
|
|
};
|
|
|
|
|
2021-05-10 15:36:09 +02:00
|
|
|
class Database {
|
|
|
|
constructor(config) {
|
2021-05-18 10:16:03 +02:00
|
|
|
this.metadata = createMetadata();
|
|
|
|
|
|
|
|
// validate models are valid
|
|
|
|
this.metadata.validate();
|
|
|
|
|
|
|
|
// this.connector = resolveConnector(this.config);
|
|
|
|
|
|
|
|
this.connection = knex(config.connection);
|
|
|
|
|
|
|
|
// build some information to make queries & schema generation easier (relations / components / dz / media / primary key ...)
|
|
|
|
|
|
|
|
// build schema
|
|
|
|
// load form memory
|
|
|
|
// sync schema
|
|
|
|
this.schemaProvider = createSchemaProvider(this);
|
|
|
|
|
|
|
|
// migrations -> allow running them through cli before startup
|
2021-05-10 15:36:09 +02:00
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
this.em = createEntityManager(this);
|
2021-05-10 15:36:09 +02:00
|
|
|
}
|
2021-05-17 16:34:19 +02:00
|
|
|
|
2021-05-18 10:16:03 +02:00
|
|
|
query(uid) {
|
|
|
|
return this.em.getRepository(uid);
|
2021-05-17 16:34:19 +02:00
|
|
|
}
|
2021-05-10 15:36:09 +02:00
|
|
|
}
|
2019-09-20 12:44:24 +02:00
|
|
|
|
|
|
|
module.exports = {
|
2021-05-10 15:36:09 +02:00
|
|
|
Database,
|
2019-09-20 12:44:24 +02:00
|
|
|
};
|