Browse Source

feat(nocodb): new apis

pull/7611/head
DarkPhoenix2704 9 months ago
parent
commit
9d720c0d78
  1. 24
      packages/nocodb/src/controllers/data-alias.controller.ts
  2. 67
      packages/nocodb/src/db/BaseModelSqlv2.ts
  3. 23
      packages/nocodb/src/helpers/getAst.ts
  4. 95
      packages/nocodb/src/schema/swagger.json
  5. 49
      packages/nocodb/src/services/datas.service.ts

24
packages/nocodb/src/controllers/data-alias.controller.ts

@ -117,6 +117,30 @@ export class DataAliasController {
res.json(countResult); res.json(countResult);
} }
@Get([
'/api/v1/db/data/:orgs/:baseName/:tableName/countByDate/',
'/api/v1/db/data/:orgs/:baseName/:tableName/views/:viewName/countByDate/',
])
@Acl('dataList')
async calendarDataCount(
@Req() req: Request,
@Res() res: Response,
@Param('baseName') baseName: string,
@Param('tableName') tableName: string,
@Param('viewName') viewName: string,
) {
const startTime = process.hrtime();
const data = await this.datasService.getCalendarRecordCount({
query: req.query,
viewId: viewName,
});
const elapsedSeconds = parseHrtimeToMilliSeconds(process.hrtime(startTime));
res.setHeader('xc-db-response', elapsedSeconds);
res.json(data);
}
@Post([ @Post([
'/api/v1/db/data/:orgs/:baseName/:tableName', '/api/v1/db/data/:orgs/:baseName/:tableName',
'/api/v1/db/data/:orgs/:baseName/:tableName/views/:viewName', '/api/v1/db/data/:orgs/:baseName/:tableName/views/:viewName',

67
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -21,7 +21,7 @@ import { customAlphabet } from 'nanoid';
import DOMPurify from 'isomorphic-dompurify'; import DOMPurify from 'isomorphic-dompurify';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import type { SortType } from 'nocodb-sdk'; import type { CalendarRangeType, SortType } from 'nocodb-sdk';
import type { Knex } from 'knex'; import type { Knex } from 'knex';
import type LookupColumn from '~/models/LookupColumn'; import type LookupColumn from '~/models/LookupColumn';
import type { XKnex } from '~/db/CustomKnex'; import type { XKnex } from '~/db/CustomKnex';
@ -251,6 +251,71 @@ class BaseModelSqlv2 {
return !!(await this.execAndParse(qb, null, { raw: true, first: true })); return !!(await this.execAndParse(qb, null, { raw: true, first: true }));
} }
public async countByRanges({
ranges,
model,
filterArr,
}: {
ranges: Partial<CalendarRangeType>[];
model: Model;
filterArr?: Filter[];
}) {
const columns = await model.getColumns();
const queryRanges = [];
for (const range of ranges) {
let query;
if (range?.fk_from_column_id && range?.fk_to_column_id) {
query = this.dbDriver(
this.dbDriver.raw(
`SELECT generate_series(
??,
??,
'1 day'
)::date AS date FROM ??`,
[
columns.find((c) => c.id === range.fk_from_column_id).column_name,
columns.find((c) => c.id === range.fk_to_column_id).column_name,
this.tnPath,
],
),
);
} else if (range.fk_from_column_id) {
query = this.dbDriver(
this.dbDriver.raw(`SELECT ??::date AS date FROM ??`, [
columns.find((c) => c.id === range.fk_from_column_id).column_name,
this.tnPath,
]),
);
}
if (query) {
await conditionV2(this, filterArr, query);
queryRanges.push(query);
}
}
const unionQuery = this.dbDriver.raw(
queryRanges.reduce(
(acc, range) =>
acc ? `${acc} UNION ALL ${range.toQuery()}` : range.toQuery(),
'',
),
);
const qb = this.dbDriver(
this.dbDriver.raw(`(${unionQuery.toQuery()}) AS ??`, ['nc']),
)
.select('date')
.count('* as count')
.groupBy('date')
.orderBy('date');
console.log(qb.toQuery());
return await this.execAndParse(qb);
}
// todo: add support for sortArrJson // todo: add support for sortArrJson
public async findOne( public async findOne(
args: { args: {

23
packages/nocodb/src/helpers/getAst.ts

@ -34,6 +34,7 @@ const getAst = async ({
}, },
getHiddenColumn = query?.['getHiddenColumn'], getHiddenColumn = query?.['getHiddenColumn'],
throwErrorIfInvalidParams = false, throwErrorIfInvalidParams = false,
extractOnlyRangeFields = false,
}: { }: {
query?: RequestQuery; query?: RequestQuery;
extractOnlyPrimaries?: boolean; extractOnlyPrimaries?: boolean;
@ -43,6 +44,8 @@ const getAst = async ({
dependencyFields?: DependantFields; dependencyFields?: DependantFields;
getHiddenColumn?: boolean; getHiddenColumn?: boolean;
throwErrorIfInvalidParams?: boolean; throwErrorIfInvalidParams?: boolean;
// Used for calendar view
extractOnlyRangeFields?: boolean;
}) => { }) => {
// set default values of dependencyFields and nested // set default values of dependencyFields and nested
dependencyFields.nested = dependencyFields.nested || {}; dependencyFields.nested = dependencyFields.nested || {};
@ -88,6 +91,26 @@ const getAst = async ({
return { ast, dependencyFields, parsedQuery: dependencyFields }; return { ast, dependencyFields, parsedQuery: dependencyFields };
} }
if (extractOnlyRangeFields) {
const ast = {
...(dependencyFieldsForCalenderView || []).reduce((o, f) => {
const col = model.columns.find((c) => c.id === f);
return { ...o, [col.title]: 1 };
}, {}),
};
await Promise.all(
(dependencyFieldsForCalenderView || []).map((f) =>
extractDependencies(
model.columns.find((c) => c.id === f),
dependencyFields,
),
),
);
return { ast, dependencyFields, parsedQuery: dependencyFields };
}
let fields = query?.fields || query?.f; let fields = query?.fields || query?.f;
if (fields && fields !== '*') { if (fields && fields !== '*') {
fields = Array.isArray(fields) ? fields : fields.split(','); fields = Array.isArray(fields) ? fields : fields.split(',');

95
packages/nocodb/src/schema/swagger.json

@ -10054,6 +10054,101 @@
} }
} }
}, },
"/api/v1/db/data/{orgs}/{baseName}/{tableName}/views/{viewName}/countByDate/" : {
"parameters": [
{
"schema": {
"type": "string"
},
"name": "orgs",
"in": "path",
"required": true,
"description": "Organisation Name. Currently `noco` will be used."
},
{
"schema": {
"type": "string"
},
"name": "baseName",
"in": "path",
"required": true,
"description": "Base Name"
},
{
"schema": {
"type": "string"
},
"name": "tableName",
"in": "path",
"required": true,
"description": "Table Name"
},
{
"schema": {
"type": "string"
},
"name": "viewName",
"in": "path",
"required": true
}
],
"get": {
"summary": "Count of Records in Dates in Calendar View",
"operationId": "db-view-row-calendar-count",
"description": "Get the count of table view rows grouped by the dates",
"tags": [
"DB View Row"
],
"parameters": [
{
"schema": {
"type": "array"
},
"in": "query",
"name": "sort"
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "where"
},
{
"schema": {
"type": "integer",
"minimum": 1
},
"in": "query",
"name": "limit"
},
{
"schema": {
"type": "integer",
"minimum": 0
},
"in": "query",
"name": "offset"
},
{
"$ref": "#/components/parameters/xc-auth"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
}
}
}
},
"/api/v1/db/data/{orgs}/{baseName}/{tableName}/views/{viewName}/groupby": { "/api/v1/db/data/{orgs}/{baseName}/{tableName}/views/{viewName}/groupby": {
"parameters": [ "parameters": [
{ {

49
packages/nocodb/src/services/datas.service.ts

@ -6,7 +6,7 @@ import { nocoExecute } from 'nc-help';
import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2';
import type { PathParams } from '~/modules/datas/helpers'; import type { PathParams } from '~/modules/datas/helpers';
import { getDbRows, getViewAndModelByAliasOrId } from '~/modules/datas/helpers'; import { getDbRows, getViewAndModelByAliasOrId } from '~/modules/datas/helpers';
import { Base, Column, Model, Source, View } from '~/models'; import { Base, CalendarRange, Column, Model, Source, View } from '~/models';
import { NcBaseError, NcError } from '~/helpers/catchError'; import { NcBaseError, NcError } from '~/helpers/catchError';
import getAst from '~/helpers/getAst'; import getAst from '~/helpers/getAst';
import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { PagedResponseImpl } from '~/helpers/PagedResponse';
@ -205,6 +205,53 @@ export class DatasService {
}); });
} }
async getCalendarRecordCount(param: { viewId: string; query: any }) {
const { viewId, query = {} } = param;
const view = await View.get(viewId);
if (!view) NcError.notFound('View not found');
if (view.type !== ViewTypes.CALENDAR)
NcError.badRequest('View is not a calendar view');
const source = await Source.get(view.source_id);
const { ranges } = await CalendarRange.read(view.id);
if (!ranges.length) NcError.badRequest('No ranges found');
const model = await Model.getByIdOrName({
id: view.fk_model_id,
});
const baseModel = await Model.getBaseModelSQL({
id: view.fk_model_id,
viewId: view?.id,
dbDriver: await NcConnectionMgrv2.get(source),
});
const { dependencyFields } = await getAst({
model,
query,
view,
extractOnlyRangeFields: true,
});
const listArgs: any = dependencyFields;
try {
listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
} catch (e) {}
try {
listArgs.sortArr = JSON.parse(listArgs.sortArrJson);
} catch (e) {}
return await baseModel.countByRanges({
model,
ranges,
...listArgs,
});
}
async getFindOne(param: { model: Model; view: View; query: any }) { async getFindOne(param: { model: Model; view: View; query: any }) {
const { model, view, query = {} } = param; const { model, view, query = {} } = param;

Loading…
Cancel
Save