Skip to content

Commit fef0e62

Browse files
committed
Getting models from server.
1 parent f340431 commit fef0e62

4 files changed

Lines changed: 325 additions & 3 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,26 @@ GET /db/task/columns
499499
500500
Note: These end-point must be enabled in the configuration with { schemaQueries: true }.
501501
502+
#### Models
503+
504+
When storing models in evol_object and evol_field tables, they can be queried through REST.
505+
506+
Get all models flagged as active.
507+
508+
```
509+
GET /md/models
510+
```
511+
512+
Get a model by ID (integer).
513+
514+
```
515+
GET /md/model/<modelid>
516+
517+
GET /md/model/1
518+
```
519+
520+
Note: Schema and Models end-points must be enabled in the configuration with { apiDesigner: true }.
521+
502522
#### API version
503523
504524
This endpoint gets the API version (as specified in the project's package.json file).

config.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ module.exports = {
1515
// - GraphQL support
1616
graphQL: true,
1717

18-
// - Permission to query DB schema for list of tables and columns
19-
schemaQueries: false,
20-
2118
// - API discovery
2219
apiInfo: true,
2320

@@ -48,4 +45,10 @@ module.exports = {
4845
logToConsole: true,
4946
logToFile: false,
5047

48+
// - Designer
49+
// - Enables storing models in the database (in tables "evol_%")
50+
apiDesigner: false,
51+
// - Query DB schema for list of tables and columns
52+
schemaQueries: false,
53+
5154
};

js/designer.js

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*!
2+
* evolutility-server-node :: designer.js
3+
* Tools to build models ( = build apps)
4+
*
5+
* https://github.com/evoluteur/evolutility-server-node
6+
* (c) 2019 Olivier Giulieri
7+
*/
8+
9+
const query = require('./utils/query'),
10+
db = query.db,
11+
logger = require('./utils/logger'),
12+
errors = require('./utils/errors'),
13+
config = require('../config.js');
14+
15+
const schema = '"'+(config.schema || 'evolutility')+'"';
16+
const camelProp = {
17+
'nameplural': 'namePlural',
18+
'pkey': 'pKey',
19+
'readonly': 'readOnly',
20+
'lovtable': 'lovTable',
21+
'inmany': 'inMany',
22+
'minlength': 'minLength',
23+
'maxlength': 'maxLength',
24+
'minvalue': 'minValue',
25+
'maxvalue': 'maxValue',
26+
'regexp': 'regExp',
27+
}
28+
const camelPropSQL = p => 't1."'+p+'"'+(camelProp[p] ? (' AS "'+camelProp[p]+'"') : '')
29+
const col2id = id => camelProp[id] || id
30+
const objProps = {
31+
ui: [
32+
"entity",
33+
"title",
34+
//"world_id",
35+
"active",
36+
"name",
37+
"nameplural",
38+
"icon",
39+
"description",
40+
//"c_date",
41+
//"u_date",
42+
],
43+
db: [
44+
"entity",
45+
"table",
46+
"pkey",
47+
"active",
48+
]
49+
}
50+
/*
51+
const groupProps = [
52+
"id",
53+
"type",
54+
"label",
55+
"icon",
56+
"css",
57+
"fields",
58+
"width",
59+
"header",
60+
"footer",
61+
"help",
62+
//"c_date",
63+
//"u_date",
64+
]
65+
*/
66+
const fldProps = {
67+
ui: [
68+
//"fid",
69+
"label",
70+
"labelshort",
71+
"position",
72+
//"fid",
73+
//"object_id",
74+
"type_id",
75+
//"dbcolumn",
76+
//"lovTable",
77+
//"lovColumn",
78+
"format",
79+
"width",
80+
"height",
81+
"css",
82+
"required",
83+
"readonly",
84+
"inmany",
85+
"minlength",
86+
"maxlength",
87+
"minvalue",
88+
"maxvalue",
89+
"regexp",
90+
"help",
91+
//"c_date",
92+
//"u_date"
93+
],
94+
db: [
95+
//"id",
96+
"label",
97+
"labelshort",
98+
"position",
99+
//"fid",
100+
//"object_id",
101+
"type_id",
102+
//"dbcolumn",
103+
//"lovTable",
104+
//"lovColumn",
105+
"format",
106+
"required",
107+
"readonly",
108+
"inmany",
109+
"minlength",
110+
"maxlength",
111+
"minvalue",
112+
"maxvalue",
113+
"regexp",
114+
"help",
115+
//"c_date",
116+
//"u_date"
117+
],
118+
}
119+
120+
const ftMap = {},
121+
ftMap2 = {},
122+
arrFieldTypes = [
123+
"text",
124+
"textmultiline",
125+
"boolean",
126+
"decimal",
127+
"money",
128+
"integer",
129+
"date",
130+
"time",
131+
"date-time",
132+
"image",
133+
"lov",
134+
"email",
135+
"url",
136+
]
137+
138+
arrFieldTypes.forEach((tid, idx) => {
139+
const id = idx + 1
140+
ftMap[tid] = id
141+
ftMap2[''+id] = tid
142+
})
143+
144+
const fieldTypeId2Name = id => ftMap2[id]
145+
146+
const trimField = (f, idx) => {
147+
let field = {}
148+
field.id=f.id
149+
field.position = (idx+1)*10
150+
fldProps.ui.forEach(prop => {
151+
const fid = col2id(prop)
152+
const fp = f[fid] || null
153+
if(fp!==null){
154+
field[fid] = fp
155+
}
156+
})
157+
field.type = fieldTypeId2Name(field.type_id)
158+
delete field.type_id
159+
return field
160+
}
161+
162+
function getModel(req, res) {
163+
logger.logReq('GET one MODEL', req);
164+
var id = req.params.id || 0,
165+
pkColumn = Number.isInteger(parseInt(id, 10)) ? 'id' : 'entity',
166+
sqlParams = [id], //t1.entity AS id2,
167+
sql, sql2
168+
169+
const modelType = 'ui' //'db'
170+
171+
// - Object
172+
let cols = objProps[modelType].map(camelPropSQL).join(',')
173+
sql = 'SELECT entity as id, '+cols+
174+
' FROM '+schema+'.evol_object AS t1 WHERE t1.'+pkColumn+'=$1 LIMIT 1';
175+
cols = fldProps.ui.map(camelPropSQL).join(',')
176+
sql2 = 'SELECT (CASE WHEN (fid IS NULL) THEN dbcolumn ELSE fid END) AS id, '+ cols +//', t_2.name AS type_name'+
177+
' FROM '+schema+'.evol_field AS t1' +
178+
//' LEFT JOIN "evolutility"."evol_field_type" AS t_2 ON t1."type_id"=t_2.id' +
179+
' WHERE object_id=$1'+
180+
' ORDER BY position, t1.id DESC';
181+
logger.logSQL(sql)
182+
logger.logSQL(sql2)
183+
184+
let qModel = {}
185+
db.conn.task(t => {
186+
return t.one(sql, sqlParams)
187+
.then(dataM => {
188+
if(dataM){
189+
qModel = dataM
190+
return t.many(sql2, sqlParams)
191+
}else{
192+
return null
193+
}
194+
})
195+
.catch(error => {
196+
return null
197+
});
198+
})
199+
.then((data) => {
200+
if(data){
201+
qModel.fields = data.map(trimField)
202+
return res.json(qModel);
203+
}else{
204+
return errors.badRequest(res, 'Invalid model ID.')
205+
}
206+
})
207+
.catch(error => {
208+
console.log(error)
209+
return errors.badRequest(res, 'Invalid model ID.')
210+
});
211+
/*
212+
// - Field Groups
213+
sql = 'SELECT t1."'+groupProps.join('", t1."')+'"'+
214+
' FROM '+schema+'.evol_field_group AS t1 WHERE id=$1';
215+
promises.push(runQueriesPromise(sql, sqlParams))
216+
217+
// TODO: Collection
218+
*/
219+
}
220+
221+
function getModels(req, res) {
222+
logger.logReq('GET all MODEL', req);
223+
//var //pkColumn = Number.isInteger(parseInt(id, 10)) ? 'id' : 'entity',
224+
var maxModels = 20,
225+
sqlParams = [true],
226+
sql, sql2,
227+
sqlFWOL = ' FROM '+schema+'.evol_object AS t1 WHERE active=true ORDER BY t1.id LIMIT '+maxModels
228+
229+
const modelType = 'ui' //'db'
230+
231+
// - Object
232+
let cols = objProps[modelType].map(camelPropSQL).join(',')
233+
cols = objProps.ui.map(camelPropSQL).join(',')
234+
sql = 'SELECT entity as id, id as oid, '+cols+sqlFWOL
235+
cols = fldProps.ui.map(camelPropSQL).join(',')
236+
sql2 = 'SELECT (CASE WHEN (fid IS NULL) THEN dbcolumn ELSE fid END) AS id, object_id, '+ cols +//', t_2.name AS type_name'+
237+
' FROM '+schema+'.evol_field AS t1' +
238+
//' LEFT JOIN "evolutility"."evol_field_type" AS t_2 ON t1."type_id"=t_2.id' +
239+
' WHERE object_id IN (SELECT id '+sqlFWOL+')'+
240+
' ORDER BY object_id, t1.position, t1.id';
241+
logger.logSQL(sql)
242+
logger.logSQL(sql2)
243+
244+
let qModel = []
245+
db.conn.task(t => {
246+
return t.many(sql)
247+
.then(dataM => {
248+
if(dataM){
249+
qModel = dataM
250+
return t.many(sql2, sqlParams)
251+
}else{
252+
return null
253+
}
254+
})
255+
.catch(error => {
256+
console.log(error)
257+
return null
258+
});
259+
})
260+
.then((dataFs) => {
261+
if(dataFs){
262+
const mh = {}
263+
qModel.forEach(m => {
264+
m.fields = [ ]
265+
mh[''+m.oid] = m
266+
})
267+
dataFs.forEach(f => {
268+
const m = mh[''+f.object_id]
269+
if(m){
270+
m.fields.push(trimField(f))
271+
}else{
272+
console.log('no model '+f.object_id+'.')
273+
}
274+
})
275+
return res.json(qModel);
276+
}else{
277+
return errors.badRequest(res, 'Invalid model ID 2.')
278+
}
279+
})
280+
.catch(error => {
281+
console.log(error)
282+
return errors.badRequest(res, 'Invalid model ID 1.')
283+
});
284+
285+
}
286+
287+
module.exports = {
288+
getModel: getModel,
289+
getModels: getModels,
290+
}

js/routes.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const express = require('express'),
1717
stats = require('./stats'),
1818
charts = require('./charts'),
1919
info = require('./info'),
20+
designer = require('./designer'),
2021
dbStructure = require('./utils/db-structure');
2122

2223
logger.startupMessage();
@@ -43,6 +44,14 @@ if(config.schemaQueries){
4344
router.get(apiPath+'db/:table/columns', dbStructure.getColumns);
4445
}
4546

47+
// ====== Models in DB ====================================
48+
if(config.apiDesigner){
49+
// - Models
50+
//router.post(apiPath+'md/model', designer.importModel);
51+
router.get(apiPath+'md/models', designer.getModels);
52+
router.get(apiPath+'md/model/:id', designer.getModel);
53+
}
54+
4655
// ====== GET STATS ====================================
4756
router.get(apiPath+':entity/stats', stats.numbers);
4857

0 commit comments

Comments
 (0)