Browse Source

feat: project templates & template parser

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/760/head
Pranav C 3 years ago
parent
commit
252cb4dbbf
  1. 47
      packages/nc-gui/components/templates/categories.vue
  2. 59
      packages/nc-gui/components/templates/detailed.vue
  3. 1036
      packages/nc-gui/components/templates/editor.vue
  4. 93
      packages/nc-gui/components/templates/list.vue
  5. 81
      packages/nc-gui/components/templates/templates.1.js
  6. 62
      packages/nc-gui/components/templates/templates.2.js
  7. 62
      packages/nc-gui/components/templates/templates.3.js
  8. 62
      packages/nc-gui/components/templates/templates.4.js
  9. 62
      packages/nc-gui/components/templates/templates.5.js
  10. 26
      packages/nc-gui/components/templates/templates.categories.js
  11. 61
      packages/nc-gui/components/templates/templates.js
  12. 38
      packages/nc-gui/components/templates/templates.list.js
  13. 42
      packages/nc-gui/components/templates/templatesModal.vue
  14. 2
      packages/nc-gui/helpers/sqlUi/MysqlUi.js
  15. 5
      packages/nc-gui/layouts/default.vue
  16. 15
      packages/nc-gui/pages/project/templates/_id.vue
  17. 16
      packages/nc-gui/pages/project/templates/index.vue
  18. 84
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts
  19. 2
      packages/nocodb/src/lib/sqlUi/MysqlUi.ts
  20. 92
      packages/nocodb/src/lib/templateParser/NcTemplateParser.ts

47
packages/nc-gui/components/templates/categories.vue

@ -0,0 +1,47 @@
<template>
<v-list dense height="20px">
<v-list-item dense>
<v-list-item-subtitle>
<span class="caption">Categories</span>
</v-list-item-subtitle>
</v-list-item>
<v-list-item-group v-model="category">
<v-list-item v-for="c in categories" :key="c.title" :value="c.title" dense>
<v-list-item-title>
<span
:class="{'font-weight-black' : category === c.title } "
>
{{
c.title
}}<span />
</span>
</v-list-item-title>
</v-list-item>
</v-list-item-group>
</v-list>
</template>
<script>
import categories from './templates.categories'
export default {
name: "categories",
props:{value:String},
data:()=>({
categories
}),
computed:{
category:{
get(){
return this.value;
},
set(v){
this.$emit('input', v)
}
}
}
}
</script>
<style scoped>
</style>

59
packages/nc-gui/components/templates/detailed.vue

@ -0,0 +1,59 @@
<template>
<v-container class="py-0">
<div class="d-flex">
<v-navigation-drawer height="calc(100vh - 40px)">
<categories @input="v => $emit('load-category', v)"/>
</v-navigation-drawer>
<v-container v-if="templateData" fluid style="height: calc(100vh - 40px ); overflow: auto">
<v-img
:src="templateData.thumbnail"
height="200px"
/>
<div class="d-flex align-center mt-10">
<h2 class="display-2 font-weight-bold my-0 flex-grow-1">
{{ templateData.title }}
</h2>
<v-btn class="primary" x-large @click="useTemplate">Use template</v-btn>
</div>
<p class="caption mt-10">
{{ templateData.description }}
</p>
<templat-editor view-mode :templateData="templateData"></templat-editor>
</v-container>
</div>
</v-container>
</template>
<script>
import categories from '~/components/templates/templates.categories'
import TemplatEditor from "~/components/templates/editor";
import Categories from "~/components/templates/categories";
export default {
name: 'ProjectTemplateDetailed',
components: {Categories, TemplatEditor},
props: {
modal: Boolean, id: [String, Number]
},
data: () => ({categories, templateData: null}),
async mounted() {
this.templateData = (await import(`./templates.${this.modal ? this.id : this.$route.params.id}`)).default
}, methods: {
useTemplate() {
if (this.modal) {
this.$emit('import', this.templateData)
}
}
}
}
</script>
<style scoped>
/deep/ .v-list-item {
min-height: 30px;
}
</style>

1036
packages/nc-gui/components/templates/editor.vue

File diff suppressed because it is too large Load Diff

93
packages/nc-gui/components/templates/list.vue

