mirror of https://github.com/nocodb/nocodb
Pranav C
2 years ago
3 changed files with 609 additions and 0 deletions
@ -0,0 +1,258 @@
|
||||
import { Request, Response, Router } from 'express'; |
||||
import ncMetaAclMw from '../../meta/helpers/ncMetaAclMw'; |
||||
import apiMetrics from '../../meta/helpers/apiMetrics'; |
||||
import { parseHrtimeToSeconds } from '../../meta/api/helpers'; |
||||
|
||||
import { dataService } from '../../services'; |
||||
|
||||
// todo: Handle the error case where view doesnt belong to model
|
||||
async function dataList(req: Request, res: Response) { |
||||
const startTime = process.hrtime(); |
||||
const responseData = await dataService.dataList({ |
||||
query: req.query, |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
}); |
||||
const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); |
||||
res.setHeader('xc-db-response', elapsedSeconds); |
||||
res.json(responseData); |
||||
} |
||||
|
||||
async function dataFindOne(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataFindOne({ |
||||
query: req.query, |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dataGroupBy(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataFindOne({ |
||||
query: req.query, |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dataCount(req: Request, res: Response) { |
||||
const count = await dataService.dataCount({ |
||||
query: req.query, |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
}); |
||||
|
||||
res.json({ count }); |
||||
} |
||||
|
||||
async function dataInsert(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataInsert({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
body: req.body, |
||||
cookie: req, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dataUpdate(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataUpdate({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
body: req.body, |
||||
cookie: req, |
||||
rowId: req.params.rowId, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dataDelete(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataDelete({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
cookie: req, |
||||
rowId: req.params.rowId, |
||||
}) |
||||
); |
||||
} |
||||
|
||||
async function dataRead(req: Request, res: Response) { |
||||
res.json( |
||||
await dataService.dataRead({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
rowId: req.params.rowId, |
||||
query: req.query, |
||||
}) |
||||
} |
||||
|
||||
async function dataExist(req: Request, res: Response) { |
||||
res.json(await dataService.dataExist({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
rowId: req.params.rowId, |
||||
query: req.query, |
||||
})); |
||||
} |
||||
|
||||
// todo: Handle the error case where view doesnt belong to model
|
||||
async function groupedDataList(req: Request, res: Response) { |
||||
const startTime = process.hrtime(); |
||||
const groupedData = await dataService.groupedDataList({ |
||||
projectName: req.params.projectName, |
||||
tableName: req.params.tableName, |
||||
viewName: req.params.viewName, |
||||
query: req.query, |
||||
columnId: req.params.columnId |
||||
}); |
||||
const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); |
||||
res.setHeader('xc-db-response', elapsedSeconds); |
||||
res.json(groupedData); |
||||
} |
||||
|
||||
const router = Router({ mergeParams: true }); |
||||
|
||||
// table data crud apis
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataList, 'dataList') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/find-one', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataFindOne, 'dataFindOne') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/groupby', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataGroupBy, 'dataGroupBy') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/group/:columnId', |
||||
apiMetrics, |
||||
ncMetaAclMw(groupedDataList, 'groupedDataList') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/exist', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataExist, 'dataExist') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/count', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataCount, 'dataCount') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/count', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataCount, 'dataCount') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataRead, 'dataRead') |
||||
); |
||||
|
||||
router.patch( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataUpdate, 'dataUpdate') |
||||
); |
||||
|
||||
router.delete( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataDelete, 'dataDelete') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataList, 'dataList') |
||||
); |
||||
|
||||
// table view data crud apis
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataList, 'dataList') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/find-one', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataFindOne, 'dataFindOne') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/groupby', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataGroupBy, 'dataGroupBy') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/group/:columnId', |
||||
apiMetrics, |
||||
ncMetaAclMw(groupedDataList, 'groupedDataList') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId/exist', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataExist, 'dataExist') |
||||
); |
||||
|
||||
router.post( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataInsert, 'dataInsert') |
||||
); |
||||
|
||||
router.post( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataInsert, 'dataInsert') |
||||
); |
||||
|
||||
router.patch( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataUpdate, 'dataUpdate') |
||||
); |
||||
|
||||
router.get( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataRead, 'dataRead') |
||||
); |
||||
|
||||
router.delete( |
||||
'/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/:rowId', |
||||
apiMetrics, |
||||
ncMetaAclMw(dataDelete, 'dataDelete') |
||||
); |
||||
|
||||
export default router; |
@ -0,0 +1,350 @@
|
||||
import { nocoExecute } from 'nc-help/dist/module/NocoExecute'; |
||||
import getAst from '../../db/sql-data-mapper/lib/sql/helpers/getAst'; |
||||
import { NcError } from '../../meta/helpers/catchError'; |
||||
import { PagedResponseImpl } from '../../meta/helpers/PagedResponse'; |
||||
import { Base, Model, View } from '../../models'; |
||||
import Project from '../../models/Project'; |
||||
import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2'; |
||||
|
||||
interface PathParams { |
||||
projectName: string; |
||||
tableName: string; |
||||
viewName: string; |
||||
} |
||||
|
||||
export async function dataList(param: PathParams & { query: any }) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
const responseData = await getDataList({ model, view, query: param.query }); |
||||
return responseData; |
||||
} |
||||
|
||||
export async function dataFindOne(param: PathParams & { query: any }) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
return await getFindOne({ model, view, query: param.query }); |
||||
} |
||||
|
||||
export async function dataGroupBy(param: PathParams & { query: any }) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
await getDataGroupBy({ model, view, query: param.query }); |
||||
} |
||||
|
||||
export async function dataCount(param: PathParams & { query: any }) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const countArgs: any = { ...param.query }; |
||||
try { |
||||
countArgs.filterArr = JSON.parse(countArgs.filterArrJson); |
||||
} catch (e) {} |
||||
|
||||
const count: number = await baseModel.count(countArgs); |
||||
|
||||
return { count }; |
||||
} |
||||
|
||||
export async function dataInsert( |
||||
param: PathParams & { body: unknown; cookie: any } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
await baseModel.insert(param.body, null, param.cookie); |
||||
} |
||||
|
||||
export async function dataUpdate( |
||||
param: PathParams & { body: unknown; cookie: any; rowId: string } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
return await baseModel.updateByPk( |
||||
param.rowId, |
||||
param.body, |
||||
null, |
||||
param.cookie |
||||
); |
||||
} |
||||
|
||||
export async function dataDelete( |
||||
param: PathParams & { rowId: string; cookie: any } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
const base = await Base.get(model.base_id); |
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
// todo: Should have error http status code
|
||||
const message = await baseModel.hasLTARData(param.rowId, model); |
||||
if (message.length) { |
||||
return { message }; |
||||
} |
||||
return await baseModel.delByPk(param.rowId, null, param.cookie); |
||||
} |
||||
|
||||
export async function getDataList(param: { |
||||
model: Model; |
||||
view: View; |
||||
query: any; |
||||
}) { |
||||
const { model, view, query = {} } = param; |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const requestObj = await getAst({ model, query, view }); |
||||
|
||||
const listArgs: any = { ...query }; |
||||
try { |
||||
listArgs.filterArr = JSON.parse(listArgs.filterArrJson); |
||||
} catch (e) {} |
||||
try { |
||||
listArgs.sortArr = JSON.parse(listArgs.sortArrJson); |
||||
} catch (e) {} |
||||
|
||||
let data = []; |
||||
let count = 0; |
||||
try { |
||||
data = await nocoExecute( |
||||
requestObj, |
||||
await baseModel.list(listArgs), |
||||
{}, |
||||
listArgs |
||||
); |
||||
count = await baseModel.count(listArgs); |
||||
} catch (e) { |
||||
console.log(e); |
||||
NcError.internalServerError( |
||||
'Internal Server Error, check server log for more details' |
||||
); |
||||
} |
||||
|
||||
return new PagedResponseImpl(data, { |
||||
...query, |
||||
count, |
||||
}); |
||||
} |
||||
|
||||
export async function getFindOne(param: { |
||||
model: Model; |
||||
view: View; |
||||
query: any; |
||||
}) { |
||||
const { model, view, query = {} } = param; |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const args: any = { ...query }; |
||||
try { |
||||
args.filterArr = JSON.parse(args.filterArrJson); |
||||
} catch (e) {} |
||||
try { |
||||
args.sortArr = JSON.parse(args.sortArrJson); |
||||
} catch (e) {} |
||||
|
||||
const data = await baseModel.findOne(args); |
||||
return data |
||||
? await nocoExecute( |
||||
await getAst({ model, query: args, view }), |
||||
data, |
||||
{}, |
||||
{} |
||||
) |
||||
: {}; |
||||
} |
||||
|
||||
export async function getDataGroupBy(param: { |
||||
model: Model; |
||||
view: View; |
||||
query?: any; |
||||
}) { |
||||
const { model, view, query = {} } = param; |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const listArgs: any = { ...query }; |
||||
const data = await baseModel.groupBy({ ...query }); |
||||
const count = await baseModel.count(listArgs); |
||||
|
||||
return new PagedResponseImpl(data, { |
||||
...query, |
||||
count, |
||||
}); |
||||
} |
||||
|
||||
export async function dataRead( |
||||
param: PathParams & { query: any; rowId: string } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const row = await baseModel.readByPk(param.rowId); |
||||
|
||||
if (!row) { |
||||
NcError.notFound(); |
||||
} |
||||
|
||||
return await nocoExecute( |
||||
await getAst({ model, query: param.query, view }), |
||||
row, |
||||
{}, |
||||
param.query |
||||
); |
||||
} |
||||
|
||||
export async function dataExist( |
||||
param: PathParams & { rowId: string; query: any } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
await baseModel.exist(param.rowId); |
||||
} |
||||
|
||||
// todo: Handle the error case where view doesnt belong to model
|
||||
export async function groupedDataList( |
||||
param: PathParams & { query: any; columnId: string } |
||||
) { |
||||
const { model, view } = await getViewAndModelByAliasOrId(param); |
||||
const groupedData = await getGroupedDataList({ |
||||
model, |
||||
view, |
||||
query: param.query, |
||||
columnId: param.columnId, |
||||
}); |
||||
return groupedData; |
||||
} |
||||
|
||||
export async function getGroupedDataList(param: { |
||||
model; |
||||
view: View; |
||||
query: any; |
||||
columnId: string; |
||||
}) { |
||||
const { model, view, query = {} } = param; |
||||
|
||||
const base = await Base.get(model.base_id); |
||||
|
||||
const baseModel = await Model.getBaseModelSQL({ |
||||
id: model.id, |
||||
viewId: view?.id, |
||||
dbDriver: NcConnectionMgrv2.get(base), |
||||
}); |
||||
|
||||
const requestObj = await getAst({ model, query, view }); |
||||
|
||||
const listArgs: any = { ...query }; |
||||
try { |
||||
listArgs.filterArr = JSON.parse(listArgs.filterArrJson); |
||||
} catch (e) {} |
||||
try { |
||||
listArgs.sortArr = JSON.parse(listArgs.sortArrJson); |
||||
} catch (e) {} |
||||
try { |
||||
listArgs.options = JSON.parse(listArgs.optionsArrJson); |
||||
} catch (e) {} |
||||
|
||||
let data = []; |
||||
|
||||
const groupedData = await baseModel.groupedList({ |
||||
...listArgs, |
||||
groupColumnId: param.columnId, |
||||
}); |
||||
data = await nocoExecute( |
||||
{ key: 1, value: requestObj }, |
||||
groupedData, |
||||
{}, |
||||
listArgs |
||||
); |
||||
const countArr = await baseModel.groupedListCount({ |
||||
...listArgs, |
||||
groupColumnId: param.columnId, |
||||
}); |
||||
data = data.map((item) => { |
||||
// todo: use map to avoid loop
|
||||
const count = |
||||
countArr.find((countItem: any) => countItem.key === item.key)?.count ?? 0; |
||||
|
||||
item.value = new PagedResponseImpl(item.value, { |
||||
...query, |
||||
count: count, |
||||
}); |
||||
return item; |
||||
}); |
||||
|
||||
return data; |
||||
} |
||||
|
||||
export async function getViewAndModelByAliasOrId(param: { |
||||
projectName: string; |
||||
tableName: string; |
||||
viewName?: string; |
||||
}) { |
||||
const project = await Project.getWithInfoByTitleOrId(param.projectName); |
||||
|
||||
const model = await Model.getByAliasOrId({ |
||||
project_id: project.id, |
||||
aliasOrId: param.tableName, |
||||
}); |
||||
const view = |
||||
param.viewName && |
||||
(await View.getByTitleOrId({ |
||||
titleOrId: param.viewName, |
||||
fk_model_id: model.id, |
||||
})); |
||||
if (!model) NcError.notFound('Table not found'); |
||||
return { model, view }; |
||||
} |
Loading…
Reference in new issue