Browse Source

chore: remove unused code base (#8676)

* fix: remove unused code base

* fix: enable cleanup

* fix: use global variable instead of static
nc-oss/f4dcddf8
Mert E 6 months ago committed by GitHub
parent
commit
38e46dd306
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2637
      packages/nocodb/src/db/BaseModelSql.ts
  2. 4
      packages/nocodb/src/db/CustomKnex.ts
  3. 228
      packages/nocodb/src/db/sql-mgr/code/gql-policies/xc-ts/ExpressXcTsPolicyGql.ts
  4. 224
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/BaseGqlXcTsSchema.ts
  5. 28
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory.ts
  6. 245
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaMssql.ts
  7. 269
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaMysql.ts
  8. 253
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaOracle.ts
  9. 325
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaPg.ts
  10. 231
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaSqlite.ts
  11. 13
      packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/schemaHelp.ts
  12. 788
      packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXc.ts
  13. 119
      packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXcBt.ts
  14. 484
      packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXcHm.ts
  15. 367
      packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes.ts
  16. 61
      packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutesBt.ts
  17. 239
      packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutesHm.ts
  18. 1706
      packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts
  19. 37
      packages/nocodb/src/db/sql-migrator/lib/SqlMigrator.ts
  20. 19
      packages/nocodb/src/db/sql-migrator/lib/SqlMigratorFactory.ts
  21. 9
      packages/nocodb/src/meta/meta.service.ts
  22. 2
      packages/nocodb/src/meta/migrations/XcMigrationSource.ts
  23. 38
      packages/nocodb/src/providers/init-meta-service.provider.ts
  24. 171
      packages/nocodb/src/utils/common/NcConnectionMgr.ts
  25. 2
      packages/nocodb/src/utils/getInstance.ts
  26. 24
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  27. 14
      packages/nocodb/src/version-upgrader/ncDataTypesUpgrader.ts
  28. 18
      packages/nocodb/src/version-upgrader/ncProjectEnvUpgrader.ts
  29. 11
      packages/nocodb/src/version-upgrader/ncProjectEnvUpgrader0011045.ts
  30. 47
      packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts
  31. 1329
      packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts
  32. 612
      packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts
  33. 198
      packages/nocodb/src/version-upgrader/v1-legacy/NcProjectBuilder.ts
  34. 145
      packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts
  35. 38
      packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts
  36. 24
      packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts
  37. 112
      packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts
  38. 176
      packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts
  39. 253
      packages/nocodb/src/version-upgrader/v1-legacy/templates/NcTemplateParser.ts

2637
packages/nocodb/src/db/BaseModelSql.ts

File diff suppressed because it is too large Load Diff

4
packages/nocodb/src/db/CustomKnex.ts

@ -2,7 +2,7 @@ import { Knex, knex } from 'knex';
import { defaults, types } from 'pg';
import dayjs from 'dayjs';
import type { FilterType } from 'nocodb-sdk';
import type { BaseModelSql } from '~/db/BaseModelSql';
import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2';
import Filter from '~/models/Filter';
import { NcError } from '~/helpers/catchError';
@ -548,7 +548,7 @@ declare module 'knex' {
conditionGraph<TRecord, TResult>(condition: {
condition: Condition;
models: { [key: string]: BaseModelSql };
models: { [key: string]: BaseModelSqlv2 };
}): Knex.QueryBuilder<TRecord, TResult>;
xhaving<TRecord, TResult>(

228
packages/nocodb/src/db/sql-mgr/code/gql-policies/xc-ts/ExpressXcTsPolicyGql.ts

@ -1,228 +0,0 @@
import BaseRender from '../../BaseRender';
class ExpressXcPolicyGql extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ctx
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir = '', filename = '', ctx }) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare(): any {
let data = {};
/* run of simple variable */
data = this.ctx;
return data;
}
getObject() {
return {
[`${this.ctx.tn_camelize}List`]: { admin: true, user: true, guest: true },
[`${this.ctx.tn_camelize}Read`]: { admin: true, user: true, guest: true },
[`${this.ctx.tn_camelize}Create`]: {
admin: true,
user: true,
guest: false,
},
[`${this.ctx.tn_camelize}Update`]: {
admin: true,
user: true,
guest: false,
},
[`${this.ctx.tn_camelize}Delete`]: {
admin: true,
user: true,
guest: false,
},
[`${this.ctx.tn_camelize}Exists`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}FindOne`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}Count`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}Distinct`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}GroupBy`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}Aggregate`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}Distribution`]: {
admin: true,
user: true,
guest: true,
},
[`${this.ctx.tn_camelize}CreateBulk`]: {
admin: true,
user: true,
guest: false,
},
[`${this.ctx.tn_camelize}UpdateBulk`]: {
admin: true,
user: true,
guest: false,
},
[`${this.ctx.tn_camelize}DeleteBulk`]: {
admin: true,
user: true,
guest: false,
},
};
}
getFunctions() {
return {
[`${this.ctx.tn_camelize}List`]: [
`
async function(args, {req,res,next}){
return (await req.model.list(args)).map(o => {
return new req.gqlType(o);
});
}
`,
],
[`${this.ctx.tn_camelize}Read`]: [
`
async function(args, {req,res,next}){
const data = await req.model.readByPk(args.id);
return new req.gqlType(data);
}
`,
],
[`${this.ctx.tn_camelize}Create`]: [
`
async function(args, {req,res,next}){
const data = await req.model.insert(args.data);
return new req.gqlType(data);
}
`,
],
[`${this.ctx.tn_camelize}Update`]: [
`
async function(args, {req,res,next}){
const data = await req.model.updateByPk(args.id, args.data);
return data;
}
`,
],
[`${this.ctx.tn_camelize}Delete`]: [
`
async function(args, {req,res,next}){
const data = await req.model.delByPk(args.id);
return data;
}
`,
],
[`${this.ctx.tn_camelize}Exists`]: [
`
async function(args, {req,res,next}){
const data = await req.model.exists(args.id);
return data;
}
`,
],
[`${this.ctx.tn_camelize}FindOne`]: [
`
async function(args, {req,res,next}){
const data = await req.model.findOne(args);
return new req.gqlType(data);
}
`,
],
[`${this.ctx.tn_camelize}Count`]: [
`
async function(args, {req,res,next}){
const data = await req.model.countByPk(args);
return data.count;
}
`,
],
[`${this.ctx.tn_camelize}Distinct`]: [
`
async function(args, {req,res,next}){
const data = (await req.model.distinct(args)).map(d => new req.gqlType(d));
return data;
}
`,
],
[`${this.ctx.tn_camelize}GroupBy`]: [
`
async function(args, {req,res,next}){
const data = await req.model.groupBy(args);
return data;
}
`,
],
[`${this.ctx.tn_camelize}Aggregate`]: [
`
async function(args, {req,res,next}){
const data = await req.model.aggregate(args);
return data;
}
`,
],
[`${this.ctx.tn_camelize}Distribution`]: [
`
async function(args, {req,res,next}){
const data = await req.model.distribution(args);
return data;
}
`,
],
[`${this.ctx.tn_camelize}CreateBulk`]: [
`
async function(args, {req,res,next}){
const data = await req.model.insertb(args.data);
return data;
}
`,
],
[`${this.ctx.tn_camelize}UpdateBulk`]: [
`
async function(args, {req,res,next}){
const data = await req.model.updateb(args.data);
return data;
}
`,
],
[`${this.ctx.tn_camelize}DeleteBulk`]: [
`
async function(args, {req,res,next}){
const data = await req.model.delb(args.data);
return data;
}
`,
],
};
}
}
export default ExpressXcPolicyGql;

224
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/BaseGqlXcTsSchema.ts

