Browse Source

fix: hm symmetric column creation

Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com>
feat/0523-export-schema
Raju Udava 2 years ago
parent
commit
1822b22e4b
  1. 284
      packages/nocodb/tests/export-import/exportSchema.js
  2. 426
      packages/nocodb/tests/export-import/importSchema.js

284
packages/nocodb/tests/export-import/exportSchema.js

@ -1,19 +1,22 @@
const Api = require('nocodb-sdk').Api; const Api = require('nocodb-sdk').Api;
const { UITypes } = require('nocodb-sdk'); const { UITypes } = require('nocodb-sdk');
const jsonfile = require("jsonfile"); const jsonfile = require('jsonfile');
let ncMap = {} const GRID = 3, GALLERY = 2, FORM = 1;
let tblSchema = []
let api = {} let ncMap = { /* id: name <string> */ };
let viewStore = {columns: {}, sort: {}, filter: {}} let tblSchema = [];
let api = {};
let viewStore = { columns: {}, sort: {}, filter: {} };
const ncConfig = { const ncConfig = {
projectName: "sample", projectName: 'sample',
baseURL: "http://localhost:8080", baseURL: 'http://localhost:8080',
headers: { headers: {
'xc-auth': "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoidXNfdDNkb2ppNXdtbDJ3bHIiLCJyb2xlcyI6InVzZXIsc3VwZXIiLCJpYXQiOjE2NTMzODY4NTN9.EvMwhhWJTM4QdEpgpmK1wSxsy7QiP7-sHWVDuTyOXSI" 'xc-auth':
''
} }
} };
// helper routines // helper routines
// remove objects containing 0/ false/ null // remove objects containing 0/ false/ null
@ -21,110 +24,147 @@ const ncConfig = {
function removeEmpty(obj) { function removeEmpty(obj) {
return Object.fromEntries( return Object.fromEntries(
Object.entries(obj) Object.entries(obj)
.filter(([_, v]) => ((v != null) && (v != 0) && (v != false))) .filter(([_, v]) => v != null && v != 0 && v != false)
.map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v]) .map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v])
); );
} }
// let linksAdded = []
// function isLinkExists(pId, cId) {
// let idx = linksAdded.findIndex(a => a.child === pId && a.parent === cId)
// if(idx === -1) {
// linksAdded.push({ child: cId, parent: pId })
// return false;
// }
// return true;
// }
function ncGetColData(cId) {
}
function addColumnSpecificData(c) { function addColumnSpecificData(c) {
// pick required fields to proceed further // pick required fields to proceed further
let col = removeEmpty((({ id, title, column_name, uidt, dt, pk, pv, rqd, dtxp, system }) => let col = removeEmpty(
({ id, title, column_name, uidt, dt, pk, pv, rqd, dtxp, system }))(c)) (({ id, title, column_name, uidt, dt, pk, pv, rqd, dtxp, system }) => ({
id,
title,
column_name,
uidt,
dt,
pk,
pv,
rqd,
dtxp,
system
}))(c)
);
let colOptions = null switch (c.uidt) {
switch(c.uidt) {
case UITypes.Formula: case UITypes.Formula:
colOptions = { col.formula = c.colOptions.formula;
formula: c.colOptions.formula, col.formula_raw = c.colOptions.formula_raw;
formula_raw: c.colOptions.formula_raw break;
}
break
case UITypes.LinkToAnotherRecord: case UITypes.LinkToAnotherRecord:
colOptions = { col[`colOptions`] = {
fk_model_id: c.fk_model_id, fk_model_id: c.fk_model_id,
fk_related_model_id: c.colOptions.fk_related_model_id, fk_related_model_id: c.colOptions.fk_related_model_id,
fk_child_column_id: c.colOptions.fk_child_column_id, fk_child_column_id: c.colOptions.fk_child_column_id,
fk_parent_column_id: c.colOptions.fk_parent_column_id, fk_parent_column_id: c.colOptions.fk_parent_column_id,
type: c.colOptions.type type: c.colOptions.type
} };
break; break;
case UITypes.Lookup: case UITypes.Lookup:
colOptions = { col[`colOptions`] = {
fk_model_id: c.fk_model_id, fk_model_id: c.fk_model_id,
fk_relation_column_id: c.colOptions.fk_relation_column_id, fk_relation_column_id: c.colOptions.fk_relation_column_id,
fk_lookup_column_id: c.colOptions.fk_lookup_column_id, fk_lookup_column_id: c.colOptions.fk_lookup_column_id
} };
break; break;
case UITypes.Rollup: case UITypes.Rollup:
colOptions = { col[`colOptions`] = {
fk_model_id: c.fk_model_id, fk_model_id: c.fk_model_id,
fk_relation_column_id: c.colOptions.fk_relation_column_id, fk_relation_column_id: c.colOptions.fk_relation_column_id,
fk_rollup_column_id: c.colOptions.fk_rollup_column_id, fk_rollup_column_id: c.colOptions.fk_rollup_column_id,
rollup_function: c.colOptions.rollup_function rollup_function: c.colOptions.rollup_function
} };
break; break;
} }
// colOptions not required for formula
if (c.uidt === UITypes.Formula) {
col.formula = c.colOptions.formula;
col.formula_raw = c.colOptions.formula_raw;
}
else if(colOptions) col[`colOptions`] = colOptions;
return col; return col;
} }
function addViewDetails(v) { function addViewDetails(v) {
// pick required fields to proceed further // pick required fields to proceed further
let view = (({ id, title, type, show_system_fields, lock_type, order }) => ( let view = (({ id, title, type, show_system_fields, lock_type, order }) => ({
{ id, title, type, show_system_fields, lock_type, order }))(v); id,
title,
type,
show_system_fields,
lock_type,
order
}))(v);
// form view // form view
if(v.type === 1) { if (v.type === FORM) {
view.property = (({ heading, subheading, success_msg, redirect_after_secs, email, submit_another_form, show_blank_form }) => ( view.property = (({
{ heading, subheading, success_msg, redirect_after_secs, email, submit_another_form, show_blank_form }))(v.view); heading,
subheading,
success_msg,
redirect_after_secs,
email,
submit_another_form,
show_blank_form
}) => ({
heading,
subheading,
success_msg,
redirect_after_secs,
email,
submit_another_form,
show_blank_form
}))(v.view);
} }
// gallery view // gallery view
else if (v.type === 2) { else if (v.type === GALLERY) {
view.property = {fk_cover_image_col_id: ncMap[v.view.fk_cover_image_col_id]} view.property = {
fk_cover_image_col_id: ncMap[v.view.fk_cover_image_col_id]
};
} }
// gallery view doesn't share column information in api yet // gallery view doesn't share column information in api yet
if(v.type !== 2) { if (v.type !== GALLERY) {
if(v.type === 3) if (v.type === GRID)
view.columns = viewStore.columns[v.id].map(a => (({ id, width, order, show }) => ( view.columns = viewStore.columns[v.id].map(a =>
{ id, width, order, show }))(a)) (({ id, width, order, show }) => ({ id, width, order, show }))(a)
if(v.type === 1) );
view.columns = viewStore.columns[v.id].map(a => (({ id, order, show, label, help, description, required }) => ( if (v.type === FORM)
{ id, order, show, label, help, description, required }))(a)) view.columns = viewStore.columns[v.id].map(a =>
(({ id, order, show, label, help, description, required }) => ({
id,
order,
show,
label,
help,
description,
required
}))(a)
);
for (let i = 0; i < view.columns?.length; i++) for (let i = 0; i < view.columns?.length; i++)
view.columns[i].title = ncMap[viewStore.columns[v.id][i].id] view.columns[i].title = ncMap[viewStore.columns[v.id][i].id];
view.columns = view.columns.filter(a => a.title.includes('_nc_m2m_') === false) // skip hm & mm columns
view.columns = view.columns
?.filter(a => a.title?.includes('_nc_m2m_') === false)
.filter(a => a.title?.includes('nc_') === false);
} }
// filter & sort configurations // filter & sort configurations
if(v.type !== 1) { if (v.type !== FORM) {
view.sort = viewStore.sort[v.id].map(a => (({ fk_column_id, direction, order }) => ( view.sort = viewStore.sort[v.id].map(a =>
{ fk_column_id, direction, order }))(a)) (({ fk_column_id, direction, order }) => ({
view.filter = viewStore.filter[v.id].map(a => (({ fk_column_id, logical_op, comparison_op, value, order }) => ( fk_column_id,
{ fk_column_id, logical_op, comparison_op, value, order }))(a)) direction,
order
}))(a)
);
view.filter = viewStore.filter[v.id].map(a =>
(({ fk_column_id, logical_op, comparison_op, value, order }) => ({
fk_column_id,
logical_op,
comparison_op,
value,
order
}))(a)
);
} }
return view; return view;
} }
@ -132,53 +172,54 @@ function addViewDetails(v) {
// view data stored as is for quick access // view data stored as is for quick access
async function storeViewDetails(tableId) { async function storeViewDetails(tableId) {
// read view data for each table // read view data for each table
let viewList = await api.dbView.list(tableId) let viewList = await api.dbView.list(tableId);
for(let j=0; j<viewList.list.length; j++) { for (let j = 0; j < viewList.list.length; j++) {
let v = viewList.list[j] let v = viewList.list[j];
let viewDetails = [] let viewDetails = [];
// invoke view specific read to populate columns information // invoke view specific read to populate columns information
if (v.type === 1) viewDetails = (await api.dbView.formRead(v.id)).columns; if (v.type === FORM) viewDetails = (await api.dbView.formRead(v.id)).columns;
else if (v.type === 2) viewDetails = await api.dbView.galleryRead(v.id); else if (v.type === GALLERY) viewDetails = await api.dbView.galleryRead(v.id);
else if (v.type === 3) viewDetails = await api.dbView.gridColumnsList(v.id); else if (v.type === GRID) viewDetails = await api.dbView.gridColumnsList(v.id);
viewStore.columns[v.id] = viewDetails; viewStore.columns[v.id] = viewDetails;
// populate sort information // populate sort information
let vSort = await api.dbTableSort.list(v.id); let vSort = await api.dbTableSort.list(v.id);
viewStore.sort[v.id] = vSort.sorts.list viewStore.sort[v.id] = vSort.sorts.list;
let vFilter = await api.dbTableFilter.read(v.id) let vFilter = await api.dbTableFilter.read(v.id);
viewStore.filter[v.id] = vFilter viewStore.filter[v.id] = vFilter;
} }
} }
// mapping table for quick information access // mapping table for quick information access
// store maps for tableId, columnId, viewColumnId & viewId to their names // store maps for tableId, columnId, viewColumnId & viewId to their names
async function generateMapTbl(pId) { async function generateMapTbl(pId) {
const tblList = await api.dbTable.list(pId) const tblList = await api.dbTable.list(pId);
for(let i=0; i<tblList.list.length; i++) { for (let i = 0; i < tblList.list.length; i++) {
let tblId = tblList.list[i].id let tblId = tblList.list[i].id;
let tbl = await api.dbTable.read(tblId) let tbl = await api.dbTable.read(tblId);
// table ID <> name // table ID <> name
ncMap[tblId] = tbl.title; ncMap[tblId] = tbl.title;
// column ID <> name // column ID <> name
tbl.columns.map(x => ncMap[x.id] = x.title ) tbl.columns.map(x => (ncMap[x.id] = x.title));
// view ID <> name // view ID <> name
tbl.views.map(x => ncMap[x.id] = x.tn ) tbl.views.map(x => (ncMap[x.id] = x.tn));
for(let i=0; i<tbl.views.length; i++) { for (let i = 0; i < tbl.views.length; i++) {
let x = tbl.views[i] let x = tbl.views[i];
let viewColumns = [] let viewColumns = [];
if (x.type === 1) viewColumns = (await api.dbView.formRead(x.id)).columns; if (x.type === FORM) viewColumns = (await api.dbView.formRead(x.id)).columns;
else if (x.type === 2) viewColumns = (await api.dbView.galleryRead(x.id)).columns; else if (x.type === GALLERY)
else viewColumns = await api.dbView.gridColumnsList(x.id); viewColumns = (await api.dbView.galleryRead(x.id)).columns;
else if (x.type === GRID) viewColumns = await api.dbView.gridColumnsList(x.id);
// view column ID <> name // view column ID <> name
viewColumns?.map(a => ncMap[a.id] = ncMap[a.fk_column_id]) viewColumns?.map(a => (ncMap[a.id] = ncMap[a.fk_column_id]));
} }
} }
} }
@ -186,21 +227,23 @@ async function generateMapTbl(pId) {
// main // main
// //
async function exportSchema() { async function exportSchema() {
api = new Api( ncConfig ); api = new Api(ncConfig);
// fetch project details (id et.al) // fetch project details (id et.al)
const x = await api.project.list(); const x = await api.project.list();
const p = x.list.find(a => a.title === ncConfig.projectName); const p = x.list.find(a => a.title === ncConfig.projectName);
await generateMapTbl(p.id) await generateMapTbl(p.id);
// read project // read project
const tblList = await api.dbTable.list(p.id) const tblList = await api.dbTable.list(p.id);
for(let i=0; i<tblList.list.length; i++) {
let tblId = tblList.list[i].id
await storeViewDetails(tblId)
let tbl = await api.dbTable.read(tblId) // for each table
for (let i = 0; i < tblList.list.length; i++) {
let tblId = tblList.list[i].id;
await storeViewDetails(tblId);
let tbl = await api.dbTable.read(tblId);
// prepare schema // prepare schema
let tSchema = { let tSchema = {
@ -208,15 +251,46 @@ async function exportSchema() {
title: tbl.title, title: tbl.title,
table_name: tbl?.table_name, table_name: tbl?.table_name,
columns: [...tbl.columns.map(c => addColumnSpecificData(c))] columns: [...tbl.columns.map(c => addColumnSpecificData(c))]
.filter(a => a.title.includes('_nc_m2m_') === false) .filter(a => a.title.includes('_nc_m2m_') === false) // mm
.filter(a => !(a?.system===1 && a.uidt===UITypes.LinkToAnotherRecord )), .filter(a => a.title.includes(p.prefix) === false) // hm
.filter(
a => !(a?.system === 1 && a.uidt === UITypes.LinkToAnotherRecord)
),
views: [...tbl.views.map(v => addViewDetails(v))] views: [...tbl.views.map(v => addViewDetails(v))]
} };
tblSchema.push(tSchema) tblSchema.push(tSchema);
} }
} }
(async() => { (async () => {
await exportSchema() await exportSchema();
jsonfile.writeFileSync(`${ncConfig.projectName.replace(/ /g, '_')}.json`, tblSchema, { spaces: 2 }) jsonfile.writeFileSync(
})().catch(e => {console.log(e)}) `${ncConfig.projectName.replace(/ /g, '_')}.json`,
tblSchema,
{ spaces: 2 }
);
})().catch(e => {
console.log(e);
});
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

426
packages/nocodb/tests/export-import/importSchema.js

@ -1,59 +1,70 @@
// tbd // tbd
// - formula dependency list // - formula dependency list
// - nested lookup/ rollup // - nested lookup/ rollup
const Api = require('nocodb-sdk').Api; const Api = require('nocodb-sdk').Api;
const { UITypes } = require('nocodb-sdk'); const { UITypes } = require('nocodb-sdk');
const jsonfile = require("jsonfile"); const jsonfile = require('jsonfile');
let api = {}
let ncIn = jsonfile.readFileSync('sample.json')
let ncProject = {}
let link = []
let lookup = []
let rollup = []
let formula = []
let ncTables = {}
let rootLinks = []
const ncConfig = { const ncConfig = {
srcProject: "sample", srcProject: 'sample',
projectName: "x2", projectName: 'x2',
baseURL: "http://localhost:8080", baseURL: 'http://localhost:8080',
headers: { headers: {
'xc-auth': "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoidXNfdDNkb2ppNXdtbDJ3bHIiLCJyb2xlcyI6InVzZXIsc3VwZXIiLCJpYXQiOjE2NTMzODY4NTN9.EvMwhhWJTM4QdEpgpmK1wSxsy7QiP7-sHWVDuTyOXSI" 'xc-auth':
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoidXNfNXB3bzFpZ2ZucHJ2YjgiLCJyb2xlcyI6InVzZXIsc3VwZXIiLCJ0b2tlbl92ZXJzaW9uIjoiZWI3YmI5ZDFkMjkyMThlZTY1N2UzNGQ4NGZlOTlhMmJiNjRlYWJiZmEwMWJkYmY4ZjIzMjhjNWFmNWIwNzAxNWRjMDJiOThjY2E5ZjY4MTIiLCJpYXQiOjE2NTU2OTkyMTQsImV4cCI6MTY1NTczNTIxNH0.LzYz_z_0a1G1x---YLIYkFuFH5dk_YL5vPH4YbmYZew'
} }
} };
let ncIn = jsonfile.readFileSync(`${ncConfig.srcProject}.json`);
let api = {};
let ncProject = {};
let link = [];
let lookup = [];
let rollup = [];
let formula = [];
let rootLinks = [];
// maps v1 table ID, v2 table ID & table title to table schema
let ncTables = {};
async function createBaseTables() { async function createBaseTables() {
console.log(`createBaseTables`) console.log(`createBaseTables`);
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i] let tblSchema = ncIn[i];
let reducedColumnSet = tblSchema.columns.filter(a => a.uidt !== UITypes.LinkToAnotherRecord && a.uidt !== UITypes.Lookup && a.uidt !== UITypes.Rollup && a.uidt !== UITypes.Formula); let reducedColumnSet = tblSchema.columns.filter(
link.push(...tblSchema.columns.filter(a => a.uidt === UITypes.LinkToAnotherRecord)) a =>
lookup.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Lookup)) a.uidt !== UITypes.LinkToAnotherRecord &&
rollup.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Rollup)) a.uidt !== UITypes.Lookup &&
formula.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Formula)) a.uidt !== UITypes.Rollup &&
formula.map(a => a['table_id'] = tblSchema.id) a.uidt !== UITypes.Formula
);
link.push(
...tblSchema.columns.filter(a => a.uidt === UITypes.LinkToAnotherRecord)
);
lookup.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Lookup));
rollup.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Rollup));
formula.push(...tblSchema.columns.filter(a => a.uidt === UITypes.Formula));
formula.map(a => (a['table_id'] = tblSchema.id));
let tbl = await api.dbTable.create(ncProject.id, { let tbl = await api.dbTable.create(ncProject.id, {
title: tblSchema.title, title: tblSchema.title,
table_name: tblSchema.title, table_name: tblSchema.title,
columns: reducedColumnSet.map(({id,...rest}) => ({...rest})) columns: reducedColumnSet.map(({ id, ...rest }) => ({ ...rest }))
}) });
ncTables[tbl.title] = tbl; ncTables[tbl.title] = tbl;
ncTables[tbl.id] = tbl; ncTables[tbl.id] = tbl;
ncTables[tblSchema.id] = tbl; ncTables[tblSchema.id] = tbl;
} }
} }
let linksCreated = [] let linksCreated = [];
function isLinkCreated(pId, cId) { function isLinkCreated(pId, cId) {
let idx = linksCreated.findIndex(a => a.cId === pId && a.pId === cId) let idx = linksCreated.findIndex(a => a.cId === pId && a.pId === cId);
if(idx === -1) { if (idx === -1) {
linksCreated.push({pId: pId, cId: cId}) linksCreated.push({ pId: pId, cId: cId });
return false; return false;
} }
return true; return true;
@ -84,13 +95,21 @@ async function createFormula() {
} }
async function createLinks() { async function createLinks() {
console.log(`createLinks`) console.log(`createLinks`);
for (let i = 0; i < link.length; i++) { for (let i = 0; i < link.length; i++) {
if (((link[i].colOptions.type === 'mm') && if (
(false === isLinkCreated(link[i].colOptions.fk_parent_column_id, link[i].colOptions.fk_child_column_id))) (link[i].colOptions.type === 'mm' &&
|| (link[i].colOptions.type === 'hm')) { false ===
isLinkCreated(
link[i].colOptions.fk_parent_column_id,
link[i].colOptions.fk_child_column_id
)) ||
link[i].colOptions.type === 'hm'
) {
let srcTbl = ncTables[link[i].colOptions.fk_model_id]; let srcTbl = ncTables[link[i].colOptions.fk_model_id];
let dstTbl = ncTables[link[i].colOptions.fk_related_model_id]; let dstTbl = ncTables[link[i].colOptions.fk_related_model_id];
// create link // create link
let tbl = await api.dbTableColumn.create(srcTbl.id, { let tbl = await api.dbTableColumn.create(srcTbl.id, {
uidt: UITypes.LinkToAnotherRecord, uidt: UITypes.LinkToAnotherRecord,
@ -102,25 +121,57 @@ async function createLinks() {
ncTables[tbl.title] = tbl; ncTables[tbl.title] = tbl;
ncTables[tbl.id] = tbl; ncTables[tbl.id] = tbl;
ncTables[link[i].colOptions.fk_model_id] = tbl; ncTables[link[i].colOptions.fk_model_id] = tbl;
// for data-link procedure later
rootLinks.push({linkColumn: link[i], linkSrcTbl: srcTbl})
let v2ColSchema = tbl.columns.find(x => x.title === link[i].title) // for data-link procedure later
rootLinks.push({ linkColumn: link[i], linkSrcTbl: srcTbl });
// symmetry field update
//
let v2ColSchema = tbl.columns.find(x => x.title === link[i].title);
// read related table again after link is created // read related table again after link is created
dstTbl = await api.dbTable.read(dstTbl.id); dstTbl = await api.dbTable.read(dstTbl.id);
let v2SymmetricColumn = (link[i].colOptions.type === 'mm') ? let v2SymmetricColumn =
dstTbl.columns.find(x => x.uidt === UITypes.LinkToAnotherRecord && x?.colOptions.fk_parent_column_id === v2ColSchema.colOptions.fk_child_column_id && x?.colOptions.fk_child_column_id === v2ColSchema.colOptions.fk_parent_column_id) : link[i].colOptions.type === 'mm'
dstTbl.columns.find(x => x.uidt === UITypes.LinkToAnotherRecord && x?.colOptions.fk_parent_column_id === v2ColSchema.colOptions.fk_parent_column_id && x?.colOptions.fk_child_column_id === v2ColSchema.colOptions.fk_child_column_id) ? dstTbl.columns.find(
let v1SymmetricColumn = (link[i].colOptions.type === 'mm') ? x =>
link.find(x => x.colOptions.fk_parent_column_id === link[i].colOptions.fk_child_column_id && x.colOptions.fk_child_column_id === link[i].colOptions.fk_parent_column_id) : x.uidt === UITypes.LinkToAnotherRecord &&
link.find(x => x.colOptions.fk_parent_column_id === link[i].colOptions.fk_parent_column_id && x.colOptions.fk_child_column_id === link[i].colOptions.fk_child_column_id); x?.colOptions.fk_parent_column_id ===
v2ColSchema.colOptions.fk_child_column_id &&
x?.colOptions.fk_child_column_id ===
v2ColSchema.colOptions.fk_parent_column_id
)
: dstTbl.columns.find(
x =>
x.uidt === UITypes.LinkToAnotherRecord &&
x?.colOptions.fk_parent_column_id ===
v2ColSchema.colOptions.fk_parent_column_id &&
x?.colOptions.fk_child_column_id ===
v2ColSchema.colOptions.fk_child_column_id
);
let v1SymmetricColumn =
link[i].colOptions.type === 'mm'
? link.find(
x =>
x.colOptions.fk_parent_column_id ===
link[i].colOptions.fk_child_column_id &&
x.colOptions.fk_child_column_id ===
link[i].colOptions.fk_parent_column_id &&
x.colOptions.type === 'mm'
)
: link.find(
x =>
x.colOptions.fk_parent_column_id ===
link[i].colOptions.fk_parent_column_id &&
x.colOptions.fk_child_column_id ===
link[i].colOptions.fk_child_column_id &&
x.colOptions.type === 'bt'
);
tbl = await api.dbTableColumn.update(v2SymmetricColumn.id, { tbl = await api.dbTableColumn.update(v2SymmetricColumn.id, {
...v2SymmetricColumn, ...v2SymmetricColumn,
title: v1SymmetricColumn.title, title: v1SymmetricColumn.title,
column_name: null column_name: null
}) });
ncTables[tbl.title] = tbl; ncTables[tbl.title] = tbl;
ncTables[tbl.id] = tbl; ncTables[tbl.id] = tbl;
ncTables[v1SymmetricColumn.colOptions.fk_model_id] = tbl; ncTables[v1SymmetricColumn.colOptions.fk_model_id] = tbl;
@ -129,26 +180,32 @@ async function createLinks() {
} }
function get_v2Id(v1ColId) { function get_v2Id(v1ColId) {
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i] let tblSchema = ncIn[i];
let colSchema = {} let colSchema = {};
if(undefined !== (colSchema = tblSchema.columns.find(x => x.id === v1ColId))) { if (
undefined !== (colSchema = tblSchema.columns.find(x => x.id === v1ColId))
) {
let colName = colSchema.title; let colName = colSchema.title;
let v2Tbl = ncTables[tblSchema.id]; let v2Tbl = ncTables[tblSchema.id];
return v2Tbl.columns.find(y => y.title === colName)?.id return v2Tbl.columns.find(y => y.title === colName)?.id;
} }
} }
} }
async function createLookup() { async function createLookup() {
console.log(`createLookup`) console.log(`createLookup`);
for(let i=0; i<lookup.length; i++) { for (let i = 0; i < lookup.length; i++) {
let srcTbl = ncTables[lookup[i].colOptions.fk_model_id]; let srcTbl = ncTables[lookup[i].colOptions.fk_model_id];
let v2_fk_relation_column_id = get_v2Id(lookup[i].colOptions.fk_relation_column_id) let v2_fk_relation_column_id = get_v2Id(
let v2_lookup_column_id = get_v2Id(lookup[i].colOptions.fk_lookup_column_id) lookup[i].colOptions.fk_relation_column_id
);
if(v2_lookup_column_id) { let v2_lookup_column_id = get_v2Id(
lookup[i].colOptions.fk_lookup_column_id
);
if (v2_lookup_column_id) {
let tbl = await api.dbTableColumn.create(srcTbl.id, { let tbl = await api.dbTableColumn.create(srcTbl.id, {
uidt: UITypes.Lookup, uidt: UITypes.Lookup,
title: lookup[i].title, title: lookup[i].title,
@ -163,14 +220,18 @@ async function createLookup() {
} }
async function createRollup() { async function createRollup() {
console.log(`createRollup`) console.log(`createRollup`);
for(let i=0; i<rollup.length; i++) { for (let i = 0; i < rollup.length; i++) {
let srcTbl = ncTables[rollup[i].colOptions.fk_model_id]; let srcTbl = ncTables[rollup[i].colOptions.fk_model_id];
let v2_fk_relation_column_id = get_v2Id(rollup[i].colOptions.fk_relation_column_id) let v2_fk_relation_column_id = get_v2Id(
let v2_rollup_column_id = get_v2Id(rollup[i].colOptions.fk_rollup_column_id) rollup[i].colOptions.fk_relation_column_id
);
if(v2_rollup_column_id) { let v2_rollup_column_id = get_v2Id(
rollup[i].colOptions.fk_rollup_column_id
);
if (v2_rollup_column_id) {
let tbl = await api.dbTableColumn.create(srcTbl.id, { let tbl = await api.dbTableColumn.create(srcTbl.id, {
uidt: UITypes.Rollup, uidt: UITypes.Rollup,
title: rollup[i].title, title: rollup[i].title,
@ -187,9 +248,9 @@ async function createRollup() {
} }
async function configureGrid() { async function configureGrid() {
console.log(`configureGrid`) console.log(`configureGrid`);
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i]; let tblSchema = ncIn[i];
let tblId = ncTables[tblSchema.id].id; let tblId = ncTables[tblSchema.id].id;
let gridList = tblSchema.views.filter(a => a.type === 3); let gridList = tblSchema.views.filter(a => a.type === 3);
@ -198,37 +259,53 @@ async function configureGrid() {
const view = await api.dbView.list(tblId); const view = await api.dbView.list(tblId);
// create / rename view // create / rename view
for(let gridCnt=0; gridCnt< gridList.length; gridCnt++) { for (let gridCnt = 0; gridCnt < gridList.length; gridCnt++) {
let viewCreated = {} let viewCreated = {};
// rename first view; default view already created // rename first view; default view already created
if(gridCnt === 0) { if (gridCnt === 0) {
viewCreated = await api.dbView.update(view.list[0].id, {title: gridList[gridCnt].title}); viewCreated = await api.dbView.update(view.list[0].id, {
title: gridList[gridCnt].title
});
} }
// create new views // create new views
else { else {
viewCreated = await api.dbView.gridCreate(tblId, {title: gridList[gridCnt].title}); viewCreated = await api.dbView.gridCreate(tblId, {
title: gridList[gridCnt].title
});
} }
// retrieve view Info // retrieve view Info
let viewId = viewCreated.id let viewId = viewCreated.id;
let viewDetails = await api.dbView.gridColumnsList(viewId); let viewDetails = await api.dbView.gridColumnsList(viewId);
// column visibility // column visibility
for(let colCnt = 0; colCnt < gridList[gridCnt].columns.length; colCnt++) { for (
let ncColumnId = srcTbl.columns.find(a => a.title === gridList[gridCnt].columns[colCnt].title)?.id let colCnt = 0;
colCnt < gridList[gridCnt].columns.length;
colCnt++
) {
let ncColumnId = srcTbl.columns.find(
a => a.title === gridList[gridCnt].columns[colCnt].title
)?.id;
// let ncViewColumnId = await nc_getViewColumnId( viewCreated.id, "grid", ncColumnId ) // let ncViewColumnId = await nc_getViewColumnId( viewCreated.id, "grid", ncColumnId )
let ncViewColumnId = viewDetails.find(x => x.fk_column_id === ncColumnId)?.id; let ncViewColumnId = viewDetails.find(
x => x.fk_column_id === ncColumnId
)?.id;
// column order & visibility // column order & visibility
await api.dbViewColumn.update(viewCreated.id, ncViewColumnId, { await api.dbViewColumn.update(viewCreated.id, ncViewColumnId, {
show: gridList[gridCnt].columns[colCnt].show, show: gridList[gridCnt].columns[colCnt].show,
order: gridList[gridCnt].columns[colCnt].order, order: gridList[gridCnt].columns[colCnt].order
});
await api.dbView.gridColumnUpdate(ncViewColumnId, {
width: gridList[gridCnt].columns[colCnt].width
}); });
await api.dbView.gridColumnUpdate(ncViewColumnId, {width: gridList[gridCnt].columns[colCnt].width})
} }
// sort // sort
for(let sCnt = 0; sCnt < gridList[gridCnt].sort.length; sCnt++) { for (let sCnt = 0; sCnt < gridList[gridCnt].sort.length; sCnt++) {
let sColName = tblSchema.columns.find(a => gridList[gridCnt].sort[sCnt].fk_column_id === a.id).title; let sColName = tblSchema.columns.find(
a => gridList[gridCnt].sort[sCnt].fk_column_id === a.id
).title;
await api.dbTableSort.create(viewId, { await api.dbTableSort.create(viewId, {
fk_column_id: srcTbl.columns.find(a => a.title === sColName)?.id, fk_column_id: srcTbl.columns.find(a => a.title === sColName)?.id,
direction: gridList[gridCnt].sort[sCnt].direction direction: gridList[gridCnt].sort[sCnt].direction
@ -236,10 +313,13 @@ async function configureGrid() {
} }
// filter // filter
for(let fCnt = 0; fCnt < gridList[gridCnt].filter.length; fCnt++) { for (let fCnt = 0; fCnt < gridList[gridCnt].filter.length; fCnt++) {
let fColName = tblSchema.columns.find(a => gridList[gridCnt].sort[fCnt].fk_column_id === a.id).title; let fColName = tblSchema.columns.find(
a => gridList[gridCnt].sort[fCnt].fk_column_id === a.id
).title;
await api.dbTableFilter.create(viewId, { await api.dbTableFilter.create(viewId, {
...gridList[gridCnt].filter[fCnt], fk_column_id: srcTbl.columns.find(a => a.title === fColName)?.id ...gridList[gridCnt].filter[fCnt],
fk_column_id: srcTbl.columns.find(a => a.title === fColName)?.id
}); });
} }
} }
@ -247,28 +327,30 @@ async function configureGrid() {
} }
async function configureGallery() { async function configureGallery() {
console.log(`configureGallery`) console.log(`configureGallery`);
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i]; let tblSchema = ncIn[i];
let tblId = ncTables[tblSchema.id].id; let tblId = ncTables[tblSchema.id].id;
let galleryList = tblSchema.views.filter(a => a.type === 2); let galleryList = tblSchema.views.filter(a => a.type === 2);
for(let cnt=0; cnt< galleryList.length; cnt++) { for (let cnt = 0; cnt < galleryList.length; cnt++) {
const viewCreated = await api.dbView.galleryCreate(tblId, {title: galleryList[cnt].title}); const viewCreated = await api.dbView.galleryCreate(tblId, {
title: galleryList[cnt].title
});
} }
} }
} }
async function configureForm() { async function configureForm() {
console.log(`configureForm`) console.log(`configureForm`);
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i]; let tblSchema = ncIn[i];
let tblId = ncTables[tblSchema.id].id; let tblId = ncTables[tblSchema.id].id;
let formList = tblSchema.views.filter(a => a.type === 1); let formList = tblSchema.views.filter(a => a.type === 1);
let srcTbl = await api.dbTable.read(tblId); let srcTbl = await api.dbTable.read(tblId);
for(let formCnt=0; formCnt< formList.length; formCnt++) { for (let formCnt = 0; formCnt < formList.length; formCnt++) {
const formData = { const formData = {
title: formList[formCnt].title, title: formList[formCnt].title,
...formList[formCnt].property ...formList[formCnt].property
@ -276,16 +358,26 @@ async function configureForm() {
const viewCreated = await api.dbView.formCreate(tblId, formData); const viewCreated = await api.dbView.formCreate(tblId, formData);
// column visibility // column visibility
for(let colCnt = 0; colCnt < formList[formCnt].columns.length; colCnt++) { for (
let ncColumnId = srcTbl.columns.find(a => a.title === formList[formCnt].columns[colCnt].title)?.id let colCnt = 0;
let ncViewColumnId = await nc_getViewColumnId( viewCreated.id, "form", ncColumnId ) colCnt < formList[formCnt].columns.length;
colCnt++
) {
let ncColumnId = srcTbl.columns.find(
a => a.title === formList[formCnt].columns[colCnt].title
)?.id;
let ncViewColumnId = await nc_getViewColumnId(
viewCreated.id,
'form',
ncColumnId
);
// column order & visibility // column order & visibility
await api.dbView.formColumnUpdate(ncViewColumnId, { await api.dbView.formColumnUpdate(ncViewColumnId, {
show: formList[formCnt].columns[colCnt].show, show: formList[formCnt].columns[colCnt].show,
order: formList[formCnt].columns[colCnt].order, order: formList[formCnt].columns[colCnt].order,
label: formList[formCnt].columns[colCnt].label, label: formList[formCnt].columns[colCnt].label,
description: formList[formCnt].columns[colCnt].description, description: formList[formCnt].columns[colCnt].description,
required: formList[formCnt].columns[colCnt].required, required: formList[formCnt].columns[colCnt].required
}); });
} }
} }
@ -293,97 +385,153 @@ async function configureForm() {
} }
async function restoreBaseData() { async function restoreBaseData() {
console.log(`restoreBaseData`) console.log(`restoreBaseData`);
for(let i=0; i<ncIn.length; i++) { for (let i = 0; i < ncIn.length; i++) {
let tblSchema = ncIn[i]; let tblSchema = ncIn[i];
let tblId = ncTables[tblSchema.id].id; let tblId = ncTables[tblSchema.id].id;
let pk = tblSchema.columns.find(a => a.pk).title let pk = tblSchema.columns.find(a => a.pk).title;
let moreRecords = true; let moreRecords = true;
let offset = 0, limit = 25; let offset = 0,
limit = 25;
while(moreRecords) {
let recList = await api.dbTableRow.list("nc", ncConfig.srcProject, tblSchema.title, {}, { while (moreRecords) {
query: { limit: limit, offset: offset } let recList = await api.dbTableRow.list(
}) 'nc',
moreRecords = !recList.pageInfo.isLastPage ncConfig.srcProject,
offset += limit tblSchema.title,
{},
{
query: { limit: limit, offset: offset }
}
);
moreRecords = !recList.pageInfo.isLastPage;
offset += limit;
for (let recCnt = 0; recCnt < recList.list.length; recCnt++) { for (let recCnt = 0; recCnt < recList.list.length; recCnt++) {
let record = await api.dbTableRow.read("nc", ncConfig.srcProject, tblSchema.title, recList.list[recCnt][pk]) let record = await api.dbTableRow.read(
'nc',
ncConfig.srcProject,
tblSchema.title,
recList.list[recCnt][pk]
);
// post-processing on the record // post-processing on the record
for (const [key, value] of Object.entries(record)) { for (const [key, value] of Object.entries(record)) {
let table = ncTables[tblId] let table = ncTables[tblId];
// retrieve datatype // retrieve datatype
const dt = table.columns.find(x => x.title === key)?.uidt; const dt = table.columns.find(x => x.title === key)?.uidt;
if (dt === UITypes.LinkToAnotherRecord) delete record[key]; if (dt === UITypes.LinkToAnotherRecord) delete record[key];
if (dt === UITypes.Lookup) delete record[key]; if (dt === UITypes.Lookup) delete record[key];
if (dt === UITypes.Rollup) delete record[key]; if (dt === UITypes.Rollup) delete record[key];
} }
await api.dbTableRow.create("nc", ncConfig.projectName, tblSchema.title, record) await api.dbTableRow.create(
'nc',
ncConfig.projectName,
tblSchema.title,
record
);
} }
} }
} }
} }
async function restoreLinks() { async function restoreLinks() {
console.log(`restoreLinks`) console.log(`restoreLinks`);
for(let i=0; i<rootLinks.length; i++) { for (let i = 0; i < rootLinks.length; i++) {
let pk = rootLinks[i].linkSrcTbl.columns.find(a => a.pk).title let pk = rootLinks[i].linkSrcTbl.columns.find(a => a.pk).title;
let moreRecords = true; let moreRecords = true;
let offset = 0, limit = 25; let offset = 0,
limit = 25;
while(moreRecords) {
let recList = await api.dbTableRow.list("nc", ncConfig.srcProject, rootLinks[i].linkSrcTbl.title, {}, { while (moreRecords) {
query: { limit: limit, offset: offset } let recList = await api.dbTableRow.list(
}) 'nc',
moreRecords = !recList.pageInfo.isLastPage ncConfig.srcProject,
offset += limit rootLinks[i].linkSrcTbl.title,
{},
{
query: { limit: limit, offset: offset }
}
);
moreRecords = !recList.pageInfo.isLastPage;
offset += limit;
for (let recCnt = 0; recCnt < recList.list.length; recCnt++) { for (let recCnt = 0; recCnt < recList.list.length; recCnt++) {
let record = await api.dbTableRow.read("nc", ncConfig.srcProject, rootLinks[i].linkSrcTbl.title, recList.list[recCnt][pk]) let record = await api.dbTableRow.read(
'nc',
ncConfig.srcProject,
rootLinks[i].linkSrcTbl.title,
recList.list[recCnt][pk]
);
let linkField = record[rootLinks[i].linkColumn.title]; let linkField = record[rootLinks[i].linkColumn.title];
if (linkField.length) { if (linkField.length) {
await api.dbTableRow.nestedAdd("nc", ncConfig.projectName, rootLinks[i].linkSrcTbl.title, await api.dbTableRow.nestedAdd(
'nc',
ncConfig.projectName,
rootLinks[i].linkSrcTbl.title,
record[pk], record[pk],
rootLinks[i].linkColumn.colOptions.type, rootLinks[i].linkColumn.colOptions.type,
encodeURIComponent(rootLinks[i].linkColumn.title), encodeURIComponent(rootLinks[i].linkColumn.title),
linkField[0][pk] linkField[0][pk]
) );
} }
} }
} }
} }
} }
async function importSchema() { async function importSchema() {
api = new Api(ncConfig); api = new Api(ncConfig);
const x = await api.project.list(); const x = await api.project.list();
const p = x.list.find(a => a.title === ncConfig.projectName); const p = x.list.find(a => a.title === ncConfig.projectName);
if (p) await api.project.delete(p.id); if (p) await api.project.delete(p.id);
ncProject = await api.project.create({ title: ncConfig.projectName }) ncProject = await api.project.create({ title: ncConfig.projectName });
await createBaseTables() await createBaseTables();
await createLinks() await createLinks();
await createLookup() await createLookup();
await createRollup() await createRollup();
await createFormula() await createFormula();
// configure views // configure views
await configureGrid() await configureGrid();
await configureGallery() await configureGallery();
await configureForm() await configureForm();
// restore data // restore data only if source project exists
await restoreBaseData() const p2 = x.list.find(a => a.title === ncConfig.srcProject);
await restoreLinks() if (p2 !== undefined) {
await restoreBaseData();
await restoreLinks();
}
} }
(async() => { (async () => {
await importSchema() await importSchema();
console.log('completed') console.log('completed');
})().catch(e => console.log(e)) })().catch(e => console.log(e));
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
Loading…
Cancel
Save