Browse Source

feat: project create api (WIP)

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/5444/head
Pranav C 2 years ago
parent
commit
e984133c0c
  1. 4
      packages/nocodb-nest/src/app.module.ts
  2. 10
      packages/nocodb-nest/src/auth/auth.module.ts
  3. 2
      packages/nocodb-nest/src/helpers/apiHelpers.ts
  4. 12
      packages/nocodb-nest/src/helpers/columnHelpers.ts
  5. 164
      packages/nocodb-nest/src/helpers/populateMeta.ts
  6. 3
      packages/nocodb-nest/src/projects/projects.controller.ts

4
packages/nocodb-nest/src/app.module.ts

@ -3,10 +3,10 @@ import { Connection } from './connection/connection';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module'; import { UsersModule } from './users/users.module';
import { MetaService } from './meta/meta.service'; import { MetaService } from './meta/meta.service';
import { LocalStrategy } from './local.strategy/local.strategy'; import { LocalStrategy } from './strategies/local.strategy';
import { UtilsModule } from './utils/utils.module'; import { UtilsModule } from './utils/utils.module';
import { ProjectsModule } from './projects/projects.module'; import { ProjectsModule } from './projects/projects.module';
import { JwtStrategy } from './strategies/jwt.strategy/jwt.strategy'; import { JwtStrategy } from './strategies/jwt.strategy';
@Module({ @Module({
imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule], imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule],

10
packages/nocodb-nest/src/auth/auth.module.ts

@ -1,16 +1,16 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { LocalStrategy } from '../local.strategy/local.strategy' import { LocalStrategy } from '../strategies/local.strategy';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { AuthController } from './auth.controller'; import { AuthController } from './auth.controller';
import { UsersModule } from "../users/users.module"; import { UsersModule } from '../users/users.module';
import { JwtModule } from "@nestjs/jwt"; import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { jwtConstants } from "./constants"; import { jwtConstants } from './constants';
@Module({ @Module({
controllers: [AuthController], controllers: [AuthController],
imports:[ imports: [
UsersModule, UsersModule,
PassportModule, PassportModule,
JwtModule.register({ JwtModule.register({

2
packages/nocodb-nest/src/helpers/apiHelpers.ts

@ -2,7 +2,7 @@ import Ajv from 'ajv';
import addFormats from 'ajv-formats'; import addFormats from 'ajv-formats';
// @ts-ignore // @ts-ignore
import swagger from '../../../../schema/swagger.json'; import swagger from '../../../../schema/swagger.json';
import { NcError } from '../../helpers/catchError'; import { NcError } from '../helpers/catchError';
import type { ErrorObject } from 'ajv'; import type { ErrorObject } from 'ajv';
import type { NextFunction, Request, Response } from 'express'; import type { NextFunction, Request, Response } from 'express';

12
packages/nocodb-nest/src/helpers/columnHelpers.ts

@ -1,8 +1,8 @@
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import { UITypes } from 'nocodb-sdk'; import { UITypes } from 'nocodb-sdk';
import Column from '../../../models/Column'; import Column from '../models/Column';
import { getUniqueColumnAliasName } from '../../helpers/getUniqueName'; import { getUniqueColumnAliasName } from '../helpers/getUniqueName';
import validateParams from '../../helpers/validateParams'; import validateParams from '../helpers/validateParams';
import type { import type {
BoolType, BoolType,
ColumnReqType, ColumnReqType,
@ -12,9 +12,9 @@ import type {
RollupColumnReqType, RollupColumnReqType,
TableType, TableType,
} from 'nocodb-sdk'; } from 'nocodb-sdk';
import type LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; import type LinkToAnotherRecordColumn from '../models/LinkToAnotherRecordColumn';
import type LookupColumn from '../../../models/LookupColumn'; import type LookupColumn from '../models/LookupColumn';
import type Model from '../../../models/Model'; import type Model from '../models/Model';
export const randomID = customAlphabet( export const randomID = customAlphabet(
'1234567890abcdefghijklmnopqrstuvwxyz_', '1234567890abcdefghijklmnopqrstuvwxyz_',

164
packages/nocodb-nest/src/helpers/populateMeta.ts

@ -1,6 +1,8 @@
import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk'; import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk';
import { isVirtualCol, RelationTypes } from '../../../nocodb-sdk'
import Column from '../models/Column'; import Column from '../models/Column';
import Model from '../models/Model'; import Model from '../models/Model';
import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2'
import NcHelp from '../utils/NcHelp'; import NcHelp from '../utils/NcHelp';
import View from '../models/View'; import View from '../models/View';
import getTableNameAlias, { import getTableNameAlias, {
@ -8,11 +10,167 @@ import getTableNameAlias, {
} from '../helpers/getTableName'; } from '../helpers/getTableName';
import getColumnUiType from '../helpers/getColumnUiType'; import getColumnUiType from '../helpers/getColumnUiType';
import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue'; import mapDefaultDisplayValue from '../helpers/mapDefaultDisplayValue';
import { extractAndGenerateManyToManyRelations } from '../../services/metaDiff.svc'; import type LinkToAnotherRecordColumn from '../models/LinkToAnotherRecordColumn';
import { IGNORE_TABLES } from '../utils/common/BaseApiBuilder';
import type LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn';
import type Base from '../models/Base'; import type Base from '../models/Base';
import type Project from '../models/Project'; import type Project from '../models/Project';
import { getUniqueColumnAliasName } from './getUniqueName'
export const IGNORE_TABLES = [
'nc_models',
'nc_roles',
'nc_routes',
'nc_loaders',
'nc_resolvers',
'nc_hooks',
'nc_store',
'_evolutions',
'nc_evolutions',
'xc_users',
'nc_rpc',
'nc_acl',
'nc_cron',
'nc_disabled_models_for_role',
'nc_audit',
'xc_knex_migrations',
'xc_knex_migrations_lock',
'nc_plugins',
'nc_migrations',
'nc_api_tokens',
'nc_projects',
'nc_projects_users',
'nc_relations',
'nc_shared_views',
];
async function isMMRelationExist(
model: Model,
assocModel: Model,
belongsToCol: Column<LinkToAnotherRecordColumn>
) {
let isExist = false;
const colChildOpt =
await belongsToCol.getColOptions<LinkToAnotherRecordColumn>();
for (const col of await model.getColumns()) {
if (col.uidt === UITypes.LinkToAnotherRecord) {
const colOpt = await col.getColOptions<LinkToAnotherRecordColumn>();
if (
colOpt &&
colOpt.type === RelationTypes.MANY_TO_MANY &&
colOpt.fk_mm_model_id === assocModel.id &&
colOpt.fk_child_column_id === colChildOpt.fk_parent_column_id &&
colOpt.fk_mm_child_column_id === colChildOpt.fk_child_column_id
) {
isExist = true;
break;
}
}
}
return isExist;
}
// @ts-ignore
export async function extractAndGenerateManyToManyRelations(
modelsArr: Array<Model>
) {
for (const assocModel of modelsArr) {
await assocModel.getColumns();
// check if table is a Bridge table(or Associative Table) by checking
// number of foreign keys and columns
const normalColumns = assocModel.columns.filter((c) => !isVirtualCol(c));
const belongsToCols: Column<LinkToAnotherRecordColumn>[] = [];
for (const col of assocModel.columns) {
if (col.uidt == UITypes.LinkToAnotherRecord) {
const colOpt = await col.getColOptions<LinkToAnotherRecordColumn>();
if (colOpt?.type === RelationTypes.BELONGS_TO) belongsToCols.push(col);
}
}
// todo: impl better method to identify m2m relation
if (belongsToCols?.length === 2 && normalColumns.length < 5) {
const modelA = await belongsToCols[0].colOptions.getRelatedTable();
const modelB = await belongsToCols[1].colOptions.getRelatedTable();
await modelA.getColumns();
await modelB.getColumns();
// check tableA already have the relation or not
const isRelationAvailInA = await isMMRelationExist(
modelA,
assocModel,
belongsToCols[0]
);
const isRelationAvailInB = await isMMRelationExist(
modelB,
assocModel,
belongsToCols[1]
);
if (!isRelationAvailInA) {
await Column.insert<LinkToAnotherRecordColumn>({
title: getUniqueColumnAliasName(
modelA.columns,
`${modelB.title} List`
),
fk_model_id: modelA.id,
fk_related_model_id: modelB.id,
fk_mm_model_id: assocModel.id,
fk_child_column_id: belongsToCols[0].colOptions.fk_parent_column_id,
fk_parent_column_id: belongsToCols[1].colOptions.fk_parent_column_id,
fk_mm_child_column_id: belongsToCols[0].colOptions.fk_child_column_id,
fk_mm_parent_column_id:
belongsToCols[1].colOptions.fk_child_column_id,
type: RelationTypes.MANY_TO_MANY,
uidt: UITypes.LinkToAnotherRecord,
});
}
if (!isRelationAvailInB) {
await Column.insert<LinkToAnotherRecordColumn>({
title: getUniqueColumnAliasName(
modelB.columns,
`${modelA.title} List`
),
fk_model_id: modelB.id,
fk_related_model_id: modelA.id,
fk_mm_model_id: assocModel.id,
fk_child_column_id: belongsToCols[1].colOptions.fk_parent_column_id,
fk_parent_column_id: belongsToCols[0].colOptions.fk_parent_column_id,
fk_mm_child_column_id: belongsToCols[1].colOptions.fk_child_column_id,
fk_mm_parent_column_id:
belongsToCols[0].colOptions.fk_child_column_id,
type: RelationTypes.MANY_TO_MANY,
uidt: UITypes.LinkToAnotherRecord,
});
}
await Model.markAsMmTable(assocModel.id, true);
// mark has many relation associated with mm as system field in both table
for (const btCol of [belongsToCols[0], belongsToCols[1]]) {
const colOpt = await btCol.colOptions;
const model = await colOpt.getRelatedTable();
for (const col of await model.getColumns()) {
if (col.uidt !== UITypes.LinkToAnotherRecord) continue;
const colOpt1 = await col.getColOptions<LinkToAnotherRecordColumn>();
if (!colOpt1 || colOpt1.type !== RelationTypes.HAS_MANY) continue;
if (
colOpt1.fk_child_column_id !== colOpt.fk_child_column_id ||
colOpt1.fk_parent_column_id !== colOpt.fk_parent_column_id
)
continue;
await Column.markAsSystemField(col.id);
break;
}
}
} else {
if (assocModel.mm) await Model.markAsMmTable(assocModel.id, false);
}
}
}
export async function populateMeta(base: Base, project: Project): Promise<any> { export async function populateMeta(base: Base, project: Project): Promise<any> {
const info = { const info = {

3
packages/nocodb-nest/src/projects/projects.controller.ts

@ -1,6 +1,7 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Request, UseGuards } from '@nestjs/common' import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Request, UseGuards } from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import isDocker from 'is-docker' import isDocker from 'is-docker'
import { ProjectReqType } from 'nocodb-sdk'
import Noco from '../Noco' import Noco from '../Noco'
import { packageVersion } from '../utils/packageVersion' import { packageVersion } from '../utils/packageVersion'
import { ProjectsService } from './projects.service'; import { ProjectsService } from './projects.service';
@ -79,7 +80,7 @@ export class ProjectsController {
@Post( @Post(
'/api/v1/db/meta/projects' '/api/v1/db/meta/projects'
) )
async projectCreate(@Body() projectBody: Record<string, any>, @Request() req){ async projectCreate(@Body() projectBody: ProjectReqType, @Request() req){
const project = await this.projectsService.projectCreate({ const project = await this.projectsService.projectCreate({
project: projectBody, project: projectBody,
user: req['user'], user: req['user'],

Loading…
Cancel
Save