@ -0,0 +1,93 @@
<template>
<v-container v-if="!modal || selectedId === null " class="py-0">
<div class="d-flex">
<v-navigation-drawer height="calc(100vh - 40px)">
<categories v-model="category"></categories>
</v-navigation-drawer>
<v-container fluid style="height: calc(100vh - 40px ); overflow: auto">
<v-row
v-if="templateList && templateList.length">
<v-col
v-for="(template,i) in templateList"
:key="i"
sm="8"
offset-sm="2"
offset-md="0"
md="6"
lg="4"
xl="3"
@click="openTemplate(template.id)"
>
<v-card
class="mx-auto"
>
<v-img
:src="template.thumbnail"
height="200px"
/>
<v-card-title>
{{ template.title }}
</v-card-title>
<v-card-subtitle>
<span class="caption">
{{ getShortDescription(template.description) }}
</span>
</v-card-subtitle>
</v-card>
</v-col>
</v-row>
<div v-else class="d-flex justify-center mt-10 ">
<v-alert class="flex-shrink-1" type="info" outlined dense >
No templates found
</v-alert>
</div>
</v-container>
</div>
</v-container>
<project-template-detailed v-else @load-category="v =>{ category = v; selectedId = null }" :id="selectedId" :modal="modal" v-on="$listeners" />
</template>
<script>
import templateList from './templates.list'
import ProjectTemplateDetailed from '~/components/templates/detailed'
import Categories from "~/components/templates/categories";
export default {
name: 'ProjectTemplates',
components: {Categories, ProjectTemplateDetailed },
props: {
modal: Boolean
},
data: () => ({
category: null,
selectedId: null
}),
computed: {
templateList() {
return templateList.filter(t => !this.category || t.category === this.category)
}
},
methods: {
getShortDescription(str) {
if (str.length < 200) { return str }
return `${str.slice(0, 200)}...`
},
openTemplate(id) {
if (this.modal) {
this.selectedId = id
} else {
this.$router.push(`/project/templates/${id}`)
}
}
}
}
</script>
<style scoped>
/deep/ .v-list-item{
min-height: 30px;
}
</style>

81
packages/nc-gui/components/templates/templates.1.js