@ -1,224 +0,0 @@
import uniqBy from 'lodash/uniqBy';
import BaseRender from '../../BaseRender';
import { AGG_DEFAULT_COLS, GROUPBY_DEFAULT_COLS } from './schemaHelp';
abstract class BaseGqlXcTsSchema extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
protected constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
public prepare(): any {
const data: any = {};
data.columns = {
func: this._renderColumns.bind(this),
args: this.ctx,
};
return data;
}
/**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*/
public _renderColumns(args): string {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`;
str += '';
return str;
}
public getString(): string {
return this._renderColumns(this.ctx);
}
protected generateManyToManyTypeProps(args: any): string {
if (!args.manyToMany?.length) {
return '';
}
let str = '\r\n';
for (const mm of args.manyToMany) {
str += `\t\t${mm._rtn}MMList(where: String,limit: Int, offset: Int, sort: String): [${mm._rtn}]\r\n`;
}
return str;
}
protected generateVirtualTypes(args: any): string {
if (!args.v?.length) {
return '';
}
const props = [];
for (const v of args.v) {
if (!v.formula && !v.rl) continue;
props.push(`\t\t${v._cn}: JSON`);
}
return props.length ? `\r\n${props.join('\r\n')}\r\n` : '';
}
protected _getInputType(args): string {
let str = `input ${args._tn}Input { \r\n`;
for (const column of args.columns) {
if (/\s/.test(column._cn)) {
console.log(`Skipping ${args.tn}.${column._cn}`);
} else {
str += `\t\t${column._cn}: ${this._getGraphqlType(column)},\r\n`;
}
}
str += `\t}`;
return str;
}
protected _getQuery(args): string {
let str = `type Query { \r\n`;
str += `\t\t${args._tn}List(where: String,condition:Condition${args._tn}, limit: Int, offset: Int, sort: String,conditionGraph: String): [${args._tn}]\r\n`;
str += `\t\t${args._tn}Read(id:String!): ${args._tn}\r\n`;
str += `\t\t${args._tn}Exists(id: String!): Boolean\r\n`;
str += `\t\t${args._tn}FindOne(where: String,condition:Condition${args._tn}): ${args._tn}\r\n`;
str += `\t\t${args._tn}Count(where: String,condition:Condition${args._tn},conditionGraph: String): Int\r\n`;
str += `\t\t${args._tn}Distinct(column_name: String, where: String,condition:Condition${args._tn}, limit: Int, offset: Int, sort: String): [${args._tn}]\r\n`;
str += `\t\t${args._tn}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args._tn}GroupBy]\r\n`;
str += `\t\t${args._tn}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args._tn}Aggregate]\r\n`;
str += `\t\t${args._tn}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`;
str += `\t}\r\n`;
return str;
}
protected _getMutation(args): string {
let str = `type Mutation { \r\n`;
str += `\t\t${args._tn}Create(data:${args._tn}Input): ${args._tn}\r\n`;
str += `\t\t${args._tn}Update(id:String,data:${args._tn}Input): ${args._tn}\r\n`; // ${args._tn}\r\n`
str += `\t\t${args._tn}Delete(id:String): Int\r\n`; // ${args._tn}\r\n`
str += `\t\t${args._tn}CreateBulk(data: [${args._tn}Input]): [Int]\r\n`;
str += `\t\t${args._tn}UpdateBulk(data: [${args._tn}Input]): [Int]\r\n`;
str += `\t\t${args._tn}DeleteBulk(data: [${args._tn}Input]): [Int]\r\n`;
str += `\t},\r\n`;
return str;
}
protected _getType(args): string {
let str = `type ${args._tn} { \r\n`;
let strWhere = `input Condition${args._tn} { \r\n`;
for (const column of args.columns) {
if (column._cn.split(' ').length > 1) {
console.log(`Skipping ${args.tn}.${column._cn}`);
} else {
str += `\t\t${column._cn.replace(/ /g, '_')}: ${this._getGraphqlType(
column,
)},\r\n`;
strWhere += `\t\t${column._cn.replace(
/ /g,
'_',
)}: ${this._getGraphqlConditionType(column)},\r\n`;
}
}
let hasManyRelations = args.hasMany;
if (hasManyRelations.length > 1) {
hasManyRelations = uniqBy(hasManyRelations, (e) => {
return [e.tn, e.rtn].join();
});
}
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (const { _tn } of hasManyRelations) {
const childTable = _tn;
str += `\t\t${childTable}List(where: String,limit: Int, offset: Int, sort: String): [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str += this.generateManyToManyTypeProps(args);
str += this.generateVirtualTypes(args);
let belongsToRelations = args.belongsTo;
if (belongsToRelations.length > 1) {
belongsToRelations = uniqBy(belongsToRelations, (e) => {
return [e.tn, e.rtn].join();
});
}
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (const { _rtn } of belongsToRelations) {
const parentTable = _rtn;
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`;
const grpFields = { ...GROUPBY_DEFAULT_COLS };
str += `type ${args._tn}GroupBy { \r\n`;
for (const { _cn, ...rest } of args.columns) {
if (_cn in grpFields) {
grpFields[_cn] = `\t\t# ${_cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${_cn.replace(/ /g, '_')}: ${this._getGraphqlType(
rest,
)},\r\n`;
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`;
const aggFields = { ...AGG_DEFAULT_COLS };
str += `type ${args._tn}Aggregate { \r\n`;
for (const column of args.columns) {
if (column._cn in aggFields) {
aggFields[
column._cn
] = `\t\t# ${column._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${column._cn.replace(/ /g, '_')}: ${this._getGraphqlType(
column,
)},\r\n`;
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`;
strWhere += `
_or:[Condition${args._tn}]
_not:Condition${args._tn}
_and:[Condition${args._tn}]
\t}\r\n`;
return `${str}\r\n\r\n${strWhere}`;
}
protected abstract _getGraphqlType(column: any): string;
protected abstract _getGraphqlConditionType(columnObj): string;
}
export default BaseGqlXcTsSchema;

28
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory.ts

@ -1,28 +0,0 @@
import GqlXcSchemaMssql from './GqlXcTsSchemaMssql';
import GqlXcTsSchemaMysql from './GqlXcTsSchemaMysql';
import GqlXcSchemaOracle from './GqlXcTsSchemaOracle';
import GqlXcSchemaPg from './GqlXcTsSchemaPg';
import GqlXcSchemaSqlite from './GqlXcTsSchemaSqlite';
class GqlXcSchemaFactory {
public static create(connectionConfig, args): any {
if (
connectionConfig.client === 'mysql2' ||
connectionConfig.client === 'mysql'
) {
return new GqlXcTsSchemaMysql(args);
} else if (connectionConfig.client === 'sqlite3') {
return new GqlXcSchemaSqlite(args);
} else if (connectionConfig.client === 'mssql') {
return new GqlXcSchemaMssql(args);
} else if (connectionConfig.client === 'pg') {
return new GqlXcSchemaPg(args);
} else if (connectionConfig.client === 'oracledb') {
return new GqlXcSchemaOracle(args);
}
throw new Error('Database not supported');
}
}
export default GqlXcSchemaFactory;

245
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaMssql.ts

@ -1,245 +0,0 @@
import BaseGqlXcTsSchema from './BaseGqlXcTsSchema';
class GqlXcTsSchemaMssql extends BaseGqlXcTsSchema {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/*
/!**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*!/
_renderColumns(args) {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`
str += '';
return str;
}
_getInputType(args) {
let str = `input ${args.tn_camelize}Input { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += `\t}`;
return str;
}
_getQuery(args) {
let str = `type Query { \r\n`
str += `\t\t${args.tn_camelize}List(where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}Read(id:String!): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Exists(id: String!): Boolean\r\n`
str += `\t\t${args.tn_camelize}FindOne(where: String,condition:Condition${args.tn_camelize}): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Count(where: String,condition:Condition${args.tn_camelize}): Int\r\n`
str += `\t\t${args.tn_camelize}Distinct(column_name: String, where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args.tn_camelize}GroupBy]\r\n`
str += `\t\t${args.tn_camelize}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args.tn_camelize}Aggregate]\r\n`
str += `\t\t${args.tn_camelize}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`
str += `\t}\r\n`
return str;
}
_getMutation(args) {
let str = `type Mutation { \r\n`
str += `\t\t${args.tn_camelize}Create(data:${args.tn_camelize}Input): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Update(id:String,data:${args.tn_camelize}Input): Int\r\n` //${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Delete(id:String): Int\r\n`//${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}CreateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}UpdateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}DeleteBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t},\r\n`
return str;
}
_getType(args) {
let str = `type ${args.tn_camelize} { \r\n`
let strWhere = `input Condition${args.tn_camelize} { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
strWhere += `\t\t${args.columns[i]._cn}: ${this._getGraphqlConditionType(args.columns[i])},\r\n`;
}
let hasManyRelations = args.relations.filter(r => r.rtn === args.tn);
if (hasManyRelations.length > 1)
hasManyRelations = lodash.uniqBy(hasManyRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (let i = 0; i < hasManyRelations.length; ++i) {
let childTable = inflection.camelize(hasManyRelations[i]._tn)
str += `\t\t${childTable}List: [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str += this.generateManyToManyTypeProps(args);
let belongsToRelations = args.relations.filter(r => r.tn === args.tn);
if (belongsToRelations.length > 1)
belongsToRelations = lodash.uniqBy(belongsToRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (let i = 0; i < belongsToRelations.length; ++i) {
let parentTable = inflection.camelize(belongsToRelations[i]._rtn)
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`
const grpFields = Object.assign({}, GROUPBY_DEFAULT_COLS);
str += `type ${args.tn_camelize}GroupBy { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in grpFields) {
grpFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`
const aggFields = Object.assign({}, AGG_DEFAULT_COLS);
str += `type ${args.tn_camelize}Aggregate { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in aggFields) {
aggFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`
strWhere += `
_or:[Condition${args.tn_camelize}]
_not:Condition${args.tn_camelize}
_and:[Condition${args.tn_camelize}]
\t}\r\n`
return `${str}\r\n\r\n${strWhere}`;
}
*/
_getGraphqlType(columnObj): any {
switch (columnObj.dt) {
case 'smallint':
case 'int':
case 'tinyint':
case 'bigint':
return 'Int';
break;
case 'numeric':
case 'money':
case 'real':
case 'decimal':
case 'float':
return 'Float';
break;
case 'binary':
case 'bit':
return 'Boolean';
break;
case 'char':
case 'date':
case 'datetime':
case 'datetime2':
case 'datetimeoffset':
case 'heirarchyid':
case 'image':
case 'nchar':
case 'ntext':
case 'nvarchar':
case 'smalldatetime':
case 'smallmoney':
case 'sql_variant':
case 'sysname':
case 'text':
case 'time':
case 'timestamp':
case 'uniqueidentifier':
case 'varbinary':
case 'xml':
case 'varchar':
default:
return 'String';
break;
case 'geography':
case 'geometry':
case 'json':
return 'JSON';
}
}
_getGraphqlConditionType(columnObj): any {
switch (this._getGraphqlType(columnObj.dt)) {
case 'Int':
return 'ConditionInt';
case 'Float':
return 'ConditionFloat';
case 'Boolean':
return 'ConditionBoolean';
case 'String':
return 'ConditionString';
case '[String]':
return 'ConditionString';
case 'JSON':
return 'ConditionString';
}
}
/* getString() {
return this._renderColumns(this.ctx);
}*/
}
export default GqlXcTsSchemaMssql;

269
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaMysql.ts

@ -1,269 +0,0 @@
import BaseGqlXcTsSchema from './BaseGqlXcTsSchema';
class GqlXcTsSchemaMysql extends BaseGqlXcTsSchema {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/*/!**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*!/
_renderColumns(args) {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`
str += '';
return str;
}
_getInputType(args) {
let str = `input ${args.tn_camelize}Input { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += `\t}`;
return str;
}
_getQuery(args) {
let str = `type Query { \r\n`
str += `\t\t${args.tn_camelize}List(where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String, conditionGraph: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}Read(id:String!): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Exists(id: String!): Boolean\r\n`
str += `\t\t${args.tn_camelize}FindOne(where: String!,condition:Condition${args.tn_camelize}): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Count(where: String!,condition:Condition${args.tn_camelize},conditionGraph: String): Int\r\n`
str += `\t\t${args.tn_camelize}Distinct(column_name: String, where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args.tn_camelize}GroupBy]\r\n`
str += `\t\t${args.tn_camelize}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args.tn_camelize}Aggregate]\r\n`
str += `\t\t${args.tn_camelize}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`
str += `\t}\r\n`
return str;
}
_getMutation(args) {
if (args.type === 'view') return '';
let str = `type Mutation { \r\n`
str += `\t\t${args.tn_camelize}Create(data:${args.tn_camelize}Input): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Update(id:String,data:${args.tn_camelize}Input): Int\r\n` //${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Delete(id:String): Int\r\n`//${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}CreateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}UpdateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}DeleteBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t},\r\n`
return str;
}
_getType(args) {
let str = `type ${args.tn_camelize} { \r\n`
let strWhere = `input Condition${args.tn_camelize} { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
// todo: handle column name contains whitespace
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
strWhere += `\t\t${args.columns[i]._cn}: ${this._getGraphqlConditionType(args.columns[i])},\r\n`;
}
}
let hasManyRelations = args.relations.filter(r => r.rtn === args.tn);
if (hasManyRelations.length > 1)
hasManyRelations = lodash.uniqBy(hasManyRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (let i = 0; i < hasManyRelations.length; ++i) {
let childTable = inflection.camelize(hasManyRelations[i]._tn)
str += `\t\t${childTable}List: [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str+= this.generateManyToManyTypeProps(args);
let belongsToRelations = args.relations.filter(r => r.tn === args.tn);
if (belongsToRelations.length > 1)
belongsToRelations = lodash.uniqBy(belongsToRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (let i = 0; i < belongsToRelations.length; ++i) {
let parentTable = inflection.camelize(belongsToRelations[i]._rtn)
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`
const grpFields = Object.assign({}, GROUPBY_DEFAULT_COLS);
str += `type ${args.tn_camelize}GroupBy { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in grpFields) {
grpFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
// todo: handle column name contains whitespace
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`
const aggFields = Object.assign({}, AGG_DEFAULT_COLS);
str += `type ${args.tn_camelize}Aggregate { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in aggFields) {
aggFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
// todo: handle column name contains whitespace
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`
strWhere += `
_or:[Condition${args.tn_camelize}]
_not:Condition${args.tn_camelize}
_and:[Condition${args.tn_camelize}]
\t}\r\n`
return `${str}\r\n\r\n${strWhere}`;
}
*/
protected _getGraphqlType(columnObj): string {
switch (columnObj.dt) {
case 'tinyint':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'serial':
case 'int':
return 'Int';
break;
case 'float':
case 'decimal':
case 'double':
case 'real':
return 'Float';
break;
case 'bit':
case 'boolean':
return 'Boolean';
case 'date':
case 'datetime':
case 'timestamp':
case 'time':
case 'year':
return 'String';
break;
case 'char':
case 'varchar':
case 'nchar':
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'binary':
case 'varbinary':
case 'blob':
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'enum':
return 'String';
break;
case 'set':
return 'JSON';
break;
case 'geometry':
case 'point':
case 'linestring':
case 'polygon':
case 'multipoint':
case 'multilinestring':
case 'multipolygon':
case 'json':
default:
return 'JSON';
break;
}
}
protected _getGraphqlConditionType(columnObj): any {
switch (this._getGraphqlType(columnObj.dt)) {
case 'Int':
return 'ConditionInt';
case 'Float':
return 'ConditionFloat';
case 'Boolean':
return 'ConditionBoolean';
case 'String':
case 'JSON':
return 'ConditionString';
case '[String]':
return 'ConditionString';
}
}
/*getString() {
return this._renderColumns(this.ctx);
}*/
}
export default GqlXcTsSchemaMysql;

253
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaOracle.ts

@ -1,253 +0,0 @@
import BaseGqlXcTsSchema from './BaseGqlXcTsSchema';
class GqlXcSchemaOracle extends BaseGqlXcTsSchema {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/*/!**
* Prepare variables used in code template
*!/
prepare() {
const data:any = {};
/!* run of simple variable *!/
data.tn = this.ctx.tn_camelize;
data.columns = {
func: this._renderColumns.bind(this),
args: this.ctx
};
return data;
}
/!**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*!/
_renderColumns(args) {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`
str += '';
return str;
}
_getInputType(args) {
let str = `input ${args.tn_camelize}Input { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn.split(' ').length > 1) {
// str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += `\t}`;
return str;
}
_getQuery(args) {
let str = `type Query { \r\n`
str += `\t\t${args.tn_camelize}List(where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}Read(id:String!): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Exists(id: String!): Boolean\r\n`
str += `\t\t${args.tn_camelize}FindOne(where: String,,condition:Condition${args.tn_camelize}): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Count(where: String,condition:Condition${args.tn_camelize}): Int\r\n`
str += `\t\t${args.tn_camelize}Distinct(column_name: String, where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args.tn_camelize}GroupBy]\r\n`
str += `\t\t${args.tn_camelize}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args.tn_camelize}Aggregate]\r\n`
str += `\t\t${args.tn_camelize}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`
str += `\t}\r\n`
return str;
}
_getMutation(args) {
let str = `type Mutation { \r\n`
str += `\t\t${args.tn_camelize}Create(data:${args.tn_camelize}Input): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Update(id:String,data:${args.tn_camelize}Input): Int\r\n` //${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Delete(id:String): Int\r\n`//${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}CreateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}UpdateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}DeleteBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t},\r\n`
return str;
}
_getType(args) {
let str = `type ${args.tn_camelize} { \r\n`
let strWhere = `input Condition${args.tn_camelize} { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
strWhere += `\t\t${args.columns[i]._cn}: ${this._getGraphqlConditionType(args.columns[i])},\r\n`;
}
let hasManyRelations = args.relations.filter(r => r.rtn === args.tn);
if (hasManyRelations.length > 1)
hasManyRelations = lodash.uniqBy(hasManyRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (let i = 0; i < hasManyRelations.length; ++i) {
let childTable = inflection.camelize(hasManyRelations[i]._tn)
str += `\t\t${childTable}List: [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str+= this.generateManyToManyTypeProps(args);
let belongsToRelations = args.relations.filter(r => r.tn === args.tn);
if (belongsToRelations.length > 1)
belongsToRelations = lodash.uniqBy(belongsToRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (let i = 0; i < belongsToRelations.length; ++i) {
let parentTable = inflection.camelize(belongsToRelations[i]._rtn)
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`
const grpFields = Object.assign({}, GROUPBY_DEFAULT_COLS);
str += `type ${args.tn_camelize}GroupBy { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in grpFields) {
grpFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`
const aggFields = Object.assign({}, AGG_DEFAULT_COLS);
str += `type ${args.tn_camelize}Aggregate { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in aggFields) {
aggFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`
strWhere += `
_or:[Condition${args.tn_camelize}]
_not:Condition${args.tn_camelize}
_and:[Condition${args.tn_camelize}]
\t}\r\n`
return `${str}\r\n\r\n${strWhere}`;
}
*/
protected _getGraphqlType(columnObj): any {
switch (columnObj.dt) {
case 'char':
case 'nchar':
case 'nvarchar2':
case 'varchar2':
case 'long':
case 'raw':
case 'long raw':
return 'String';
break;
case 'number':
case 'numeric':
case 'float':
case 'dec':
case 'real':
case 'decimal':
case 'double precision':
return 'Float';
break;
case 'integer':
case 'int':
case 'smallint':
return 'Int';
break;
case 'date':
case 'timestamp':
case 'timestamp with time zone':
case 'timestamp with local time zone':
case 'interval year to month':
case 'interval day to second':
case 'bfile':
case 'blob':
case 'clob':
case 'nclob':
return 'String';
break;
case 'rowid':
case 'urowid':
return 'Int';
break;
default:
return 'String';
break;
}
}
protected _getGraphqlConditionType(columnObj): any {
switch (this._getGraphqlType(columnObj.dt)) {
case 'Int':
return 'ConditionInt';
case 'Float':
return 'ConditionFloat';
case 'Boolean':
return 'ConditionBoolean';
case 'String':
return 'ConditionString';
case '[String]':
return 'ConditionString';
}
}
/*getString(){
return this._renderColumns(this.ctx);
}*/
}
export default GqlXcSchemaOracle;

325
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaPg.ts

@ -1,325 +0,0 @@
import BaseGqlXcTsSchema from './BaseGqlXcTsSchema';
class GqlXcSchemaPg extends BaseGqlXcTsSchema {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/* /!**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*!/
_renderColumns(args) {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`
str += '';
return str;
}*/
/* _getInputType(args) {
let str = `input ${args.tn_camelize}Input { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn.split(' ').length > 1) {
console.log(`Skipping ${args.tn}.${args.columns[i]._cn}`);
} else {
str += `\t\t${args.columns[i]._cn.replace(/ /g, '_')}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += `\t}`;
return str;
}*/
/* _getQuery(args) {
let str = `type Query { \r\n`
str += `\t\t${args.tn_camelize}List(where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}Read(id:String!): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Exists(id: String!): Boolean\r\n`
str += `\t\t${args.tn_camelize}FindOne(where: String,condition:Condition${args.tn_camelize}): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Count(where: String,condition:Condition${args.tn_camelize}): Int\r\n`
str += `\t\t${args.tn_camelize}Distinct(column_name: String, where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args.tn_camelize}GroupBy]\r\n`
str += `\t\t${args.tn_camelize}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args.tn_camelize}Aggregate]\r\n`
str += `\t\t${args.tn_camelize}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`
str += `\t}\r\n`
return str;
}*/
/* _getMutation(args) {
let str = `type Mutation { \r\n`
str += `\t\t${args.tn_camelize}Create(data:${args.tn_camelize}Input): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Update(id:String,data:${args.tn_camelize}Input): Int\r\n` //${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Delete(id:String): Int\r\n`//${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}CreateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}UpdateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}DeleteBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t},\r\n`
return str;
}*/
/* _getType(args) {
let str = `type ${args.tn_camelize} { \r\n`
let strWhere = `input Condition${args.tn_camelize} { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn.split(' ').length > 1) {
console.log(`Skipping ${args.tn}.${args.columns[i]._cn}`);
} else {
str += `\t\t${args.columns[i]._cn.replace(/ /g, '_')}: ${this._getGraphqlType(args.columns[i])},\r\n`;
strWhere += `\t\t${args.columns[i]._cn.replace(/ /g, '_')}: ${this._getGraphqlConditionType(args.columns[i])},\r\n`;
}
}
let hasManyRelations = args.relations.filter(r => r.rtn === args.tn);
if (hasManyRelations.length > 1)
hasManyRelations = lodash.uniqBy(hasManyRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (let i = 0; i < hasManyRelations.length; ++i) {
let childTable = inflection.camelize(hasManyRelations[i]._tn)
str += `\t\t${childTable}List: [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str+= this.generateManyToManyTypeProps(args);
let belongsToRelations = args.relations.filter(r => r.tn === args.tn);
if (belongsToRelations.length > 1)
belongsToRelations = lodash.uniqBy(belongsToRelations, function (e) {
return [e.tn, e.rtn].join();
});
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (let i = 0; i < belongsToRelations.length; ++i) {
let parentTable = inflection.camelize(belongsToRelations[i]._rtn)
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`
const grpFields = Object.assign({}, GROUPBY_DEFAULT_COLS);
str += `type ${args.tn_camelize}GroupBy { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in grpFields) {
grpFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn.replace(/ /g, '_')}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`
const aggFields = Object.assign({}, AGG_DEFAULT_COLS);
str += `type ${args.tn_camelize}Aggregate { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in aggFields) {
aggFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn.replace(/ /g, '_')}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`
strWhere += `
_or:[Condition${args.tn_camelize}]
_not:Condition${args.tn_camelize}
_and:[Condition${args.tn_camelize}]
\t}\r\n`
return `${str}\r\n\r\n${strWhere}`;
}*/
_getGraphqlType(columnObj) {
switch (columnObj.dt) {
case 'int':
case 'integer':
case 'bigint':
case 'bigserial':
case 'char':
case 'int2':
case 'int4':
case 'int8':
case 'int4range':
case 'int8range':
case 'serial':
case 'serial2':
case 'smallint':
case 'smallserial':
case 'serial8':
if (columnObj.dtx === 'ARRAY') {
return '[Int]';
}
return 'Int';
break;
case 'bit':
case 'bool':
case 'boolean':
if (columnObj.dtx === 'ARRAY') {
return '[Boolean]';
}
return 'Boolean';
break;
case 'money':
case 'real':
case 'float4':
case 'float8':
if (columnObj.dtx === 'ARRAY') {
return '[Float]';
}
return 'Float';
break;
case 'json':
case 'jsonb':
case 'anyenum':
case 'anynonarray':
case 'path':
case 'point':
case 'polygon':
if (columnObj.dtx === 'ARRAY') {
return '[JSON]';
}
return 'JSON';
case 'character':
case 'uuid':
case 'date':
case 'double precision':
case 'event_trigger':
case 'fdw_handler':
case 'character varying':
case 'text':
case 'time':
case 'time without time zone':
case 'timestamp':
case 'timestamp without time zone':
case 'timestamptz':
case 'timestamp with time zone':
case 'timetz':
case 'time with time zone':
case 'daterange':
case 'gtsvector':
case 'index_am_handler':
case 'anyrange':
case 'box':
case 'bpchar':
case 'bytea':
case 'cid':
case 'cidr':
case 'circle':
case 'cstring':
case 'inet':
case 'internal':
case 'interval':
case 'language_handler':
case 'line':
case 'lsec':
case 'macaddr':
case 'name':
case 'numeric':
case 'numrange':
case 'oid':
case 'opaque':
case 'pg_ddl_command':
case 'pg_lsn':
case 'pg_node_tree':
case 'record':
case 'refcursor':
case 'regclass':
case 'regconfig':
case 'regdictionary':
case 'regnamespace':
case 'regoper':
case 'regoperator':
case 'regproc':
case 'regpreocedure':
case 'regrole':
case 'regtype':
case 'reltime':
case 'smgr':
case 'tid':
case 'tinterval':
case 'trigger':
case 'tsm_handler':
case 'tsquery':
case 'tsrange':
case 'tstzrange':
case 'tsvector':
case 'txid_snapshot':
case 'unknown':
case 'void':
case 'xid':
case 'xml':
default:
if (columnObj.dtx === 'ARRAY') {
return '[String]';
}
return 'String';
break;
}
}
protected _getGraphqlConditionType(columnObj): any {
switch (this._getGraphqlType(columnObj.dt)) {
case 'Int':
return 'ConditionInt';
case 'Float':
return 'ConditionFloat';
case 'Boolean':
return 'ConditionBoolean';
case 'String':
return 'ConditionString';
case '[String]':
return 'ConditionString';
case '[JSON]':
return 'ConditionString';
case 'JSON':
return 'ConditionString';
}
}
/* getString(){
return this._renderColumns(this.ctx);
}*/
}
export default GqlXcSchemaPg;

231
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/GqlXcTsSchemaSqlite.ts

@ -1,231 +0,0 @@
import BaseGqlXcTsSchema from './BaseGqlXcTsSchema';
class GqlXcSchemaSqlite extends BaseGqlXcTsSchema {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }) {
super({ dir, filename, ctx });
}
/*/!**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*!/
public _renderColumns(args): string {
let str = '';
str += `
${this._getInputType(args)}\r\n
${this._getQuery(args)},\r\n
${this._getMutation(args)}\r\n
${this._getType(args)}\r\n
`
str += '';
return str;
}*/
protected _getGraphqlType(columnObj): any {
switch (columnObj.dt) {
case 'int':
case 'integer':
case 'tinyint':
case 'smallint':
case 'mediumint':
case 'bigint':
case 'int2':
case 'int8':
return 'Int';
break;
case 'character':
case 'blob sub_type text':
case 'blob':
return 'String';
break;
case 'real':
case 'double':
case 'double precision':
case 'float':
case 'numeric':
return 'Float';
break;
case 'boolean':
return 'Boolean';
break;
case 'date':
case 'datetime':
case 'text':
case 'varchar':
case 'timestamp':
return 'String';
break;
default:
return 'String';
break;
}
}
protected _getGraphqlConditionType(columnObj): any {
switch (this._getGraphqlType(columnObj.dt)) {
case 'Int':
return 'ConditionInt';
case 'Float':
return 'ConditionFloat';
case 'Boolean':
return 'ConditionBoolean';
case 'String':
return 'ConditionString';
case '[String]':
return 'ConditionString';
}
}
/*
public getString(): string {
return this._renderColumns(this.ctx);
}
*/
/*
protected _getInputType(args): string {
let str = `input ${args.tn_camelize}Input { \r\n`
for (const column of args.columns) {
if (column._cn.split(' ').length > 1) {
// str += `\t\t${column._cn}: ${this._getGraphqlType(column)},\r\n`;
} else {
str += `\t\t${column._cn}: ${this._getGraphqlType(column)},\r\n`;
}
}
str += `\t}`;
return str;
}
protected _getQuery(args): string {
let str = `type Query { \r\n`
str += `\t\t${args.tn_camelize}List(where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}Read(id:String!): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Exists(id: String!): Boolean\r\n`
str += `\t\t${args.tn_camelize}FindOne(where: String,condition:Condition${args.tn_camelize}): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Count(where: String,condition:Condition${args.tn_camelize}): Int\r\n`
str += `\t\t${args.tn_camelize}Distinct(column_name: String, where: String,condition:Condition${args.tn_camelize}, limit: Int, offset: Int, sort: String): [${args.tn_camelize}]\r\n`
str += `\t\t${args.tn_camelize}GroupBy(fields: String, having: String, limit: Int, offset: Int, sort: String): [${args.tn_camelize}GroupBy]\r\n`
str += `\t\t${args.tn_camelize}Aggregate(column_name: String!, having: String, limit: Int, offset: Int, sort: String, func: String!): [${args.tn_camelize}Aggregate]\r\n`
str += `\t\t${args.tn_camelize}Distribution(min: Int, max: Int, step: Int, steps: String, column_name: String!): [distribution]\r\n`
str += `\t}\r\n`
return str;
}
protected _getMutation(args): string {
let str = `type Mutation { \r\n`
str += `\t\t${args.tn_camelize}Create(data:${args.tn_camelize}Input): ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Update(id:String,data:${args.tn_camelize}Input): Int\r\n` // ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}Delete(id:String): Int\r\n`// ${args.tn_camelize}\r\n`
str += `\t\t${args.tn_camelize}CreateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}UpdateBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t\t${args.tn_camelize}DeleteBulk(data: [${args.tn_camelize}Input]): [Int]\r\n`
str += `\t},\r\n`
return str;
}
protected _getType(args): string {
let str = `type ${args.tn_camelize} { \r\n`
let strWhere = `input Condition${args.tn_camelize} { \r\n`
for (const column of args.columns.length) {
str += `\t\t${column._cn}: ${this._getGraphqlType(column)},\r\n`;
strWhere += `\t\t${column._cn.replace(/ /g, '_')}: ${this._getGraphqlConditionType(column)},\r\n`;
}
let hasManyRelations = args.relations.filter(r => r.rtn === args.tn);
if (hasManyRelations.length > 1) {
hasManyRelations = lodash.uniqBy(hasManyRelations, (e) => {
return [e.tn, e.rtn].join();
});
}
str += hasManyRelations.length ? `\r\n` : ``;
// cityList in Country
for (const {_tn} of hasManyRelations.length) {
const childTable = inflection.camelize(_tn)
str += `\t\t${childTable}List: [${childTable}]\r\n`;
strWhere += `\t\t${childTable}List: Condition${childTable}\r\n`;
str += `\t\t${childTable}Count: Int\r\n`;
}
str += this.generateManyToManyTypeProps(args);
let belongsToRelations = args.relations.filter(r => r.tn === args.tn);
if (belongsToRelations.length > 1) {
belongsToRelations = lodash.uniqBy(belongsToRelations, (e) => {
return [e.tn, e.rtn].join();
});
}
str += belongsToRelations.length ? `\r\n` : ``;
// Country withi city - this is reverse
for (const {_rtn} of belongsToRelations.length) {
const parentTable = inflection.camelize(_rtn)
str += `\t\t${parentTable}Read(id:String): ${parentTable}\r\n`;
strWhere += `\t\t${parentTable}Read: Condition${parentTable}\r\n`;
}
str += `\t}\r\n`
const grpFields = {...GROUPBY_DEFAULT_COLS};
str += `type ${args.tn_camelize}GroupBy { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in grpFields) {
grpFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(grpFields).join('');
str += `\t}\r\n`;
const aggFields = {...AGG_DEFAULT_COLS};
str += `type ${args.tn_camelize}Aggregate { \r\n`
for (let i = 0; i < args.columns.length; ++i) {
if (args.columns[i]._cn in aggFields) {
aggFields[args.columns[i]._cn] = `\t\t# ${args.columns[i]._cn} - clashes with column in table\r\n`;
} else {
str += `\t\t${args.columns[i]._cn}: ${this._getGraphqlType(args.columns[i])},\r\n`;
}
}
str += Object.values(aggFields).join('');
str += `\t}\r\n`
strWhere += `
_or:[Condition${args.tn_camelize}]
_not:Condition${args.tn_camelize}
_and:[Condition${args.tn_camelize}]
\t}\r\n`
return `${str}\r\n\r\n${strWhere}`;
}*/
}
export default GqlXcSchemaSqlite;

