From 20f7d45e04bb7c7f2d08e086185bac98e7d3ebb4 Mon Sep 17 00:00:00 2001 From: Pranav C <61551451+pranavxc@users.noreply.github.com> Date: Wed, 4 Aug 2021 13:32:52 +0530 Subject: [PATCH] feat: Generate swagger json for relation and formula Signed-off-by: Pranav C <61551451+pranavxc@users.noreply.github.com> --- .../src/lib/noco/common/BaseApiBuilder.ts | 6 +- .../nocodb/src/lib/noco/gql/GqlApiBuilder.ts | 6 +- .../src/lib/noco/rest/RestApiBuilder.ts | 56 +++++++++++++++++-- .../sqlMgr/code/routers/xc-ts/SwaggerXc.ts | 31 +++++++--- 4 files changed, 80 insertions(+), 19 deletions(-) diff --git a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts index 365d49c3b1..90f9737405 100644 --- a/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts +++ b/packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts @@ -317,7 +317,7 @@ export default abstract class BaseApiBuilder implements XcDynami this.baseLog(`onValidationUpdate : '%s'`, tn); const modelRow = await this.xcMeta.metaGet(this.projectId, this.dbAlias, 'nc_models', { title: tn, - type:'table' + type: 'table' }); if (!modelRow) { @@ -1365,7 +1365,7 @@ export default abstract class BaseApiBuilder implements XcDynami } - protected async getManyToManyRelations({parent = null, child = null, localMetas = null} = {}) { + protected async getManyToManyRelations({parent = null, child = null, localMetas = null} = {}): Promise> { const metas = new Set(); const assocMetas = new Set(); @@ -1492,6 +1492,8 @@ export default abstract class BaseApiBuilder implements XcDynami this.models[meta.tn] = this.getBaseModel(meta) } } + + return metas; } diff --git a/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts b/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts index 3152497a6a..0e4dc208dc 100644 --- a/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts +++ b/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts @@ -1852,8 +1852,8 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { log(`${this.dbAlias} : ${str}`, ...args); } - public async onManyToManyRelationCreate(parent: string, child: string, args?: any) { - await super.onManyToManyRelationCreate(parent, child, args); + public async onManyToManyRelationCreate(parent: string, child: string, args?: any): Promise> { + const res = await super.onManyToManyRelationCreate(parent, child, args); for (const tn of [parent, child]) { const meta = this.metas[tn]; const {columns, hasMany, belongsTo, manyToMany} = meta; @@ -1900,7 +1900,7 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { }); await this.reInitializeGraphqlEndpoint(); - + return res; } public async onManyToManyRelationDelete(parent: string, child: string, args?: any) { diff --git a/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts b/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts index 22fc2d128d..5d2a47ffc1 100644 --- a/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts +++ b/packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts @@ -291,7 +291,7 @@ export class RestApiBuilder extends BaseApiBuilder { r._rtn = args?.tableNames?.find(t => t.tn === r.rtn)?._tn || this.getTableNameAlias(r.rtn); r._tn = args?.tableNames?.find(t => t.tn === r.tn)?._tn || this.getTableNameAlias(r.tn); r.enabled = true; - }) + }); this.relationsCount = relations.length; @@ -564,7 +564,6 @@ export class RestApiBuilder extends BaseApiBuilder { await NcHelp.executeOperations(relationRoutes, this.connectionConfig.client); - await this.getManyToManyRelations(); const swaggerDoc = { @@ -600,6 +599,8 @@ export class RestApiBuilder extends BaseApiBuilder { } + await this.getManyToManyRelations(); + } @@ -1052,7 +1053,7 @@ export class RestApiBuilder extends BaseApiBuilder { _cn: `${this.getTableNameAlias(tnp)} => ${this.getTableNameAlias(tnc)}` }) - swaggerArr.push(new SwaggerXc({ctx:{...ctx, v: oldMeta.v}}).getObject()); + swaggerArr.push(new SwaggerXc({ctx: {...ctx, v: oldMeta.v}}).getObject()); if (queryParams?.showFields) { @@ -1149,8 +1150,7 @@ export class RestApiBuilder extends BaseApiBuilder { _cn: `${this.getTableNameAlias(tnp)} <= ${this.getTableNameAlias(tnc)}` }) - swaggerArr.push(new SwaggerXc({ctx:{...ctx, v: oldMeta.v}}).getObject()); - + swaggerArr.push(new SwaggerXc({ctx: {...ctx, v: oldMeta.v}}).getObject()); if (queryParams?.showFields) { @@ -1798,6 +1798,52 @@ export class RestApiBuilder extends BaseApiBuilder { await this.onSwaggerDocUpdate(tn); } + + protected async getManyToManyRelations(args = {}): Promise> { + const metas:Set = await super.getManyToManyRelations(args); + + for (const metaObj of metas) { + + const ctx = this.generateContextForTable( + metaObj.tn, + metaObj.columns, + [...metaObj.belongsTo, ...metaObj.hasMany], + metaObj.hasMany, + metaObj.belongsTo + ); + + const swaggerDoc = await new SwaggerXc({ + dir: '', ctx: { + ...ctx, + v: metaObj.v + }, filename: '' + }).getObject(); + + const meta = await this.xcMeta.metaGet(this.projectId, this.dbAlias, 'nc_models', { + title: metaObj.tn, + type: 'table' + }); + const oldSwaggerDoc = JSON.parse(meta.schema); + + // keep upto 5 schema backup on table update + let previousSchemas = [oldSwaggerDoc] + if (meta.schema_previous) { + previousSchemas = [...JSON.parse(meta.schema_previous), oldSwaggerDoc].slice(-5); + } + + oldSwaggerDoc.definitions = swaggerDoc.definitions; + await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', { + schema: JSON.stringify(oldSwaggerDoc), + schema_previous: JSON.stringify(previousSchemas) + }, { + title: metaObj.tn, + type: 'table' + }); + } + + return metas + } + } diff --git a/packages/nocodb/src/lib/sqlMgr/code/routers/xc-ts/SwaggerXc.ts b/packages/nocodb/src/lib/sqlMgr/code/routers/xc-ts/SwaggerXc.ts index b80c3c833f..bc70c40554 100644 --- a/packages/nocodb/src/lib/sqlMgr/code/routers/xc-ts/SwaggerXc.ts +++ b/packages/nocodb/src/lib/sqlMgr/code/routers/xc-ts/SwaggerXc.ts @@ -63,11 +63,14 @@ class SwaggerXc extends BaseRender { [args._tn]: { type: 'object', properties: {} + }, + [`${args._tn}Nested`]: { + type: 'object', + properties: {} } - }; - const properties = obj[args._tn].properties; + let properties = obj[args._tn].properties; for (const column of args.columns) { const field: any = {}; @@ -85,6 +88,7 @@ class SwaggerXc extends BaseRender { properties[column._cn] = field; } + properties = Object.assign(obj[`${args._tn}Nested`].properties, properties) for (const column of (args.v || [])) { const field: any = {}; field.readOnly = true; @@ -99,13 +103,13 @@ class SwaggerXc extends BaseRender { } else if (column.hm) { field.type = 'array'; field.items = { - $ref: `#/definitions/${column.mm?._rtn}` + $ref: `#/definitions/${column.hm?._tn}` }; - field.$ref = `#/definitions/${column.mm?._rtn}` - _cn = `${column.mm?._rtn}List`; + field.$ref = `#/definitions/${column.hm?._tn}` + _cn = `${column.hm?._tn}List`; } else if (column.bt) { - field.$ref = `#/definitions/${column.mm?._tn}` - _cn = `${column.mm?._rtn}Read`; + field.$ref = `#/definitions/${column.bt?._rtn}` + _cn = `${column.bt?._rtn}Read`; } properties[_cn] = field; @@ -227,7 +231,16 @@ class SwaggerXc extends BaseRender { "responses": { "405": { "description": "Invalid input" - } + }, + "200": { + "description": "successful operation", + "schema": { + type: "array", + items: { + "$ref": `#/definitions/${this.ctx._tn}Nested` + } + } + }, } } }, @@ -273,7 +286,7 @@ class SwaggerXc extends BaseRender { "200": { "description": "successful operation", "schema": { - "$ref": `#/definitions/${this.ctx._tn}` + "$ref": `#/definitions/${this.ctx._tn}Nested` } }, "400": {