@ -0,0 +1,81 @@
const templates = {
title: 'Art Gallery Management',
thumbnail: 'https://picsum.photos/200/300?1',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: [
{
_cn: 'comments_count',
rl: {
rltn: 'comment',
rlcn: 'body',
type: 'hm',
fn: 'count'
}
}
]
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: [
{
_cn: 'blog_title',
lk: {
ltn: 'blog',
type: 'bt',
lcn: 'title'
}
}
]
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

62
packages/nc-gui/components/templates/templates.2.js

@ -0,0 +1,62 @@
const templates = {
title: 'Digital video production',
thumbnail: 'https://picsum.photos/200/300?2',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: []
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: []
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

62
packages/nc-gui/components/templates/templates.3.js

@ -0,0 +1,62 @@
const templates = {
title: 'Content calendar',
thumbnail: 'https://picsum.photos/200/300?3',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: []
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: []
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

62
packages/nc-gui/components/templates/templates.4.js

@ -0,0 +1,62 @@
const templates = {
title: 'Event Marketing',
thumbnail: 'https://picsum.photos/200/300?3',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: []
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: []
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

62
packages/nc-gui/components/templates/templates.5.js

@ -0,0 +1,62 @@
const templates = {
title: 'Wedding Planning',
thumbnail: 'https://picsum.photos/200/300?5',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: []
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: []
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

26
packages/nc-gui/components/templates/templates.categories.js

@ -0,0 +1,26 @@
const categories = [
{ title: 'Content production' },
{ title: 'Featured' },
{ title: 'Creative' },
{ title: 'Event Planning' },
{ title: 'Everyday Life' },
{ title: 'Groups, Clubs & Hobbies' },
{ title: 'HR & Recruiting' },
{ title: 'Legal' },
{ title: 'Local Business' },
{ title: 'Marketing' },
{ title: 'Nonprofit' },
{ title: 'Personal' },
{ title: 'PR & Communications' },
{ title: 'Product, design, and UX' },
{ title: 'Project Management' },
{ title: 'Publishing' },
{ title: 'Real Estate' },
{ title: 'Remote work' },
{ title: 'Sales & Customers' },
{ title: 'Software Development' },
{ title: 'Startup' },
{ title: 'Venture Capital' }
]
export default categories

61
packages/nc-gui/components/templates/templates.js

@ -0,0 +1,61 @@
const templates = {
title: 'Project name',
tables: [
{
tn: 'blog',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
},
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [
{
tn: 'comment',
_cn: 'title3'
}
],
manyToMany: [
{
rtn: 'tag',
_cn: 'title4'
}
],
v: []
},
{
tn: 'comment',
columns: [
{
cn: 'body',
uidt: 'LongText'
}
],
hasMany: [],
manyToMany: [],
v: []
},
{
tn: 'tag',
columns: [
{
cn: 'title',
uidt: 'SingleLineText'
}
],
hasMany: [],
manyToMany: [],
v: []
}
],
category: 'test',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}
export default templates

38
packages/nc-gui/components/templates/templates.list.js

@ -0,0 +1,38 @@
const templatesList = [{
id: 1,
title: 'Art Gallery Management',
category: 'Creative',
thumbnail: 'https://picsum.photos/200/300?1',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}, {
id: 2,
title: 'Digital video production',
category: 'Creative',
thumbnail: 'https://picsum.photos/200/300?2',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}, {
id: 3,
title: 'Content calendar',
category: 'Creative',
thumbnail: 'https://picsum.photos/200/300?3',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}, {
id: 4,
title: 'Event Marketing',
category: 'Event Planning',
thumbnail: 'https://picsum.photos/200/300?4',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}, {
id: 5,
title: 'Wedding Planning',
category: 'Event Planning',
thumbnail: 'https://picsum.photos/200/300?5',
tags: 'a,b,c',
description: 'I\'m a thing. But, like most politicians, he promised more than he could deliver. You won\'t have time for sleeping, soldier, not with all the bed making you\'ll be doing. Then we\'ll go with that data file! Hey, you add a one and two zeros to that or we walk!'
}]
export default templatesList

42
packages/nc-gui/components/templates/templatesModal.vue

@ -0,0 +1,42 @@
<template>
<div>
<span class="caption font-weight-bold" @click="templatesModal = true">Templates</span>
<v-dialog v-model="templatesModal" v-if="templatesModal">
<v-card>
<project-templates modal @import="importTemplate" />
</v-card>
</v-dialog>
</div>
</template>
<script>
import ProjectTemplates from '~/components/templates/list'
export default {
name: 'TemplatesModal',
components: { ProjectTemplates },
data: () => ({
templatesModal: false
}),
methods: {
importTemplate(template) {
try {
this.$store.dispatch('sqlMgr/ActSqlOp', [{
// todo: extract based on active
dbAlias: 'db', // this.nodes.dbAlias,
env: '_noco'
}, 'xcModelsCreateFromTemplate', {
template
}])
this.$toast.success('Template imported successfully').goAway(3000);
this.templatesModal = false;
} catch (e) {
this.$toast.error(e.message).goAway(3000)
}
}
}
}
</script>
<style scoped>
</style>

2
packages/nc-gui/helpers/sqlUi/MysqlUi.js

@ -212,7 +212,7 @@ export class MysqlUi {
return 255
case 'varchar':
return 45
return 255
case 'nchar':
return 255

5
packages/nc-gui/layouts/default.vue

@ -43,7 +43,8 @@
>
{{ ghStarText }}
</gh-btns-star>
<a class="caption font-weight-bold ml-1 mr-2 white--text" href="https://docs.nocodb.com" target="_blank">Docs</a>
<a class="align-self-center caption font-weight-bold ml-1 mr-2 white--text" href="https://docs.nocodb.com" target="_blank">Docs</a>
<templates-modal class="align-self-center" />
</v-toolbar-items>
<!-- <template v-if="!isThisMobile ">
@ -574,9 +575,11 @@ import xTerm from '../components/xTerm'
import { copyTextToClipboard } from '@/helpers/xutils'
import Snackbar from '~/components/snackbar'
import Language from '~/components/utils/language'
import TemplatesModal from '~/components/templates/templatesModal'
export default {
components: {
TemplatesModal,
ReleaseInfo,
Language,
ChangeEnv,

15
packages/nc-gui/pages/project/templates/_id.vue

@ -0,0 +1,15 @@
<template>
<project-template />
</template>
<script>
import ProjectTemplate from '~/components/templates/detailed'
export default {
name: '_id.vue',
components: { ProjectTemplate }
}
</script>
<style scoped>
</style>

16
packages/nc-gui/pages/project/templates/index.vue

@ -0,0 +1,16 @@
<template>
<project-templates />
</template>
<script>
import ProjectTemplates from '~/components/templates/list'
export default {
components: {
ProjectTemplates
}
}
</script>
<style scoped>
</style>

84
packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

@ -2271,7 +2271,7 @@ export default class NcMetaMgr {
// NOTE: updated
protected async xcModelSet(args): Promise<any> {
const dbAlias = await this.getDbAlias(args);
this.cacheModelDel(args.project_id, dbAlias, 'table', args.args.tn);
this.cacheModelDel(this.getProjectId(args), dbAlias, 'table', args.args.tn);
return this.xcMeta.metaUpdate(
args.project_id,
dbAlias,
@ -4075,9 +4075,15 @@ export default class NcMetaMgr {
d => d?.meta?.dbAlias === dbAlias
);
const apiBuilder = this.app?.projectBuilders
?.find(pb => pb.id === projectId)
?.apiBuilders?.find(ab => ab.dbAlias === dbAlias);
const parser = new NcTemplateParser({
client: connectionConfig?.client,
template
template,
prefix: projectConfig?.prefix
});
parser.parse();
@ -4111,7 +4117,7 @@ export default class NcMetaMgr {
// create relations
for (const relation of parser.relations) {
// if (args.args.type === 'real') {
if (relation.type === 'real') {
const outrel = await this.projectMgr
.getSqlMgr({ id: projectId })
.handleRequest('relationCreate', {
@ -4132,27 +4138,27 @@ export default class NcMetaMgr {
}
});
}
// } else {
// const outrel = await this.xcVirtualRelationCreate(
// {...args, args: rel1Args},
// req
// );
// if (this.listener) {
// await this.listener({
// req: {
// ...args,
// args: rel1Args,
// api: 'xcVirtualRelationCreate'
// },
// res: outrel,
// user: req.user,
// ctx: {
// req
// }
// });
// }
} else {
const outrel = await this.xcVirtualRelationCreate(
{...args, args: relation},
req
);
if (this.listener) {
await this.listener({
req: {
...args,
args: relation,
api: 'xcVirtualRelationCreate'
},
res: outrel,
user: req.user,
ctx: {
req
}
});
}
// }
}
}
//create m2m relations
@ -4181,6 +4187,38 @@ export default class NcMetaMgr {
});
}
}
// add virtual columns
for(const [tn, vColumns] of Object.entries(parser.virtualColumns)){
const meta = apiBuilder.getMeta(tn);
meta.v = meta.v || [];
meta.v.push(...vColumns)
const res = await this.xcModelSet({
...args,
args: {
meta,
tn
}
})
await this.listener({
req: {
...args,
args:{
meta,
tn
},
api: 'xcM2MRelationCreate'
},
res,
user: req.user,
ctx: {
req
}
});
}
}
protected async xcExportAsCsv(args, _req, res: express.Response) {

2
packages/nocodb/src/lib/sqlUi/MysqlUi.ts

@ -212,7 +212,7 @@ export class MysqlUi {
return 255;
case 'varchar':
return 45;
return 255;
case 'nchar':
return 255;

92
packages/nocodb/src/lib/templateParser/NcTemplateParser.ts

@ -17,27 +17,39 @@ export default class NcTemplateParser {
| typeof SqliteUi;
private _tables: any[];
private client: string;
private _relations: any[];
private _m2mRelations: any[];
private _virtualColumns: { [tn: string]: any[] };
private prefix: string;
private template: any;
constructor({ client, template }) {
this.sqlUi = SqlUiFactory.create({ client });
constructor({client, template, prefix = ''}) {
this.client = client;
this.sqlUi = SqlUiFactory.create({client});
this.template = template;
this.prefix = prefix
}
public parse(template?: any): any {
const tables = [];
this.template = template || this.template;
for (const tableTemplate of this.template.tables) {
const table = this.extractTable(tableTemplate);
const tableTemplates = this.template.tables.map(tableTemplate => {
const t = {
...tableTemplate,
tn: this.getTable(tableTemplate.tn),
_tn: tableTemplate._tn || tableTemplate.tn
}
const table = this.extractTable(t);
tables.push(table);
}
return t
})
this._tables = tables;
for (const tableTemplate of this.template.tables) {
for (const tableTemplate of tableTemplates) {
this.extractRelations(tableTemplate);
this.extractVirtualColumns(tableTemplate);
}
}
@ -57,9 +69,11 @@ export default class NcTemplateParser {
return {
tn: tableTemplate.tn,
_tn: tableTemplate._tn,
columns: [
...defaultColumns,
...this.extractTableColumns(tableTemplate.columns)
defaultColumns[0],
...this.extractTableColumns(tableTemplate.columns),
...defaultColumns.slice(1),
]
};
}
@ -81,12 +95,21 @@ export default class NcTemplateParser {
// // this.extractRelations(tableColumn, 'mm');
// break;
default:
const colProp = this.sqlUi.getDataTypeForUiType(tableColumn);
columns.push({
...this.sqlUi.getNewColumn(''),
rqd: false,
pk: false,
ai: false,
cdf: null,
un: false,
dtx: 'specificType',
dtxp: this.sqlUi.getDefaultLengthForDatatype(colProp.dt),
dtxs: this.sqlUi.getDefaultScaleForDatatype(colProp.dt),
cn: tableColumn.cn,
_cn: tableColumn.cn,
uidt: tableColumn.uidt,
...this.sqlUi.getDataTypeForUiType(tableColumn)
...colProp
});
break;
}
@ -98,11 +121,11 @@ export default class NcTemplateParser {
if (!this._relations) this._relations = [];
if (!this._m2mRelations) this._m2mRelations = [];
for (const hasMany of tableTemplate.hasMany || []) {
const childTable = this.tables.find(table => table.tn === hasMany.tn);
const partentTable = this.tables.find(
const childTable = this.tables.find(table => table.tn === this.getTable(hasMany.tn));
const parentTable = this.tables.find(
table => table.tn === tableTemplate.tn
);
const parentPrimaryColumn = partentTable.columns.find(
const parentPrimaryColumn = parentTable.columns.find(
column => column.uidt === UITypes.ID
);
@ -126,18 +149,18 @@ export default class NcTemplateParser {
// add relation create entry
this._relations.push({
childColumn: childColumnName,
childTable: hasMany.tn,
childTable: childTable.tn,
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
parentColumn: parentPrimaryColumn.cn,
parentTable: tableTemplate.tn,
type: 'real',
type: this.client === 'sqlite3' ? 'virtual' : 'real',
updateRelation: false
});
}
for (const manyToMany of tableTemplate.manyToMany || []) {
// @ts-ignore
const childTable = this.tables.find(table => table.tn === manyToMany.rtn);
const childTable = this.tables.find(table => table.tn === this.getTable(manyToMany.rtn));
const parentTable = this.tables.find(
table => table.tn === tableTemplate.tn
);
@ -157,12 +180,40 @@ export default class NcTemplateParser {
onUpdate: 'NO ACTION',
parentColumn: parentPrimaryColumn.cn,
parentTable: parentTable.tn,
type: 'real',
type: this.client === 'sqlite3' ? 'virtual' : 'real',
updateRelation: false
});
}
}
private extractVirtualColumns(tableMeta) {
if (!this._virtualColumns) this._virtualColumns = {};
const virtualColumns = [];
for (const v of (tableMeta.v || [])) {
const v1 = {...v}
let type, prop;
switch (v.uidt) {
case UITypes.Rollup:
type = v.rl.type
prop = 'rl'
break;
case UITypes.Lookup:
type = v.lk.type
prop = 'lk'
break;
}
if (type && prop) {
// todo: extract relation data
} else {
virtualColumns.push(v1)
}
}
this.virtualColumns[tableMeta.tn] = virtualColumns;
}
get tables(): any[] {
return this._tables;
}
@ -170,7 +221,16 @@ export default class NcTemplateParser {
get relations(): any[] {
return this._relations;
}
get m2mRelations(): any[] {
return this._m2mRelations;
}
get virtualColumns(): { [tn: string]: any[] } {
return this._virtualColumns;
}
private getTable(tn) {
return `${this.prefix}${tn}`
}
}

Loading…
Cancel
Save