13
packages/nocodb/src/db/sql-mgr/code/gql-schema/xc-ts/schemaHelp.ts

@ -1,13 +0,0 @@
const AGG_DEFAULT_COLS = {
count: `\t\tcount: Int,\r\n`,
avg: `\t\tavg: Float,\r\n`,
min: `\t\tmin: Float,\r\n`,
max: `\t\tmax: Int,\r\n`,
sum: `\t\tsum: Float\r\n`,
};
const GROUPBY_DEFAULT_COLS = {
count: `\t\tcount: Int,\r\n`,
};
export { AGG_DEFAULT_COLS, GROUPBY_DEFAULT_COLS };

788
packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXc.ts

@ -1,788 +0,0 @@
import BaseRender from '../../BaseRender';
import SwaggerTypes from './SwaggerTypes';
class SwaggerXc extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir = '', filename = '', ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare() {
let data: any = {};
/* run of simple variable */
data = this.ctx;
data.paths = {};
data.definitions = {
func: this._renderDefinitions.bind(this),
args: {
tn: this.ctx.tn,
columns: this.ctx.columns,
relations: this.ctx.relations,
dbType: this.ctx.dbType,
},
};
return data;
}
/**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*/
_renderDefinitions(args) {
const obj = this.getDefenitions(args);
return JSON.stringify(obj);
}
getDefenitions(args) {
const obj = {
[args._tn]: {
type: 'object',
properties: {},
},
[`${args._tn}Nested`]: {
type: 'object',
properties: {},
},
};
let properties = obj[args._tn].properties;
for (const column of args.columns) {
const field: any = {};
SwaggerTypes.setSwaggerType(column, field, args.dbType);
if (column.rqd) {
field.nullable = false;
}
if (column.ai) {
field.readOnly = true;
}
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;
let _cn = column._cn;
if (column.mm) {
field.type = 'array';
field.items = {
$ref: `#/definitions/${column.mm?._rtn}`,
};
_cn = `${column.mm?._rtn}MMList`;
} else if (column.hm) {
field.type = 'array';
field.items = {
$ref: `#/definitions/${column.hm?._tn}`,
};
field.$ref = `#/definitions/${column.hm?._tn}`;
_cn = `${column.hm?._tn}List`;
} else if (column.bt) {
field.$ref = `#/definitions/${column.bt?._rtn}`;
_cn = `${column.bt?._rtn}Read`;
}
properties[_cn] = field;
}
return obj;
}
getObject() {
return {
tags: [
{
name: `${this.ctx._tn}`,
description: `Everything about your ${this.ctx._tn}`,
},
],
paths: {
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}`]:
{
post: {
tags: [`${this.ctx._tn}`],
summary: `Add a new ${this.ctx._tn}`,
description: '',
operationId: `add${this.ctx._tn}`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._tn} object that needs to add`,
required: true,
schema: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
],
responses: {
'405': {
description: 'Invalid input',
},
},
},
get: {
tags: [`${this.ctx._tn}`],
summary: 'Get list',
description: '',
operationId: `get${this.ctx._tn}`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'fields',
type: 'string',
description: 'Comma separated fields from the model',
},
{
in: 'query',
name: 'bt',
type: 'string',
description: 'Comma separated parent table names(Belongs To)',
},
{
in: 'query',
name: 'hm',
type: 'string',
description: 'Comma separated child table names(Has Many)',
},
{
in: 'query',
name: 'mm',
type: 'string',
description:
'Comma separated child table names(Many to Many)',
},
{
in: 'query',
name: 'where',
type: 'string',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Comma separated sort fields',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: {
$ref: `#/definitions/${this.ctx._tn}Nested`,
},
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: `Find ${this.ctx._tn} by ID`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `get${this.ctx._tn}ById`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return. In case of composite key provide keys separated by ___`,
required: true,
type: 'string',
},
{
in: 'query',
name: 'bt',
type: 'string',
description: 'Comma separated parent table names(Belongs To)',
},
{
in: 'query',
name: 'hm',
type: 'string',
description: 'Comma separated child table names(Has Many)',
},
{
in: 'query',
name: 'mm',
type: 'string',
description:
'Comma separated child table names(Many to Many)',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
$ref: `#/definitions/${this.ctx._tn}Nested`,
},
},
'400': {
description: 'Invalid ID supplied',
},
'404': {
description: `${this.ctx._tn} not found`,
},
},
},
put: {
tags: [`${this.ctx._tn}`],
summary: `Updates a ${this.ctx._tn}`,
description: '',
operationId: `update${this.ctx._tn}`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return. In case of composite key provide keys separated by ___`,
required: true,
type: 'string',
},
{
in: 'body',
name: 'body',
description: `${this.ctx._tn} object that needs to be added to the store`,
required: true,
schema: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
],
responses: {
'405': {
description: 'Invalid input',
},
},
},
delete: {
tags: [`${this.ctx._tn}`],
summary: `Deletes a ${this.ctx._tn}`,
description: '',
operationId: `delete${this.ctx._tn}`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return. In case of composite key provide keys separated by ___`,
required: true,
type: 'string',
},
],
responses: {
'400': {
description: 'Invalid ID supplied',
},
'404': {
description: `${this.ctx._tn} not found`,
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/bulk`]:
{
post: {
tags: [`${this.ctx._tn}`],
summary: `Bulk ${this.ctx._tn} insert`,
description: '',
operationId: `bulk${this.ctx._tn}Insert`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._tn} objects`,
required: true,
schema: {
type: 'array',
items: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
],
responses: {
'405': {
description: 'Invalid input',
},
},
},
put: {
tags: [`${this.ctx._tn}`],
summary: `Bulk ${this.ctx._tn} update`,
description: '',
operationId: `bulk${this.ctx._tn}Update`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._tn} objects with id`,
required: true,
schema: {
type: 'array',
items: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
],
responses: {
'405': {
description: 'Invalid input',
},
},
},
delete: {
tags: [`${this.ctx._tn}`],
summary: `Bulk ${this.ctx._tn} delete`,
description: '',
operationId: `bulk${this.ctx._tn}Delete`,
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._tn} objects contains id`,
required: true,
schema: {
type: 'array',
items: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
],
responses: {
'400': {
description: 'Invalid ID supplied',
},
'404': {
description: `${this.ctx._tn} not found`,
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/findOne`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: 'Get first one from filtered data',
description: '',
operationId: `findOne${this.ctx._tn}`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'fields',
type: 'string',
description: 'Comma separated fields from the model',
},
{
in: 'query',
name: 'where',
type: 'string',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Comma separated sort fields',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/exists`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: `Check ${this.ctx._tn} with provided ID exists`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `check${this.ctx._tn}Exists`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return. In case of composite key provide keys separated by ___`,
required: true,
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'boolean',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/count`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: `Get ${this.ctx._tn} count`,
operationId: `get${this.ctx._tn}Count`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'where',
type: 'string',
description: 'Where expression',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
type: 'object',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/groupby`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: 'Group by column',
description: '',
operationId: `${this.ctx._tn}GroupByColumn`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'column_name',
type: 'string',
description: 'Column name',
},
{
in: 'query',
name: 'where',
type: 'string',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Comma separated sort fieldst',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/distribution`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: '',
description: '',
operationId: `${this.ctx._tn}Distribution`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'column_name',
type: 'string',
description: 'Column name',
},
{
in: 'query',
name: 'min',
description: 'min value',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'max',
description: 'max value',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'step',
description: 'step value',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'steps',
description: 'steps value',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'func',
description: 'comma separated aggregation functions',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: {
type: 'object',
},
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/distinct`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: 'Get first one from filtered data',
description: '',
operationId: `${this.ctx._tn}Distinct`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'column_name',
type: 'string',
description: 'Column name',
},
{
in: 'query',
name: 'where',
type: 'string',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Comma separated sort fields',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: {
type: 'object',
},
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/aggregate`]:
{
get: {
tags: [`${this.ctx._tn}`],
summary: 'Get first one from filtered data',
description: '',
operationId: `${this.ctx._tn}Aggregate`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'column_name',
type: 'string',
description: 'Column name',
},
{
in: 'query',
name: 'func',
type: 'string',
description: 'Comma separated aggregate functions',
},
{
in: 'query',
name: 'having',
type: 'string',
description: 'Having expression',
},
{
in: 'query',
name: 'fields',
type: 'string',
description: 'Comma separated fields from the model',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Comma separated sort fields',
type: 'string',
},
],
responses: {
'405': {
description: 'Invalid input',
},
'200': {
description: 'successful operation',
schema: {
$ref: `#/definitions/${this.ctx._tn}`,
},
},
},
},
},
},
definitions: this.getDefenitions(this.ctx),
};
}
}
export default SwaggerXc;

119
packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXcBt.ts

@ -1,119 +0,0 @@
import BaseRender from '../../BaseRender';
class SwaggerXcBt extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare() {
let data: any = {};
/* run of simple variable */
data = this.ctx;
data.definitions = {
func: this._renderDefinitions.bind(this),
args: {
tn: this.ctx.tn,
columns: this.ctx.columns,
relations: this.ctx.relations,
},
};
return data;
}
/**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*/
_renderDefinitions(_args) {
const obj = {};
return JSON.stringify(obj);
}
getObject() {
return {
tags: [
{
name: `${this.ctx._tn}BelongsTo${this.ctx._rtn || this.ctx.rtn}`,
description: 'Everything about belongs to relation',
},
],
paths: {
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${
this.ctx._tn
}/belongs/${this.ctx._rtn || this.ctx.rtn}`]: {
get: {
tags: [`${this.ctx._tn}BelongsTo${this.ctx._rtn || this.ctx.rtn}`],
summary: `Get ${this.ctx._tn} list with ${
this.ctx._rtn || this.ctx.rtn
} parent`,
description: '',
operationId: `${this.ctx._tn}WithParent`,
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'where',
type: 'String',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'Page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'Pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'Sort parameter',
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: {
type: 'object',
},
},
},
},
},
},
},
definitions: {},
};
}
}
export default SwaggerXcBt;

484
packages/nocodb/src/db/sql-mgr/code/routers/xc-ts/SwaggerXcHm.ts

@ -1,484 +0,0 @@
import BaseRender from '../../BaseRender';
class SwaggerXcHm extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare() {
let data: any = {};
/* run of simple variable */
data = this.ctx;
data.definitions = {
func: this._renderDefinitions.bind(this),
args: {
tn: this.ctx.tn,
columns: this.ctx.columns,
relations: this.ctx.relations,
},
};
return data;
}
/**
*
* @param args
* @param args.columns
* @param args.relations
* @returns {string}
* @private
*/
_renderDefinitions(_args) {
const obj = {};
return JSON.stringify(obj);
}
getObject() {
return {
tags: [
{
name: `${this.ctx._tn}HasMany${this.ctx._ctn}`,
description: 'Everything about has many relation',
},
],
paths: {
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/has/${this.ctx._ctn}`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Get ${this.ctx._tn} list with ${this.ctx._ctn} children`,
description: '',
operationId: `${this.ctx._tn}HasMany${this.ctx._ctn}List`,
produces: ['application/json'],
parameters: [
{
in: 'query',
name: 'fields',
type: 'String',
description: 'Comma separated fields of model',
},
{
in: 'query',
name: 'where',
type: 'String',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'sort parameter',
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: {
type: 'object',
},
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/${this.ctx._ctn}`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Find ${this.ctx._ctn} list by parent ${this.ctx._tn} id`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `get${this.ctx._ctn}By${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return`,
required: true,
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'fields',
type: 'String',
description: 'Comma separated fields of model',
},
{
in: 'query',
name: 'where',
type: 'String',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'sort parameter',
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: 'object',
},
},
'400': {
description: 'Invalid ID supplied',
},
'404': {
description: `${this.ctx._tn} not found`,
},
},
},
post: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Insert ${this.ctx._ctn} under a parent ${this.ctx._tn}`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `insert${this.ctx._ctn}By${this.ctx._tn}Id`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._ctn} object to insert`,
required: true,
schema: {
type: 'object',
},
},
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return`,
required: true,
type: 'integer',
format: 'int64',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'object',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/${this.ctx._ctn}/{${this.ctx._ctn}Id}`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Get by ${this.ctx._ctn} id parent ${this.ctx._tn} id`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `get${this.ctx._ctn}ByIdAnd${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of parent ${this.ctx._tn}`,
required: true,
type: 'integer',
format: 'int64',
},
{
name: `${this.ctx._ctn}Id`,
in: 'path',
description: `ID of ${this.ctx._ctn}`,
required: true,
type: 'integer',
format: 'int64',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'array',
items: 'object',
},
},
},
},
delete: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Delete by ${this.ctx._ctn} id parent ${this.ctx._tn} id`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `delete${this.ctx._ctn}ByIdAnd${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of parent ${this.ctx._tn}`,
required: true,
type: 'integer',
format: 'int64',
},
{
name: `${this.ctx._ctn}Id`,
in: 'path',
description: `ID of c${this.ctx._ctn}`,
required: true,
type: 'integer',
format: 'int64',
},
],
responses: {
'200': {
description: 'successful operation',
},
},
},
put: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Update ${this.ctx._ctn} under a parent ${this.ctx._tn}`,
description: `Returns a single ${this.ctx._tn}`,
operationId: `update${this.ctx._ctn}ByIdAnd${this.ctx._tn}Id`,
consumes: ['application/json'],
produces: ['application/json'],
parameters: [
{
in: 'body',
name: 'body',
description: `${this.ctx._ctn} object to insert`,
required: true,
schema: {
type: 'object',
},
},
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of ${this.ctx._tn} to return`,
required: true,
type: 'integer',
format: 'int64',
},
{
name: `${this.ctx._ctn}Id`,
in: 'path',
description: `ID of ${this.ctx._ctn}`,
required: true,
type: 'integer',
format: 'int64',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'object',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/${this.ctx._ctn}/{${this.ctx._ctn}Id}/exists`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Check row exists by ${this.ctx._ctn} id and parent ${this.ctx._tn} id`,
description: '',
operationId: `exists${this.ctx._ctn}ByIdAnd${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of parent ${this.ctx._tn}`,
required: true,
type: 'integer',
format: 'int64',
},
{
name: `${this.ctx._ctn}Id`,
in: 'path',
description: `ID of ${this.ctx._ctn}`,
required: true,
type: 'integer',
format: 'int64',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'boolean',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/${this.ctx._ctn}/findOne`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Find one ${this.ctx._ctn} by parent ${this.ctx._tn} id and filters`,
description: '',
operationId: `findOne${this.ctx._ctn}By${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of parent ${this.ctx._tn}`,
required: true,
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'fields',
type: 'String',
description: 'Comma separated fields of model',
},
{
in: 'query',
name: 'where',
type: 'String',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'sort parameter',
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'object',
},
},
},
},
},
[`/nc/${this.ctx.base_id}/api/${this.ctx.routeVersionLetter}/${this.ctx._tn}/{${this.ctx._tn}Id}/${this.ctx._ctn}/count`]:
{
get: {
tags: [`${this.ctx._tn}HasMany${this.ctx._ctn}`],
summary: `Get ${this.ctx._ctn} count by parent id and filter`,
description: '',
operationId: `getCountWithin${this.ctx._tn}Id`,
produces: ['application/json'],
parameters: [
{
name: `${this.ctx._tn}Id`,
in: 'path',
description: `ID of parent ${this.ctx._tn}`,
required: true,
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'where',
type: 'String',
description: 'Where expression',
},
{
in: 'query',
name: 'limit',
description: 'page size limit',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'offset',
description: 'pagination offset',
type: 'integer',
format: 'int64',
},
{
in: 'query',
name: 'sort',
description: 'sort parameter',
type: 'string',
},
],
responses: {
'200': {
description: 'successful operation',
schema: {
type: 'object',
},
},
},
},
},
},
definitions: {},
};
}
}
export default SwaggerXcHm;

367
packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes.ts

@ -1,367 +0,0 @@
import BaseRender from '../../BaseRender';
class ExpressXcTsRoutes extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare() {
let data: any = {};
/* run of simple variable */
data = this.ctx;
return data;
}
getObject() {
const ejsData: any = this.prepare();
const routes = [
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}`,
type: 'get',
handler: ['list'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.list(req.query);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/findOne`,
type: 'get',
handler: ['findOne'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.findOne(req.query);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/m2mNotChildren/:assoc/:pid`,
type: 'get',
handler: ['m2mNotChildren'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/groupby/:column_name`,
type: 'get',
handler: ['groupby'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.groupBy({
...req.params,
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/count`,
type: 'get',
handler: ['count'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.countByPk({
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/bulk`,
type: 'post',
handler: ['bulkInsert'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.insertb(req.body);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/bulk`,
type: 'put',
handler: ['bulkUpdate'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.updateb(req.body);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/bulk`,
type: 'delete',
handler: ['bulkDelete'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.delb(req.body)
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/:id/exists`,
type: 'get',
handler: ['exists'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.exists(req.params.id);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/distinct`,
type: 'get',
handler: ['distinct'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.distinct({
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/distribute`,
type: 'get',
handler: ['distribute'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.distribution({
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/aggregate`,
type: 'get',
handler: ['aggregate'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.aggregate({
...req.params,
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/groupby`,
type: 'get',
handler: ['groupby'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.groupBy({
...req.params,
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/:id`,
type: 'get',
handler: ['get'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.model.readByPk(req.params.id);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}`,
type: 'post',
handler: ['create'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.insert(req.body, null, req);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/:id`,
type: 'put',
handler: ['update'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.updateByPk(req.params.id, req.body, null, req);
res.json(data);
}
`,
],
},
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/:id`,
type: 'delete',
handler: ['delete'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.model.delByPk(req.params.id, null, req);
res.json(data);
}
`,
],
},
];
if (this.ctx.type === 'view') {
return routes.filter(
({ type, handler }) =>
type === 'get' &&
!handler.includes('exists') &&
!handler.includes('get'),
);
}
return routes;
}
getObjectWithoutFunctions() {
return this.getObject().map(({ functions, ...rest }) => rest);
}
}
export default ExpressXcTsRoutes;

61
packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutesBt.ts

@ -1,61 +0,0 @@
import BaseRender from '../../BaseRender';
class ExpressXcTsRoutesBt extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
prepare() {
let data: any = {};
/* run of simple variable */
data = this.ctx;
return data;
}
getObject() {
const ejsData = this.prepare();
return [
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/belongs/${ejsData._rtn}`,
type: 'get',
handler: ['list'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.childModel.belongsTo({
parents: req.parentModel.tn,
...req.query
});
res.json(data);
}
`,
],
},
];
}
getObjectWithoutFunctions() {
return this.getObject().map(({ functions, ...rest }) => rest);
}
}
export default ExpressXcTsRoutesBt;

239
packages/nocodb/src/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutesHm.ts

@ -1,239 +0,0 @@
import BaseRender from '../../BaseRender';
class ExpressXcTsRoutesHm extends BaseRender {
/**
*
* @param dir
* @param filename
* @param ct
* @param ctx.tn
* @param ctx.columns
* @param ctx.relations
*/
constructor({ dir, filename, ctx }: any) {
super({ dir, filename, ctx });
}
/**
* Prepare variables used in code template
*/
public prepare(): any {
let data = {};
/* run of simple variable */
data = this.ctx;
return data;
}
public getObject() {
const ejsData: any = this.prepare();
return [
{
path: `/api/${this.ctx.routeVersionLetter}/${ejsData._tn}/has/:childs`, // ${ejsData._ctn}
type: 'get',
handler: ['hasManyList'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.parentModel.hasManyList({
...req.query,
childs: req.childModel.tn
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}`,
type: 'get',
handler: ['list'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.parentModel.hasManyChildren({
child: req.childModel.tn,
...req.params,
...req.query
})
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}`,
type: 'post',
handler: ['create'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.childModel.insertByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
data: req.body
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/findOne`,
type: 'get',
handler: ['findOne'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.childModel.findOneByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/count`,
type: 'get',
handler: ['count'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.childModel.countByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
...req.query
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/:id`,
type: 'get',
handler: ['read'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.childModel.readByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
id: req.params.id
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/:id`,
type: 'put',
handler: ['update'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.childModel.updateByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
id: req.params.id,
data: req.body
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/:id`,
type: 'delete',
handler: ['delete'],
acl: {
admin: true,
user: true,
guest: false,
},
functions: [
`
async function(req, res){
const data = await req.childModel.delByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
id: req.params.id
});
res.json(data);
}
`,
],
},
{
path: `/api/v1/${ejsData._tn}/:parentId/${ejsData._ctn}/:id/exists`,
type: 'get',
handler: ['exists'],
acl: {
admin: true,
user: true,
guest: true,
},
functions: [
`
async function(req, res){
const data = await req.childModel.existsByFk({
parentId: req.params.parentId,
parentTableName: req.parentModel.tn,
id: req.params.id,
...req.query
});
res.json(data);
}
`,
],
},
];
}
public getObjectWithoutFunctions() {
return this.getObject().map(({ functions, ...rest }) => rest);
}
}
export default ExpressXcTsRoutesHm;

1706
packages/nocodb/src/db/sql-migrator/lib/KnexMigrator.ts

File diff suppressed because it is too large Load Diff

37
packages/nocodb/src/db/sql-migrator/lib/SqlMigrator.ts

@ -1,37 +0,0 @@
export default class SqlMigrator {
protected base: any;
constructor() {
this.base = null;
}
init(_project = null) {}
// migrationsInit() {
//
// }
//
// migrationsCreate() {
//
// }
//
// migrationsList() {
//
// }
//
// migrationsUp() {
//
// }
//
// migrationsDown() {
//
// }
//
// migrationsStatus() {
//
// }
//
// migrationsDelete() {
//
// }
}

19
packages/nocodb/src/db/sql-migrator/lib/SqlMigratorFactory.ts

@ -1,19 +0,0 @@
import KnexMigrator from './KnexMigrator';
export default class SqlMigratorFactory {
static create(args) {
switch (args.client) {
case 'mysql':
case 'mysql2':
case 'pg':
case 'oracledb':
case 'mssql':
case 'sqlite3':
return new KnexMigrator();
break;
default:
throw new Error('Database not supported');
break;
}
}
}

9
packages/nocodb/src/meta/meta.service.ts

@ -707,6 +707,15 @@ export class MetaService {
* @returns {Promise<any[]>} - List of bases
* */
public async baseList(): Promise<any[]> {
// check if table exists
const tableExists = await this.knexConnection.schema.hasTable(
'nc_projects',
);
if (!tableExists) {
return [];
}
return (await this.knexConnection('nc_projects').select()).map((p) => {
p.config = CryptoJS.AES.decrypt(
p.config,

2
packages/nocodb/src/meta/migrations/XcMigrationSource.ts

@ -30,7 +30,7 @@ export default class XcMigrationSource {
'nc_009_add_model_order',
'nc_010_add_parent_title_column',
'nc_011_remove_old_ses_plugin',
...(process.env.NC_CLOUD === 'true' ? ['nc_012_cloud_cleanup'] : []),
'nc_012_cloud_cleanup',
]);
}

38
packages/nocodb/src/providers/init-meta-service.provider.ts

@ -11,6 +11,7 @@ import getInstance from '~/utils/getInstance';
import initAdminFromEnv from '~/helpers/initAdminFromEnv';
import { User } from '~/models';
import { NcConfig, prepareEnv } from '~/utils/nc-config';
import { MetaTable, RootScopes } from '~/utils/globals';
export const InitMetaServiceProvider: FactoryProvider = {
// initialize app,
@ -34,6 +35,43 @@ export const InitMetaServiceProvider: FactoryProvider = {
// init meta service
const metaService = new MetaService(config);
// check if nc_store exists
const ncStoreExists = await metaService.knexConnection.schema.hasTable(
MetaTable.STORE,
);
// get instance config
const instanceConfig = ncStoreExists
? await metaService.metaGet(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.STORE,
{
key: 'NC_CONFIG_MAIN',
},
)
: null;
// Avoid upgrading directly from versions lower than 0100002 (NC_VERSION)
if (instanceConfig) {
const configObj: NcConfig = JSON.parse(instanceConfig.value);
if (+configObj.version < 100002) {
throw new Error(
`You are trying to upgrade from an old version of NocoDB. Please upgrade to 0.207.3 first and then you can upgrade to the latest version.`,
);
}
} else {
// if bases are present then it is an old version missing the config
const isOld = (await metaService.baseList())?.length;
if (isOld) {
throw new Error(
`You are trying to upgrade from an old version of NocoDB. Please upgrade to 0.207.3 first and then you can upgrade to the latest version.`,
);
}
}
await metaService.init();
// provide meta and config to Noco

171
packages/nocodb/src/utils/common/NcConnectionMgr.ts

@ -1,171 +0,0 @@
import fs from 'fs';
import { promisify } from 'util';
import { defaultConnectionConfig } from '../nc-config';
import type { Knex } from 'knex';
import SqlClientFactory from '~/db/sql-client/lib/SqlClientFactory';
import { XKnex } from '~/db/CustomKnex';
// import type { NcConfig } from '~/interface/config';
// import type NcMetaIO from '~/meta/NcMetaIO';
export default class NcConnectionMgr {
private static connectionRefs: {
[baseId: string]: {
[env: string]: {
[dbAlias: string]: XKnex;
};
};
} = {};
private static metaKnex: any;
public static setXcMeta(ncMeta: any) {
this.metaKnex = ncMeta;
}
public static delete({
dbAlias = 'db',
env = '_noco',
baseId,
}: {
dbAlias: string;
env: string;
baseId: string;
}) {
// todo: ignore meta bases
if (this.connectionRefs?.[baseId]?.[env]?.[dbAlias]) {
try {
const conn = this.connectionRefs[baseId][env][dbAlias];
conn.destroy();
delete this.connectionRefs[baseId][env][dbAlias];
} catch (e) {
console.log(e);
}
}
}
public static async get({
dbAlias = 'db',
env = '_noco',
config,
baseId,
}: {
dbAlias: string;
env: string;
config: any;
baseId: string;
}): Promise<XKnex> {
if (this.connectionRefs?.[baseId]?.[env]?.[dbAlias]) {
return this.connectionRefs?.[baseId]?.[env]?.[dbAlias];
}
this.connectionRefs[baseId] = this.connectionRefs[baseId] || {};
this.connectionRefs[baseId][env] = this.connectionRefs[baseId][env] || {};
if (config?.prefix && this.metaKnex) {
this.connectionRefs[baseId][env][dbAlias] = this.metaKnex?.knex;
} else {
const connectionConfig = this.getConnectionConfig(config, env, dbAlias);
if (
connectionConfig?.connection?.ssl &&
typeof connectionConfig?.connection?.ssl === 'object'
) {
if (
connectionConfig.connection.ssl.caFilePath &&
!connectionConfig.connection.ssl.ca
) {
connectionConfig.connection.ssl.ca = (
await promisify(fs.readFile)(
connectionConfig.connection.ssl.caFilePath,
)
).toString();
delete connectionConfig.connection.ssl.caFilePath;
}
if (
connectionConfig.connection.ssl.keyFilePath &&
!connectionConfig.connection.ssl.key
) {
connectionConfig.connection.ssl.key = (
await promisify(fs.readFile)(
connectionConfig.connection.ssl.keyFilePath,
)
).toString();
delete connectionConfig.connection.ssl.keyFilePath;
}
if (
connectionConfig.connection.ssl.certFilePath &&
!connectionConfig.connection.ssl.cert
) {
connectionConfig.connection.ssl.cert = (
await promisify(fs.readFile)(
connectionConfig.connection.ssl.certFilePath,
)
).toString();
delete connectionConfig.connection.ssl.certFilePath;
}
}
const isSqlite = connectionConfig?.client === 'sqlite3';
if (connectionConfig?.connection?.port) {
connectionConfig.connection.port = +connectionConfig.connection.port;
}
this.connectionRefs[baseId][env][dbAlias] = XKnex(
isSqlite
? (connectionConfig.connection as Knex.Config)
: ({
...connectionConfig,
connection: {
...defaultConnectionConfig,
...connectionConfig.connection,
typeCast(_field, next) {
const res = next();
if (res instanceof Buffer) {
return [...res]
.map((v) => ('00' + v.toString(16)).slice(-2))
.join('');
}
return res;
},
},
} as any),
);
if (isSqlite) {
this.connectionRefs[baseId][env][dbAlias]
.raw(`PRAGMA journal_mode=WAL;`)
.then(() => {});
}
}
return this.connectionRefs[baseId][env][dbAlias];
}
private static getConnectionConfig(
config: any,
env: string,
dbAlias: string,
) {
return config?.envs?.[env]?.db?.find((db) => db?.meta?.dbAlias === dbAlias);
}
public static async getSqlClient({
baseId,
dbAlias = 'db',
env = '_noco',
config,
}: {
dbAlias: string;
env: string;
config: any;
baseId: string;
}) {
const knex = this.get({
dbAlias,
env,
config,
baseId,
});
return SqlClientFactory.create({
knex,
...this.getConnectionConfig(config, env, dbAlias),
});
}
}

2
packages/nocodb/src/utils/getInstance.ts

@ -29,7 +29,7 @@ export default async function (force = false, ncMeta = Noco.ncMeta) {
.first()
.then((c) => c.count);
const created = await ncMeta
.knex('nc_store')
.knex(MetaTable.STORE)
.select('created_at')
.where('key', 'nc_server_id')
.first()

24
packages/nocodb/src/version-upgrader/NcUpgrader.ts

@ -7,11 +7,6 @@ import ncStickyColumnUpgrader from './ncStickyColumnUpgrader';
import ncFilterUpgrader_0104004 from './ncFilterUpgrader_0104004';
import ncFilterUpgrader_0105003 from './ncFilterUpgrader_0105003';
import ncFilterUpgrader from './ncFilterUpgrader';
import ncProjectRolesUpgrader from './ncProjectRolesUpgrader';
import ncDataTypesUpgrader from './ncDataTypesUpgrader';
import ncProjectUpgraderV2_0090000 from './ncProjectUpgraderV2_0090000';
import ncProjectEnvUpgrader0011045 from './ncProjectEnvUpgrader0011045';
import ncProjectEnvUpgrader from './ncProjectEnvUpgrader';
import ncHookUpgrader from './ncHookUpgrader';
import ncProjectConfigUpgrader from './ncProjectConfigUpgrader';
import ncXcdbLTARUpgrader from './ncXcdbLTARUpgrader';
@ -19,7 +14,7 @@ import ncXcdbLTARIndexUpgrader from './ncXcdbLTARIndexUpgrader';
import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './ncXcdbCreatedAndUpdatedSystemFieldsUpgrader';
import type { MetaService } from '~/meta/meta.service';
import type { NcConfig } from '~/interface/config';
import { RootScopes } from '~/utils/globals';
import { MetaTable, RootScopes } from '~/utils/globals';
const log = debug('nc:version-upgrader');
@ -38,7 +33,9 @@ export default class NcUpgrader {
try {
ctx.ncMeta = await ctx.ncMeta.startTransaction();
if (!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.('nc_store'))) {
if (
!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.(MetaTable.STORE))
) {
return;
}
this.log(`upgrade : Getting configuration from meta database`);
@ -46,7 +43,7 @@ export default class NcUpgrader {
const config = await ctx.ncMeta.metaGet(
RootScopes.ROOT,
RootScopes.ROOT,
'nc_store',
MetaTable.STORE,
{
key: this.STORE_KEY,
},
@ -73,7 +70,7 @@ export default class NcUpgrader {
await ctx.ncMeta.metaUpdate(
RootScopes.ROOT,
RootScopes.ROOT,
'nc_store',
MetaTable.STORE,
{
value: JSON.stringify({ version: config.version }),
},
@ -100,7 +97,7 @@ export default class NcUpgrader {
await ctx.ncMeta.metaInsert2(
RootScopes.ROOT,
RootScopes.ROOT,
'nc_store',
MetaTable.STORE,
{
key: NcUpgrader.STORE_KEY,
value: JSON.stringify(configObj),
@ -140,13 +137,6 @@ export default class NcUpgrader {
handler: (ctx?: NcUpgraderCtx) => Promise<void> | void;
}[] {
return [
{ name: '0009000', handler: null },
{ name: '0009044', handler: null },
{ name: '0011043', handler: ncProjectEnvUpgrader },
{ name: '0011045', handler: ncProjectEnvUpgrader0011045 },
{ name: '0090000', handler: ncProjectUpgraderV2_0090000 },
{ name: '0098004', handler: ncDataTypesUpgrader },
{ name: '0098005', handler: ncProjectRolesUpgrader },
{ name: '0100002', handler: ncFilterUpgrader },
{ name: '0101002', handler: ncAttachmentUpgrader },
{ name: '0104002', handler: ncAttachmentUpgrader_0104002 },

14
packages/nocodb/src/version-upgrader/ncDataTypesUpgrader.ts

@ -1,14 +0,0 @@
import { UITypes } from 'nocodb-sdk';
import type { NcUpgraderCtx } from './NcUpgrader';
import { MetaTable } from '~/utils/globals';
// The Count and AutoNumber types are removed
// so convert all existing Count and AutoNumber fields to Number type
export default async function (ctx: NcUpgraderCtx) {
// directly update uidt of all existing Count and AutoNumber fields to Number
await ctx.ncMeta.knex
.update({ uidt: UITypes.Number })
.where({ uidt: UITypes.Count })
.orWhere({ uidt: UITypes.AutoNumber })
.table(MetaTable.COLUMNS);
}

18
packages/nocodb/src/version-upgrader/ncProjectEnvUpgrader.ts

@ -1,18 +0,0 @@
import type { NcUpgraderCtx } from './NcUpgrader';
export default async function (ctx: NcUpgraderCtx) {
const bases = await ctx.ncMeta.baseList();
for (const base of bases) {
const baseConfig = JSON.parse(base.config);
const envVal = baseConfig.envs?.dev;
baseConfig.workingEnv = '_noco';
if (envVal) {
baseConfig.envs._noco = envVal;
delete baseConfig.envs.dev;
}
await ctx.ncMeta.baseUpdate(base?.id, baseConfig);
}
}

11
packages/nocodb/src/version-upgrader/ncProjectEnvUpgrader0011045.ts

@ -1,11 +0,0 @@
import type { NcUpgraderCtx } from './NcUpgrader';
export default async function (ctx: NcUpgraderCtx) {
const bases = await ctx.ncMeta.baseList();
for (const base of bases) {
const baseConfig = JSON.parse(base.config);
baseConfig.env = '_noco';
await ctx.ncMeta.baseUpdate(base?.id, baseConfig);
}
}

47
packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts

@ -1,47 +0,0 @@
import { OrgUserRoles } from 'nocodb-sdk';
import { NC_APP_SETTINGS } from '../constants';
import type { NcUpgraderCtx } from './NcUpgrader';
import Store from '~/models/Store';
import { MetaTable, RootScopes } from '~/utils/globals';
/** Upgrader for upgrading roles */
export default async function ({ ncMeta }: NcUpgraderCtx) {
const users = await ncMeta.metaList2(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.USERS,
);
for (const user of users) {
user.roles = user.roles
.split(',')
.map((r) => {
// update old role names with new roles
if (r === 'user') {
return OrgUserRoles.CREATOR;
} else if (r === 'user-new') {
return OrgUserRoles.VIEWER;
}
return r;
})
.join(',');
await ncMeta.metaUpdate(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.USERS,
{ roles: user.roles },
user.id,
);
}
// set invite only signup if user have environment variable set
if (process.env.NC_INVITE_ONLY_SIGNUP) {
await Store.saveOrUpdate(
{
value: '{ "invite_only_signup": true }',
key: NC_APP_SETTINGS,
},
ncMeta,
);
}
}

1329
packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts

File diff suppressed because it is too large Load Diff

612
packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts

@ -1,612 +0,0 @@
import debug from 'debug';
import { Router } from 'express';
import inflection from 'inflection';
import ncModelsOrderUpgrader from './jobs/ncModelsOrderUpgrader';
import ncParentModelTitleUpgrader from './jobs/ncParentModelTitleUpgrader';
import ncRemoveDuplicatedRelationRows from './jobs/ncRemoveDuplicatedRelationRows';
import type NcProjectBuilder from './NcProjectBuilder';
import type { XKnex } from '~/db/CustomKnex';
import type { BaseModelSql } from '~/db/BaseModelSql';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import type { MysqlClient, PgClient, SqlClient } from 'nc-help';
import type { DbConfig, NcConfig } from '~/interface/config';
import ModelXcMetaFactory from '~/db/sql-mgr/code/models/xc/ModelXcMetaFactory';
import NcConnectionMgr from '~/utils/common/NcConnectionMgr';
import { RootScopes } from '~/utils/globals';
const log = debug('nc:api:source');
export default abstract class BaseApiBuilder<T extends Noco> {
public abstract readonly type: string;
public get knex(): XKnex {
return this.sqlClient?.knex || this.dbDriver;
}
public get prefix() {
return this.baseBuilder?.prefix;
}
public get apiType(): string {
return this.connectionConfig?.meta?.api?.type;
}
public get apiPrefix(): string {
return this.connectionConfig?.meta?.api?.prefix;
}
public get dbAlias(): any {
return this.connectionConfig?.meta?.dbAlias;
}
public get router(): Router {
if (!this.apiRouter) {
this.baseLog(`router : Initializing builder router`);
this.apiRouter = Router();
// (this.app as any).router.use('/', this.apiRouter)
(this.baseBuilder as any).router.use('/', this.apiRouter);
}
return this.apiRouter;
}
public get routeVersionLetter(): string {
return this.connectionConfig?.meta?.api?.prefix || 'v1';
}
protected get baseId(): string {
return this.baseBuilder?.id;
}
public get xcModels() {
return this.models;
}
public get client() {
return this.connectionConfig?.client;
}
public readonly app: T;
public hooks: {
[tableName: string]: {
[key: string]: Array<{
event: string;
url: string;
[key: string]: any;
}>;
};
};
public formViews: {
[tableName: string]: any;
};
protected tablesCount = 0;
protected relationsCount = 0;
protected viewsCount = 0;
protected functionsCount = 0;
protected proceduresCount = 0;
protected baseBuilder: NcProjectBuilder;
protected models: { [key: string]: BaseModelSql };
protected metas: { [key: string]: NcMetaData };
protected sqlClient: MysqlClient | PgClient | SqlClient | any;
protected dbDriver: XKnex;
protected config: NcConfig;
protected connectionConfig: DbConfig;
protected procedureOrFunctionAcls: {
[name: string]: { [role: string]: boolean };
};
protected xcMeta: MetaService;
private apiRouter: Router;
constructor(
app: T,
baseBuilder: NcProjectBuilder,
config: NcConfig,
connectionConfig: DbConfig,
) {
this.models = {};
this.app = app;
this.config = config;
this.connectionConfig = connectionConfig;
this.metas = {};
this.procedureOrFunctionAcls = {};
this.hooks = {};
this.formViews = {};
this.baseBuilder = baseBuilder;
}
public getDbType(): any {
return this.connectionConfig.client;
}
public getDbName(): any {
return (this.connectionConfig.connection as any)?.database;
}
public getDbAlias(): any {
return this.connectionConfig?.meta?.dbAlias;
}
public async getSqlClient() {
return NcConnectionMgr.getSqlClient({
dbAlias: this.dbAlias,
env: this.config.env,
config: this.config,
baseId: this.baseId,
});
}
public async xcUpgrade(): Promise<any> {
const NC_VERSIONS = [
{ name: '0009000', handler: null },
{ name: '0009044', handler: this.ncUpManyToMany.bind(this) },
{ name: '0083006', handler: ncModelsOrderUpgrader },
{ name: '0083007', handler: ncParentModelTitleUpgrader },
{ name: '0083008', handler: ncRemoveDuplicatedRelationRows },
{ name: '0084002', handler: this.ncUpAddNestedResolverArgs.bind(this) },
];
if (!(await this.xcMeta?.knex?.schema?.hasTable?.('nc_store'))) {
return;
}
this.baseLog(`xcUpgrade : Getting configuration from meta database`);
const config = await this.xcMeta.metaGet(
this.baseId,
this.dbAlias,
'nc_store',
{ key: 'NC_CONFIG' },
);
if (config) {
const configObj: NcConfig = JSON.parse(config.value);
if (configObj.version !== process.env.NC_VERSION) {
for (const version of NC_VERSIONS) {
// compare current version and old version
if (version.name > configObj.version) {
this.baseLog(
`xcUpgrade : Upgrading '%s' => '%s'`,
configObj.version,
version.name,
);
await version?.handler?.(<NcBuilderUpgraderCtx>{
xcMeta: this.xcMeta,
builder: this,
dbAlias: this.dbAlias,
baseId: this.baseId,
});
// update version in meta after each upgrade
configObj.version = version.name;
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_store',
{
value: JSON.stringify(configObj),
},
{
key: 'NC_CONFIG',
},
);
// todo: backup data
}
if (version.name === process.env.NC_VERSION) {
break;
}
}
configObj.version = process.env.NC_VERSION;
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_store',
{
value: JSON.stringify(configObj),
},
{
key: 'NC_CONFIG',
},
);
}
} else {
this.baseLog(`xcUpgrade : Inserting config to meta database`);
const configObj: NcConfig = JSON.parse(JSON.stringify(this.config));
delete configObj.envs;
const isOld = (
await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models')
)?.length;
configObj.version = isOld ? '0009000' : process.env.NC_VERSION;
await this.xcMeta.metaInsert2(
context.workspace_id,
context.base_id,
'nc_store',
{
key: 'NC_CONFIG',
value: JSON.stringify(configObj),
dbAlias: this.dbAlias,
},
true,
);
if (isOld) {
await this.xcUpgrade();
}
}
}
public getProjectId(): string {
return this.baseId;
}
public async init(): Promise<void> {
await this.xcUpgrade();
}
protected async initDbDriver(): Promise<void> {
this.dbDriver = await NcConnectionMgr.get({
dbAlias: this.dbAlias,
env: this.config.env,
config: this.config,
baseId: this.baseId,
});
this.sqlClient = await NcConnectionMgr.getSqlClient({
dbAlias: this.dbAlias,
env: this.config.env,
config: this.config,
baseId: this.baseId,
});
}
private baseLog(str, ...args): void {
log(`${this.dbAlias} : ${str}`, ...args);
}
protected generateContextForTable(
tn: string,
columns: any[],
relations,
hasMany: any[],
belongsTo: any[],
type = 'table',
tableNameAlias?: string,
): any {
this.baseLog(`generateContextForTable : '%s' %s`, tn, type);
for (const col of columns) {
col._cn = col._cn || this.getColumnNameAlias(col);
}
// tslint:disable-next-line:variable-name
const _tn = tableNameAlias || this.getTableNameAlias(tn);
const ctx = {
dbType: this.connectionConfig.client,
tn,
_tn,
tn_camelize: inflection.camelize(_tn),
tn_camelize_low: inflection.camelize(_tn, true),
columns,
relations,
hasMany,
belongsTo,
dbAlias: '',
routeVersionLetter: this.routeVersionLetter,
type,
base_id: this.baseId,
};
return ctx;
}
private getColumnNameAlias(col, tableName?: string) {
return (
this.metas?.[tableName]?.columns?.find((c) => c.cn === col.cn)?._cn ||
col._cn ||
this.getInflectedName(col.cn, this.connectionConfig?.meta?.inflection?.cn)
);
}
// table alias functions
protected getInflectedName(_name: string, inflectionFns: string): string {
let name = _name;
if (process.env.NC_INFLECTION) {
inflectionFns = 'camelize';
}
if (inflectionFns && inflectionFns !== 'none') {
name = inflectionFns
.split(',')
.reduce((out, fn) => inflection?.[fn]?.(out) || out, name);
}
return this.apiType === 'graphql' ? name.replace(/[^_\da-z]/gi, '_') : name;
}
protected async ncUpAddNestedResolverArgs(_ctx: any): Promise<any> {}
protected getTableNameAlias(tableName: string) {
let tn = tableName;
if (this.metas?.[tn]?._tn) {
return this.metas?.[tn]?._tn;
}
if (this.baseBuilder?.prefix) {
tn = tn.replace(this.baseBuilder?.prefix, '');
}
const modifiedTableName = tn?.replace(/^(?=\d+)/, 'ISN___');
return this.getInflectedName(
modifiedTableName,
this.connectionConfig?.meta?.inflection?.tn,
);
}
protected async ncUpManyToMany(_ctx: any): Promise<any> {
const models = await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', {
fields: ['meta'],
condition: {
type: 'table',
},
});
if (!models.length) {
return;
}
const metas = [];
// add virtual columns for relations
for (const metaObj of models) {
const meta = JSON.parse(metaObj.meta);
metas.push(meta);
const ctx = this.generateContextForTable(
meta.tn,
meta.columns,
[],
meta.hasMany,
meta.belongsTo,
meta.type,
meta._tn,
);
// generate virtual columns
meta.v = ModelXcMetaFactory.create(this.connectionConfig, {
dir: '',
ctx,
filename: '',
}).getVirtualColumns();
// set default display values
ModelXcMetaFactory.create(
this.connectionConfig,
{},
).mapDefaultDisplayValue(meta.columns);
// update meta
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
meta: JSON.stringify(meta),
},
{ title: meta.tn },
);
}
// generate many to many relations an columns
await this.getManyToManyRelations({ localMetas: metas });
return metas;
}
protected async getManyToManyRelations({
parent = null,
child = null,
localMetas = null,
} = {}): Promise<Set<any>> {
const metas = new Set<any>();
const assocMetas = new Set<any>();
if (localMetas) {
for (const meta of localMetas) {
this.metas[meta.tn] = meta;
}
}
for (const meta of Object.values(this.metas)) {
// check if table is a Bridge table(or Associative Table) by checking
// number of foreign keys and columns
if (meta.belongsTo?.length === 2 && meta.columns.length < 5) {
if (
parent &&
child &&
!(
[parent, child].includes(meta.belongsTo[0].rtn) &&
[parent, child].includes(meta.belongsTo[1].rtn)
)
) {
continue;
}
const tableMetaA = this.metas[meta.belongsTo[0].rtn];
const tableMetaB = this.metas[meta.belongsTo[1].rtn];
/* // remove hasmany relation with associate table from tables
tableMetaA.hasMany.splice(tableMetaA.hasMany.findIndex(hm => hm.tn === meta.tn), 1)
tableMetaB.hasMany.splice(tableMetaB.hasMany.findIndex(hm => hm.tn === meta.tn), 1)*/
// add manytomany data under metadata of both linked tables
tableMetaA.manyToMany = tableMetaA.manyToMany || [];
if (tableMetaA.manyToMany.every((mm) => mm.vtn !== meta.tn)) {
tableMetaA.manyToMany.push({
tn: tableMetaA.tn,
cn: meta.belongsTo[0].rcn,
vtn: meta.tn,
vcn: meta.belongsTo[0].cn,
vrcn: meta.belongsTo[1].cn,
rtn: meta.belongsTo[1].rtn,
rcn: meta.belongsTo[1].rcn,
_tn: tableMetaA._tn,
_cn: meta.belongsTo[0]._rcn,
_rtn: meta.belongsTo[1]._rtn,
_rcn: meta.belongsTo[1]._rcn,
});
metas.add(tableMetaA);
}
// ignore if A & B are same table
if (tableMetaB !== tableMetaA) {
tableMetaB.manyToMany = tableMetaB.manyToMany || [];
if (tableMetaB.manyToMany.every((mm) => mm.vtn !== meta.tn)) {
tableMetaB.manyToMany.push({
tn: tableMetaB.tn,
cn: meta.belongsTo[1].rcn,
vtn: meta.tn,
vcn: meta.belongsTo[1].cn,
vrcn: meta.belongsTo[0].cn,
rtn: meta.belongsTo[0].rtn,
rcn: meta.belongsTo[0].rcn,
_tn: tableMetaB._tn,
_cn: meta.belongsTo[1]._rcn,
_rtn: meta.belongsTo[0]._rtn,
_rcn: meta.belongsTo[0]._rcn,
});
metas.add(tableMetaB);
}
}
assocMetas.add(meta);
}
}
// Update metadata of tables which have manytomany relation
// and recreate basemodel with new meta information
for (const meta of metas) {
let queryParams;
// update showfields on new many to many relation create
if (parent && child) {
try {
queryParams = JSON.parse(
(
await this.xcMeta.metaGet(
this.baseId,
this.dbAlias,
'nc_models',
{ title: meta.tn },
)
).query_params,
);
} catch (e) {
// ignore
}
}
meta.v = [
...meta.v.filter(
(vc) => !(vc.hm && meta.manyToMany.some((mm) => vc.hm.tn === mm.vtn)),
),
// todo: ignore duplicate m2m relations
// todo: optimize, just compare associative table(Vtn)
...meta.manyToMany
.filter(
(v, i) =>
!meta.v.some(
(v1) =>
v1.mm &&
((v1.mm.tn === v.tn && v.rtn === v1.mm.rtn) ||
(v1.mm.rtn === v.tn && v.tn === v1.mm.rtn)) &&
v.vtn === v1.mm.vtn,
) &&
// ignore duplicate
!meta.manyToMany.some(
(v1, i1) =>
i1 !== i &&
v1.tn === v.tn &&
v.rtn === v1.rtn &&
v.vtn === v1.vtn,
),
)
.map((mm) => {
if (
queryParams?.showFields &&
!(`${mm._tn} <=> ${mm._rtn}` in queryParams.showFields)
) {
queryParams.showFields[`${mm._tn} <=> ${mm._rtn}`] = true;
}
return {
mm,
_cn: `${mm._tn} <=> ${mm._rtn}`,
};
}),
];
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
meta: JSON.stringify(meta),
...(queryParams ? { query_params: JSON.stringify(queryParams) } : {}),
},
{ title: meta.tn },
);
// XcCache.del([this.baseId, this.dbAlias, 'table', meta.tn].join('::'));
// if (!localMetas) {
// this.models[meta.tn] = this.getBaseModel(meta);
// }
}
// Update metadata of associative table
for (const meta of assocMetas) {
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
mm: 1,
},
{ title: meta.tn },
);
}
return metas;
}
}
interface NcBuilderUpgraderCtx {
xcMeta: MetaService;
builder: BaseApiBuilder<any>;
baseId: string;
dbAlias: string;
}
interface NcMetaData {
tn: string;
_tn?: string;
v: Array<{
_cn?: string;
[key: string]: any;
}>;
columns: Array<{
_cn?: string;
cn?: string;
uidt?: string;
[key: string]: any;
}>;
[key: string]: any;
}
type XcTablesPopulateParams = {
tableNames?: Array<{
tn: string;
_tn?: string;
}>;
type?: 'table' | 'view' | 'function' | 'procedure';
columns?: {
[tn: string]: any;
};
oldMetas?: {
[tn: string]: NcMetaData;
};
};
export { NcBuilderUpgraderCtx, NcMetaData, XcTablesPopulateParams };

198
packages/nocodb/src/version-upgrader/v1-legacy/NcProjectBuilder.ts

@ -1,198 +0,0 @@
import { Router } from 'express';
import { GqlApiBuilder } from './gql/GqlApiBuilder';
import { RestApiBuilder } from './rest/RestApiBuilder';
import type Noco from '~/Noco';
import type { NcConfig } from '~/interface/config';
import { SqlClientFactory } from '~/db/sql-client/lib/SqlClientFactory';
export default class NcProjectBuilder {
public readonly id: string;
public readonly title: string;
public readonly description: string;
public readonly router: Router;
public readonly apiBuilders: Array<RestApiBuilder | GqlApiBuilder> = [];
private _config: any;
protected startTime;
protected app: Noco;
protected appConfig: NcConfig;
protected apiInfInfoList: any[] = [];
protected aggregatedApiInfo: any;
protected authHook: any;
constructor(app: Noco, appConfig: NcConfig, base: any) {
this.app = app;
this.appConfig = appConfig;
if (base) {
this.id = base.id;
this.title = base.title;
this.description = base.description;
this._config = { ...this.appConfig, ...JSON.parse(base.config) };
this.router = Router();
}
}
public async init(_isFirstTime?: boolean) {
try {
// await this.addAuthHookToMiddleware();
this.startTime = Date.now();
const allRoutesInfo: any[] = [];
// await this.app.ncMeta.baseStatusUpdate(this.id, 'starting');
// await this.syncMigration();
await this._createApiBuilder();
// this.initApiInfoRoute();
/* Create REST APIs / GraphQL Resolvers */
for (const meta of this.apiBuilders) {
let routeInfo;
if (meta instanceof RestApiBuilder) {
console.log(
`Creating REST APIs ${meta.getDbType()} - > ${meta.getDbName()}`,
);
routeInfo = await (meta as RestApiBuilder).init();
} else if (meta instanceof GqlApiBuilder) {
console.log(
`Creating GraphQL APIs ${meta.getDbType()} - > ${meta.getDbName()}`,
);
routeInfo = await (meta as GqlApiBuilder).init();
}
allRoutesInfo.push(routeInfo);
// this.progress(routeInfo, allRoutesInfo, isFirstTime);
}
// this.app.baseRouter.use(`/nc/${this.id}`, this.router);
// await this.app.ncMeta.baseStatusUpdate(this.id, 'started');
} catch (e) {
console.log(e);
throw e;
// await this.app.ncMeta.baseStatusUpdate(this.id, 'stopped');
}
}
protected async _createApiBuilder() {
this.apiBuilders.splice(0, this.apiBuilders.length);
let i = 0;
const connectionConfigs = [];
/* for each db create an api builder */
for (const db of this.config?.envs?.[this.appConfig?.workingEnv]?.db ||
[]) {
let Builder;
switch (db.meta.api.type) {
case 'graphql':
Builder = GqlApiBuilder;
break;
case 'rest':
Builder = RestApiBuilder;
break;
}
if ((db?.connection as any)?.database) {
const connectionConfig = {
...db,
meta: {
...db.meta,
api: {
...db.meta.api,
prefix: db.meta.api.prefix || this.genVer(i),
},
},
};
this.apiBuilders.push(
new Builder(
this.app,
this,
this.config,
connectionConfig,
this.app.ncMeta,
),
);
connectionConfigs.push(connectionConfig);
i++;
} else if (db.meta?.allSchemas) {
/* get all schemas and create APIs for all of them */
const sqlClient = await SqlClientFactory.create({
...db,
connection: { ...db.connection, database: undefined },
});
const schemaList = (await sqlClient.schemaList({}))?.data?.list;
for (const schema of schemaList) {
const connectionConfig = {
...db,
connection: { ...db.connection, database: schema.schema_name },
meta: {
...db.meta,
dbAlias: i ? db.meta.dbAlias + i : db.meta.dbAlias,
api: {
...db.meta.api,
prefix: db.meta.api.prefix || this.genVer(i),
},
},
};
this.apiBuilders.push(
new Builder(
this.app,
this,
this.config,
connectionConfig,
this.app.ncMeta,
),
);
connectionConfigs.push(connectionConfig);
i++;
}
sqlClient.knex.destroy();
}
}
if (this.config?.envs?.[this.appConfig.workingEnv]?.db) {
this.config.envs[this.appConfig.workingEnv].db.splice(
0,
this.config.envs[this.appConfig.workingEnv].db.length,
...connectionConfigs,
);
}
}
protected genVer(i): string {
const l = 'vwxyzabcdefghijklmnopqrstu';
return (
i
.toString(26)
.split('')
.map((v) => l[parseInt(v, 26)])
.join('') + '1'
);
}
protected static triggerGarbageCollect() {
try {
if (global.gc) {
global.gc();
}
} catch (e) {
console.log('`node --expose-gc index.js`');
process.exit();
}
}
public get prefix(): string {
return this.config?.prefix;
}
public get config(): any {
return this._config;
}
public updateConfig(config: string) {
this._config = { ...this.appConfig, ...JSON.parse(config) };
}
}

145
packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts

@ -1,145 +0,0 @@
import { Router } from 'express';
import BaseApiBuilder from '../BaseApiBuilder';
import type NcProjectBuilder from '../NcProjectBuilder';
import type XcMetaMgr from '~/interface/XcMetaMgr';
import type { DbConfig, NcConfig } from '~/interface/config';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import GqlXcSchemaFactory from '~/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory';
export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr {
public readonly type = 'gql';
private readonly gqlRouter: Router;
constructor(
app: Noco,
baseBuilder: NcProjectBuilder,
config: NcConfig,
connectionConfig: DbConfig,
xcMeta?: MetaService,
) {
super(app, baseBuilder, config, connectionConfig);
this.config = config;
this.connectionConfig = connectionConfig;
this.gqlRouter = Router();
this.xcMeta = xcMeta;
}
public async init(): Promise<void> {
await super.init();
}
protected async ncUpAddNestedResolverArgs(_ctx: any): Promise<any> {
const models = await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', {
fields: ['meta'],
condition: {
type: 'table',
},
});
if (!models.length) {
return;
}
// add virtual columns for relations
for (const metaObj of models) {
const meta = JSON.parse(metaObj.meta);
const ctx = this.generateContextForTable(
meta.tn,
meta.columns,
[],
meta.hasMany,
meta.belongsTo,
meta.type,
meta._tn,
);
/* generate gql schema of the table */
const schema = GqlXcSchemaFactory.create(this.connectionConfig, {
dir: '',
ctx: {
...ctx,
manyToMany: meta.manyToMany,
},
filename: '',
}).getString();
/* update schema in metadb */
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
schema,
},
{
title: meta.tn,
type: 'table',
},
);
}
}
protected async ncUpManyToMany(ctx: any): Promise<any> {
const metas = await super.ncUpManyToMany(ctx);
if (!metas) {
return;
}
for (const meta of metas) {
const ctx = this.generateContextForTable(
meta.tn,
meta.columns,
[],
meta.hasMany,
meta.belongsTo,
meta.type,
meta._tn,
);
/* generate gql schema of the table */
const schema = GqlXcSchemaFactory.create(this.connectionConfig, {
dir: '',
ctx: {
...ctx,
manyToMany: meta.manyToMany,
},
filename: '',
}).getString();
/* update schema in metadb */
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
schema,
},
{
title: meta.tn,
type: 'table',
},
);
// todo : add loaders
if (meta.manyToMany) {
for (const mm of meta.manyToMany) {
await this.xcMeta.metaInsert2(
context.workspace_id,
context.base_id,
'nc_loaders',
{
title: `${mm.tn}Mm${mm.rtn}List`,
parent: mm.tn,
child: mm.rtn,
relation: 'mm',
resolver: 'mmlist',
dbAlias: this.dbAlias,
},
true,
);
}
}
}
}
}

38
packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts

@ -1,38 +0,0 @@
import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder';
export default async function (ctx: NcBuilderUpgraderCtx) {
const models = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', {
xcCondition: {
_or: [{ type: { eq: 'table' } }, { type: { eq: 'view' } }],
},
});
let order = 0;
for (const model of models) {
await ctx.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
order: ++order,
view_order: 1,
},
model.id,
);
const views = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', {
condition: { parent_model_title: model.title },
});
let view_order = 1;
for (const view of views) {
await ctx.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{
view_order: ++view_order,
},
view.id,
);
}
}
}

24
packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts

@ -1,24 +0,0 @@
import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder';
export default async function (ctx: NcBuilderUpgraderCtx) {
const views = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', {
condition: {
type: 'vtable',
},
});
for (const view of views) {
await ctx.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_disabled_models_for_role',
{
parent_model_title: view.parent_model_title,
},
{
type: 'vtable',
title: view.title,
},
);
}
}

112
packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts

@ -1,112 +0,0 @@
import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder';
export default async function (ctx: NcBuilderUpgraderCtx) {
try {
const relations = await ctx.xcMeta.metaList2(
context.workspace_id,
context.base_id,
'nc_relations',
);
const duplicates = [];
for (const relation of relations) {
if (relation.type !== 'real' || duplicates.includes(relation)) continue;
const duplicateRelIndex = relations.findIndex(
(rel) =>
rel !== relation &&
rel.tn === relation.tn &&
rel.rtn === relation.rtn &&
rel.cn === relation.cn &&
rel.rcn === relation.rcn &&
rel.type === 'real',
);
if (duplicateRelIndex > -1) duplicates.push(relations[duplicateRelIndex]);
}
// delete relation
for (const dupRelation of duplicates) {
await ctx.xcMeta.metaDeleteAll('nc_relations', {
id: dupRelation.id,
base_id: ctx.baseId,
db_alias: ctx.dbAlias,
});
{
const tnModel = await ctx.xcMeta.metaGet(
ctx.baseId,
ctx.dbAlias,
'nc_models',
{
type: 'table',
title: dupRelation.tn,
},
);
const meta = JSON.parse(tnModel.meta);
const duplicateBts = meta.belongsTo.filter(
(bt) =>
bt.tn === dupRelation.tn &&
bt.rtn === dupRelation.rtn &&
bt.cn === dupRelation.cn &&
bt.rcn === dupRelation.rcn &&
bt.type === 'real',
);
if (duplicateBts?.length > 1) {
meta.belongsTo.splice(meta.belongsTo.indexOf(duplicateBts[1]), 1);
}
await ctx.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{ meta: JSON.stringify(meta) },
{
type: 'table',
title: dupRelation.tn,
},
);
}
{
const rtnModel = await ctx.xcMeta.metaGet(
ctx.baseId,
ctx.dbAlias,
'nc_models',
{
type: 'table',
title: dupRelation.rtn,
},
);
const meta = JSON.parse(rtnModel.meta);
const duplicateHms = meta.hasMany.filter(
(bt) =>
bt.tn === dupRelation.tn &&
bt.rtn === dupRelation.rtn &&
bt.cn === dupRelation.cn &&
bt.rcn === dupRelation.rcn &&
bt.type === 'real',
);
if (duplicateHms?.length > 1) {
meta.hasMany.splice(meta.hasMany.indexOf(duplicateHms[1]), 1);
}
await ctx.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_models',
{ meta: JSON.stringify(meta) },
{
type: 'table',
title: dupRelation.rtn,
},
);
}
}
} catch (e) {
console.log(e);
}
}

176
packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts

@ -1,176 +0,0 @@
import autoBind from 'auto-bind';
import BaseApiBuilder from '../BaseApiBuilder';
import type NcProjectBuilder from '../NcProjectBuilder';
import type { Router } from 'express';
import type { DbConfig, NcConfig } from '~/interface/config';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import NcHelp from '~/utils/NcHelp';
import ExpressXcTsRoutes from '~/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes';
import SwaggerXc from '~/db/sql-mgr/code/routers/xc-ts/SwaggerXc';
export class RestApiBuilder extends BaseApiBuilder<Noco> {
public readonly type = 'rest';
protected nocoTypes: any;
protected nocoRootResolvers: any;
private routers: { [key: string]: Router };
constructor(
app: Noco,
baseBuilder: NcProjectBuilder,
config: NcConfig,
connectionConfig: DbConfig,
xcMeta?: MetaService,
) {
super(app, baseBuilder, config, connectionConfig);
autoBind(this);
this.routers = {};
this.hooks = {};
this.xcMeta = xcMeta;
}
public async init(): Promise<void> {
await super.init();
}
protected async ncUpManyToMany(ctx: any): Promise<any> {
const metas = await super.ncUpManyToMany(ctx);
if (!metas) {
return;
}
for (const meta of metas) {
const ctx = this.generateContextForTable(
meta.tn,
meta.columns,
[],
meta.hasMany,
meta.belongsTo,
meta.type,
meta._tn,
);
/* create routes for table */
const routes = new ExpressXcTsRoutes({
dir: '',
ctx,
filename: '',
}).getObjectWithoutFunctions();
/* create nc_routes, add new routes or update order */
const routesInsertion = routes.map((route, i) => {
return async () => {
if (
!(await this.xcMeta.metaGet(
this.baseId,
this.dbAlias,
'nc_routes',
{
path: route.path,
tn: meta.tn,
title: meta.tn,
type: route.type,
},
))
) {
await this.xcMeta.metaInsert2(
context.workspace_id,
context.base_id,
'nc_routes',
{
acl: JSON.stringify(route.acl),
handler: JSON.stringify(route.handler),
order: i,
path: route.path,
tn: meta.tn,
title: meta.tn,
type: route.type,
dbAlias: this.dbAlias,
},
true,
);
} else {
await this.xcMeta.metaUpdate(
context.workspace_id,
context.base_id,
'nc_routes',
{
order: i,
},
{
path: route.path,
tn: meta.tn,
title: meta.tn,
type: route.type,
},
);
}
};
});
await NcHelp.executeOperations(
routesInsertion,
this.connectionConfig.client,
);
}
// add new routes
}
protected async getManyToManyRelations(args = {}): Promise<Set<any>> {
const metas: Set<any> = 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.baseId,
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(
context.workspace_id,
context.base_id,
'nc_models',
{
schema: JSON.stringify(oldSwaggerDoc),
// schema_previous: JSON.stringify(previousSchemas)
},
{
title: metaObj.tn,
type: 'table',
},
);
}
return metas;
}
}

253
packages/nocodb/src/version-upgrader/v1-legacy/templates/NcTemplateParser.ts

@ -1,253 +0,0 @@
import { SqlUiFactory, UITypes } from 'nocodb-sdk';
import type { MssqlUi, MysqlUi, OracleUi, PgUi, SqliteUi } from 'nocodb-sdk';
export default class NcTemplateParser {
sqlUi:
| typeof MysqlUi
| typeof MssqlUi
| typeof PgUi
| typeof OracleUi
| 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, 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;
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 tableTemplates) {
this.extractRelations(tableTemplate);
this.extractVirtualColumns(tableTemplate);
}
}
private extractTable(tableTemplate) {
if (!tableTemplate?.tn) {
throw Error('Missing table name in template');
}
const defaultColumns = this.sqlUi
.getNewTableColumns()
.filter(
(column) =>
column.cn !== 'title' &&
(column.uidt !== 'ID' ||
tableTemplate.columns.every((c) => c.uidt !== 'ID')),
);
return {
tn: tableTemplate.tn,
_tn: tableTemplate._tn,
columns: [
defaultColumns[0],
...this.extractTableColumns(tableTemplate.columns),
...defaultColumns.slice(1),
],
};
}
private extractTableColumns(tableColumns: any[]) {
const columns = [];
for (const tableColumn of tableColumns) {
if (!tableColumn?.cn) {
throw Error('Missing column name in template');
}
switch (tableColumn.uidt) {
// case UITypes.ForeignKey:
// // todo :
// this.extractRelations(tableColumn, 'bt');
// break;
// case UITypes.LinkToAnotherRecord:
// // todo :
// this.extractRelations(tableColumn, 'hm');
// // 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),
...colProp,
_cn: tableColumn.cn,
...tableColumn,
});
}
break;
}
}
return columns;
}
protected extractRelations(tableTemplate) {
if (!this._relations) this._relations = [];
if (!this._m2mRelations) this._m2mRelations = [];
for (const hasMany of tableTemplate.hasMany || []) {
const childTable = this.tables.find(
(table) => table.tn === this.getTable(hasMany.tn),
);
const parentTable = this.tables.find(
(table) => table.tn === tableTemplate.tn,
);
const parentPrimaryColumn = parentTable.columns.find(
(column) => column.uidt === UITypes.ID,
);
//
// // if duplicate relation ignore
// if (
// this._relations.some(rl => {
// return (
// (rl.childTable === childTable.tn &&
// rl.parentTable === parentTable.tn) ||
// (rl.parentTable === childTable.tn &&
// rl.childTable === parentTable.tn)
// );
// })
// ) {
// continue;f
// }
// add a column in child table
const childColumnName = `${tableTemplate.tn}_id`;
childTable.columns.push({
column_name: childColumnName,
_cn: childColumnName,
rqd: false,
pk: false,
ai: false,
cdf: null,
dt: parentPrimaryColumn.dt,
dtxp: parentPrimaryColumn.dtxp,
dtxs: parentPrimaryColumn.dtxs,
un: parentPrimaryColumn.un,
altered: 1,
});
// add relation create entry
this._relations.push({
childColumn: childColumnName,
childTable: childTable.tn,
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
parentColumn: parentPrimaryColumn.cn,
parentTable: tableTemplate.tn,
type: this.client === 'sqlite3' ? 'virtual' : 'real',
updateRelation: false,
});
}
for (const manyToMany of tableTemplate.manyToMany || []) {
// @ts-ignore
const childTable = this.tables.find(
(table) => table.tn === this.getTable(manyToMany.rtn),
);
const parentTable = this.tables.find(
(table) => table.tn === tableTemplate.tn,
);
const parentPrimaryColumn = parentTable.columns.find(
(column) => column.uidt === UITypes.ID,
);
const childPrimaryColumn = childTable.columns.find(
(column) => column.uidt === UITypes.ID,
);
// if duplicate relation ignore
if (
this._m2mRelations.some((mm) => {
return (
(mm.childTable === childTable.tn &&
mm.parentTable === parentTable.tn) ||
(mm.parentTable === childTable.tn &&
mm.childTable === parentTable.tn)
);
})
) {
continue;
}
// add many to many relation create entry
this._m2mRelations.push({
alias: 'title8',
childColumn: childPrimaryColumn.cn,
childTable: childTable.tn,
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
parentColumn: parentPrimaryColumn.cn,
parentTable: parentTable.tn,
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 };
if (v.rl) {
v1.rl.rlttn = v1.rl.rltn;
v1.rl.rltn = this.getTable(v1.rl.rltn);
} else if (v.lk) {
v1.lk._ltn = v1.lk.ltn;
v1.lk.ltn = this.getTable(v1.lk.ltn);
}
virtualColumns.push(v1);
}
this.virtualColumns[tableMeta.tn] = virtualColumns;
}
get tables(): any[] {
return this._tables;
}
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