Browse Source

Merge pull request #5749 from nocodb/develop

pull/5750/head 0.107.5
github-actions[bot] 2 years ago committed by GitHub
parent
commit
88274c54e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  2. 10
      packages/nc-gui/lang/fr.json
  3. 52
      packages/nc-gui/package-lock.json
  4. 2
      packages/nc-gui/package.json
  5. 4
      packages/nocodb-sdk/package-lock.json
  6. 2
      packages/nocodb-sdk/src/lib/Api.ts
  7. 30
      packages/nocodb/package-lock.json
  8. 2
      packages/nocodb/package.json
  9. 2
      packages/nocodb/src/Noco.ts
  10. 33
      packages/nocodb/src/db/BaseModelSqlv2.ts
  11. 5
      packages/nocodb/src/schema/swagger.json
  12. 2
      packages/nocodb/src/services/app-init.service.ts
  13. 23
      packages/nocodb/src/services/datas.service.ts
  14. 238
      packages/nocodb/tests/unit/rest/tests/tableRow.test.ts
  15. 2
      packages/nocodb/tests/unit/rest/tests/viewRow.test.ts

4
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -495,7 +495,7 @@ watch(
</a-form-item> </a-form-item>
<div class="flex items-right justify-end gap-2"> <div class="flex items-right justify-end gap-2">
<!-- Use Connection URL --> <!-- Use Connection URL -->
<a-button type="primary" class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true"> <a-button class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }} {{ $t('activity.useConnectionUrl') }}
</a-button> </a-button>
</div> </div>
@ -611,7 +611,7 @@ watch(
<a-form-item class="flex justify-end !mt-5"> <a-form-item class="flex justify-end !mt-5">
<div class="flex justify-end gap-2"> <div class="flex justify-end gap-2">
<a-button type="text" class="nc-extdb-btn-test-connection !rounded-md" @click="testConnection"> <a-button type="primary" class="nc-extdb-btn-test-connection !rounded-md" @click="testConnection">
{{ $t('activity.testDbConn') }} {{ $t('activity.testDbConn') }}
</a-button> </a-button>

10
packages/nc-gui/lang/fr.json

@ -260,7 +260,7 @@
"barcodeFormat": "Format du code-barres", "barcodeFormat": "Format du code-barres",
"qrCodeValueTooLong": "Trop de caractères pour un code QR", "qrCodeValueTooLong": "Trop de caractères pour un code QR",
"barcodeValueTooLong": "Trop de caractères pour un code-barres", "barcodeValueTooLong": "Trop de caractères pour un code-barres",
"currentLocation": "Current Location", "currentLocation": "Emplacement actuel",
"lng": "Lng", "lng": "Lng",
"lat": "Lat", "lat": "Lat",
"aggregateFunction": "Fonction agrégée", "aggregateFunction": "Fonction agrégée",
@ -385,12 +385,12 @@
"nextRecord": "Ligne suivante", "nextRecord": "Ligne suivante",
"previousRecord": "Ligne précédente", "previousRecord": "Ligne précédente",
"copyApiURL": "Copier l'URL de l'API", "copyApiURL": "Copier l'URL de l'API",
"createTable": "Create New Table", "createTable": "Créer une nouvelle table",
"refreshTable": "Actualiser le tableau", "refreshTable": "Actualiser le tableau",
"renameTable": "Rename Table", "renameTable": "Renommer la table",
"deleteTable": "Delete Table", "deleteTable": "Supprimer la table",
"addField": "Ajouter un nouveau champ à ce tableau", "addField": "Ajouter un nouveau champ à ce tableau",
"setDisplay": "Set as Display value", "setDisplay": "Définir comme valeur d'affichage",
"addRow": "Ajouter une nouvelle ligne", "addRow": "Ajouter une nouvelle ligne",
"saveRow": "Enregistrer la ligne", "saveRow": "Enregistrer la ligne",
"saveAndExit": "Enregistrer et quitter", "saveAndExit": "Enregistrer et quitter",

52
packages/nc-gui/package-lock.json generated

@ -30,7 +30,7 @@
"leaflet.markercluster": "^1.5.3", "leaflet.markercluster": "^1.5.3",
"locale-codes": "^1.3.1", "locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "0.107.4", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
"pinia": "^2.0.33", "pinia": "^2.0.33",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
@ -111,7 +111,6 @@
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.107.4", "version": "0.107.4",
"extraneous": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -8776,6 +8775,7 @@
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"devOptional": true,
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -12294,21 +12294,8 @@
} }
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"version": "0.107.4", "resolved": "../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.107.4.tgz", "link": true
"integrity": "sha512-9fmUMTmsyY6T5ahqidwGpG5aoDnmrheLYYAAZug5CctEsdCCYv0RoIag/0AB7PAkAqrA3pvjnmFTtCbPoRF1vQ==",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
},
"node_modules/nocodb-sdk/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.23.0", "version": "3.23.0",
@ -24810,7 +24797,8 @@
"follow-redirects": { "follow-redirects": {
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"devOptional": true
}, },
"form-data": { "form-data": {
"version": "4.0.0", "version": "4.0.0",
@ -27360,22 +27348,22 @@
} }
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "0.107.4", "version": "file:../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.107.4.tgz",
"integrity": "sha512-9fmUMTmsyY6T5ahqidwGpG5aoDnmrheLYYAAZug5CctEsdCCYv0RoIag/0AB7PAkAqrA3pvjnmFTtCbPoRF1vQ==",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"jsep": "^1.3.6" "cspell": "^4.1.0",
}, "eslint": "^7.8.0",
"dependencies": { "eslint-config-prettier": "^6.11.0",
"axios": { "eslint-plugin-eslint-comments": "^3.2.0",
"version": "0.21.4", "eslint-plugin-functional": "^3.0.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", "eslint-plugin-import": "^2.22.0",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "eslint-plugin-prettier": "^4.0.0",
"requires": { "jsep": "^1.3.6",
"follow-redirects": "^1.14.0" "npm-run-all": "^4.1.5",
} "prettier": "^2.1.1",
} "typescript": "^4.0.2"
} }
}, },
"node-abi": { "node-abi": {

2
packages/nc-gui/package.json

@ -54,7 +54,7 @@
"leaflet.markercluster": "^1.5.3", "leaflet.markercluster": "^1.5.3",
"locale-codes": "^1.3.1", "locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "0.107.4", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
"pinia": "^2.0.33", "pinia": "^2.0.33",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",

4
packages/nocodb-sdk/package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.107.3", "version": "0.107.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.107.3", "version": "0.107.4",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",

2
packages/nocodb-sdk/src/lib/Api.ts

@ -1603,7 +1603,7 @@ export interface NormalColumnRequestType {
/** Data Type Extra */ /** Data Type Extra */
dtx?: StringOrNullType; dtx?: StringOrNullType;
/** Data Type Extra Precision */ /** Data Type Extra Precision */
dtxp?: StringOrNullType | number; dtxp?: string | number | null;
/** Data Type Extra Scale */ /** Data Type Extra Scale */
dtxs?: StringOrNullType | number; dtxs?: StringOrNullType | number;
/** Numeric Precision */ /** Numeric Precision */

30
packages/nocodb/package-lock.json generated

@ -83,7 +83,7 @@
"nc-lib-gui": "0.107.4", "nc-lib-gui": "0.107.4",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "0.107.4", "nocodb-sdk": "file:../nocodb-sdk",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"os-locale": "^6.0.2", "os-locale": "^6.0.2",
@ -191,7 +191,6 @@
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.107.4", "version": "0.107.4",
"extraneous": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -13207,13 +13206,8 @@
} }
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"version": "0.107.4", "resolved": "../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.107.4.tgz", "link": true
"integrity": "sha512-9fmUMTmsyY6T5ahqidwGpG5aoDnmrheLYYAAZug5CctEsdCCYv0RoIag/0AB7PAkAqrA3pvjnmFTtCbPoRF1vQ==",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
}, },
"node_modules/node-abort-controller": { "node_modules/node-abort-controller": {
"version": "3.1.1", "version": "3.1.1",
@ -28485,12 +28479,22 @@
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "0.107.4", "version": "file:../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.107.4.tgz",
"integrity": "sha512-9fmUMTmsyY6T5ahqidwGpG5aoDnmrheLYYAAZug5CctEsdCCYv0RoIag/0AB7PAkAqrA3pvjnmFTtCbPoRF1vQ==",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"jsep": "^1.3.6" "cspell": "^4.1.0",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"jsep": "^1.3.6",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
} }
}, },
"node-abort-controller": { "node-abort-controller": {

2
packages/nocodb/package.json

@ -116,7 +116,7 @@
"nc-lib-gui": "0.107.4", "nc-lib-gui": "0.107.4",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "0.107.4", "nocodb-sdk": "file:../nocodb-sdk",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"os-locale": "^6.0.2", "os-locale": "^6.0.2",

2
packages/nocodb/src/Noco.ts

@ -1,6 +1,6 @@
import path from 'path';
import Sentry, { Handlers } from '@sentry/node'; import Sentry, { Handlers } from '@sentry/node';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import path from 'path';
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import clear from 'clear'; import clear from 'clear';
import * as express from 'express'; import * as express from 'express';

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

@ -130,10 +130,24 @@ class BaseModelSqlv2 {
autoBind(this); autoBind(this);
} }
public async readByPk(id?: any, validateFormula = false): Promise<any> { public async readByPk(
id?: any,
validateFormula = false,
query: any = {},
): Promise<any> {
const qb = this.dbDriver(this.tnPath); const qb = this.dbDriver(this.tnPath);
await this.selectObject({ qb, validateFormula }); const { ast, dependencyFields } = await getAst({
query,
model: this.model,
view: this.viewId && (await View.get(this.viewId)),
});
await this.selectObject({
...(dependencyFields ?? {}),
qb,
validateFormula,
});
qb.where(_wherePk(this.model.primaryKeys, id)); qb.where(_wherePk(this.model.primaryKeys, id));
@ -153,14 +167,7 @@ class BaseModelSqlv2 {
data.__proto__ = proto; data.__proto__ = proto;
} }
// retrieve virtual column data as well return data ? await nocoExecute(ast, data, {}, query) : {};
const project = await Project.get(this.model.project_id);
const { model, view } = await getViewAndModelByAliasOrId({
projectName: project.title,
tableName: this.model.title,
});
const { ast } = await getAst({ model, view });
return data ? await nocoExecute(ast, data, {}) : {};
} }
public async exist(id?: any): Promise<any> { public async exist(id?: any): Promise<any> {
@ -190,7 +197,7 @@ class BaseModelSqlv2 {
): Promise<any> { ): Promise<any> {
const { where, ...rest } = this._getListArgs(args as any); const { where, ...rest } = this._getListArgs(args as any);
const qb = this.dbDriver(this.tnPath); const qb = this.dbDriver(this.tnPath);
await this.selectObject({ qb, validateFormula }); await this.selectObject({ ...args, qb, validateFormula });
const aliasColObjMap = await this.model.getAliasColObjMap(); const aliasColObjMap = await this.model.getAliasColObjMap();
const sorts = extractSortsObject(rest?.sort, aliasColObjMap); const sorts = extractSortsObject(rest?.sort, aliasColObjMap);
@ -2091,6 +2098,7 @@ class BaseModelSqlv2 {
raw?: boolean; raw?: boolean;
} = {}, } = {},
) { ) {
let trx;
try { try {
// TODO: ag column handling for raw bulk insert // TODO: ag column handling for raw bulk insert
const insertDatas = raw const insertDatas = raw
@ -2115,7 +2123,7 @@ class BaseModelSqlv2 {
// refer : https://www.sqlite.org/limits.html // refer : https://www.sqlite.org/limits.html
const chunkSize = this.isSqlite ? 10 : _chunkSize; const chunkSize = this.isSqlite ? 10 : _chunkSize;
const trx = await this.dbDriver.transaction(); trx = await this.dbDriver.transaction();
if (!foreign_key_checks) { if (!foreign_key_checks) {
if (this.isPg) { if (this.isPg) {
@ -2146,6 +2154,7 @@ class BaseModelSqlv2 {
return response; return response;
} catch (e) { } catch (e) {
await trx?.rollback();
// await this.errorInsertb(e, data, null); // await this.errorInsertb(e, data, null);
throw e; throw e;
} }

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

@ -17834,10 +17834,13 @@
"dtxp": { "dtxp": {
"oneOf": [ "oneOf": [
{ {
"$ref": "#/components/schemas/StringOrNull" "type": "string"
}, },
{ {
"type": "number" "type": "number"
},
{
"type": "null"
} }
], ],
"description": "Data Type Extra Precision" "description": "Data Type Extra Precision"

2
packages/nocodb/src/services/app-init.service.ts

@ -4,7 +4,7 @@ import { Connection } from '../connection/connection';
import initAdminFromEnv from '../helpers/initAdminFromEnv'; import initAdminFromEnv from '../helpers/initAdminFromEnv';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import { MetaService } from '../meta/meta.service'; import { MetaService } from '../meta/meta.service';
import { User } from '../models' import { User } from '../models';
import Noco from '../Noco'; import Noco from '../Noco';
import getInstance from '../utils/getInstance'; import getInstance from '../utils/getInstance';
import NcConfigFactory from '../utils/NcConfigFactory'; import NcConfigFactory from '../utils/NcConfigFactory';

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

@ -185,8 +185,8 @@ export class DatasService {
view, view,
}); });
const data = await baseModel.findOne({ ...args, dependencyFields }); const data = await baseModel.findOne({ ...args, ...dependencyFields });
return data ? await nocoExecute(ast, data, {}, {}) : {}; return data ? await nocoExecute(ast, data, {}, dependencyFields) : {};
} }
async getDataGroupBy(param: { model: Model; view: View; query?: any }) { async getDataGroupBy(param: { model: Model; view: View; query?: any }) {
@ -221,15 +221,13 @@ export class DatasService {
dbDriver: await NcConnectionMgrv2.get(base), dbDriver: await NcConnectionMgrv2.get(base),
}); });
const row = await baseModel.readByPk(param.rowId); const row = await baseModel.readByPk(param.rowId, false, param.query);
if (!row) { if (!row) {
NcError.notFound('Row not found'); NcError.notFound('Row not found');
} }
const { ast } = await getAst({ model, query: param.query, view }); return row;
return await nocoExecute(ast, row, {}, param.query);
} }
async dataExist(param: PathParams & { rowId: string; query: any }) { async dataExist(param: PathParams & { rowId: string; query: any }) {
@ -274,9 +272,9 @@ export class DatasService {
dbDriver: await NcConnectionMgrv2.get(base), dbDriver: await NcConnectionMgrv2.get(base),
}); });
const { ast } = await getAst({ model, query, view }); const { ast, dependencyFields } = await getAst({ model, query, view });
const listArgs: any = { ...query }; const listArgs: any = { ...dependencyFields };
try { try {
listArgs.filterArr = JSON.parse(listArgs.filterArrJson); listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
} catch (e) {} } catch (e) {}
@ -637,13 +635,16 @@ export class DatasService {
dbDriver: await NcConnectionMgrv2.get(base), dbDriver: await NcConnectionMgrv2.get(base),
}); });
const { ast } = await getAst({ model, query: param.query }); const { ast, dependencyFields } = await getAst({
model,
query: param.query,
});
return await nocoExecute( return await nocoExecute(
ast, ast,
await baseModel.readByPk(param.rowId), await baseModel.readByPk(param.rowId, false),
{},
{}, {},
dependencyFields,
); );
} catch (e) { } catch (e) {
console.log(e); console.log(e);

238
packages/nocodb/tests/unit/rest/tests/tableRow.test.ts

@ -1,8 +1,9 @@
import 'mocha'; import 'mocha';
import request from 'supertest';
import { UITypes } from 'nocodb-sdk';
import { expect } from 'chai';
import init from '../../init'; import init from '../../init';
import { createProject, createSakilaProject } from '../../factory/project'; import { createProject, createSakilaProject } from '../../factory/project';
import request from 'supertest';
import { ColumnType, UITypes } from 'nocodb-sdk';
import { import {
createColumn, createColumn,
createLookupColumn, createLookupColumn,
@ -11,18 +12,18 @@ import {
} from '../../factory/column'; } from '../../factory/column';
import { createTable, getTable } from '../../factory/table'; import { createTable, getTable } from '../../factory/table';
import { import {
createBulkRows,
createChildRow, createChildRow,
createRow, createRow,
generateDefaultRowAttributes, generateDefaultRowAttributes,
getOneRow, getOneRow,
getRow, getRow,
listRow, listRow,
createBulkRows,
} from '../../factory/row'; } from '../../factory/row';
import { isMysql, isPg, isSqlite } from '../../init/db'; import { isMysql, isPg, isSqlite } from '../../init/db';
import Model from '../../../../src/models/Model'; import type { ColumnType } from 'nocodb-sdk';
import Project from '../../../../src/models/Project'; import type Model from '../../../../src/models/Model';
import { expect } from 'chai'; import type Project from '../../../../src/models/Project';
const isColumnsCorrectInResponse = (row, columns: ColumnType[]) => { const isColumnsCorrectInResponse = (row, columns: ColumnType[]) => {
const responseColumnsListStr = Object.keys(row).sort().join(','); const responseColumnsListStr = Object.keys(row).sort().join(',');
@ -160,7 +161,7 @@ function tableTest() {
it('Get desc sorted table data list with required columns', async function () { it('Get desc sorted table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const visibleColumns = [firstNameColumn]; const visibleColumns = [firstNameColumn];
const sortInfo = [{ fk_column_id: firstNameColumn.id, direction: 'desc' }]; const sortInfo = [{ fk_column_id: firstNameColumn.id, direction: 'desc' }];
@ -214,7 +215,7 @@ function tableTest() {
it('Get asc sorted table data list with required columns', async function () { it('Get asc sorted table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const visibleColumns = [firstNameColumn]; const visibleColumns = [firstNameColumn];
const sortInfo = [{ fk_column_id: firstNameColumn.id, direction: 'asc' }]; const sortInfo = [{ fk_column_id: firstNameColumn.id, direction: 'asc' }];
@ -427,7 +428,7 @@ function tableTest() {
}); });
const paymentListColumn = (await rentalTable.getColumns()).find( const paymentListColumn = (await rentalTable.getColumns()).find(
(c) => c.title === 'Payment List' (c) => c.title === 'Payment List',
); );
const nestedFilter = { const nestedFilter = {
@ -513,11 +514,11 @@ function tableTest() {
}); });
const paymentListColumn = (await rentalTable.getColumns()).find( const paymentListColumn = (await rentalTable.getColumns()).find(
(c) => c.title === 'Payment List' (c) => c.title === 'Payment List',
); );
const returnDateColumn = (await rentalTable.getColumns()).find( const returnDateColumn = (await rentalTable.getColumns()).find(
(c) => c.title === 'ReturnDate' (c) => c.title === 'ReturnDate',
); );
const nestedFilter = { const nestedFilter = {
@ -630,15 +631,15 @@ function tableTest() {
}); });
const paymentListColumn = (await customerTable.getColumns()).find( const paymentListColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Payment List' (c) => c.title === 'Payment List',
); );
const activeColumn = (await customerTable.getColumns()).find( const activeColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Active' (c) => c.title === 'Active',
); );
const addressColumn = (await customerTable.getColumns()).find( const addressColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Address' (c) => c.title === 'Address',
); );
const nestedFilter = [ const nestedFilter = [
@ -786,11 +787,11 @@ function tableTest() {
}); });
const paymentListColumn = (await customerTable.getColumns()).find( const paymentListColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Payment List' (c) => c.title === 'Payment List',
); );
const activeColumn = (await customerTable.getColumns()).find( const activeColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Active' (c) => c.title === 'Active',
); );
const nestedFields = { const nestedFields = {
@ -866,7 +867,7 @@ function tableTest() {
} }
const nestedRentalResponse = Object.keys( const nestedRentalResponse = Object.keys(
ascResponse.body.list[0]['Rental List'] ascResponse.body.list[0]['Rental List'],
); );
if ( if (
nestedRentalResponse.includes('ReturnDate') && nestedRentalResponse.includes('ReturnDate') &&
@ -914,7 +915,7 @@ function tableTest() {
if ( if (
(response.body.list as Array<any>).every( (response.body.list as Array<any>).every(
(row) => (row) =>
parseInt(row['Formula']) !== parseInt(row[rollupColumnTitle]) + 10 parseInt(row['Formula']) !== parseInt(row[rollupColumnTitle]) + 10,
) )
) { ) {
throw new Error('Wrong formula'); throw new Error('Wrong formula');
@ -998,13 +999,13 @@ function tableTest() {
it('Find one sorted table data list with required columns', async function () { it('Find one sorted table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const visibleColumns = [firstNameColumn]; const visibleColumns = [firstNameColumn];
let response = await request(context.app) let response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1025,7 +1026,7 @@ function tableTest() {
response = await request(context.app) response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1047,7 +1048,7 @@ function tableTest() {
it('Find one desc sorted and with rollup table data list with required columns', async function () { it('Find one desc sorted and with rollup table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const rollupColumn = await createRollupColumn(context, { const rollupColumn = await createRollupColumn(context, {
@ -1064,7 +1065,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1095,15 +1096,17 @@ function tableTest() {
}); });
const paymentListColumn = (await customerTable.getColumns()).find( const paymentListColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Payment List' (c) => c.title === 'Payment List',
); );
const activeColumn = (await customerTable.getColumns()).find( const activeColumn = (await customerTable.getColumns()).find(
(c) => c.title === 'Active' (c) => c.title === 'Active',
); );
const nestedFields = { const nestedFields = {
'Rental List': ['RentalDate', 'ReturnDate'], 'Rental List': {
f: 'RentalDate,ReturnDate',
},
}; };
const nestedFilter = [ const nestedFilter = [
@ -1152,7 +1155,7 @@ function tableTest() {
const ascResponse = await request(context.app) const ascResponse = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/find-one`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1179,7 +1182,7 @@ function tableTest() {
it('Groupby desc sorted and with rollup table data list with required columns', async function () { it('Groupby desc sorted and with rollup table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const rollupColumn = await createRollupColumn(context, { const rollupColumn = await createRollupColumn(context, {
@ -1196,7 +1199,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/groupby` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/groupby`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1215,7 +1218,7 @@ function tableTest() {
it('Groupby desc sorted and with rollup table data list with required columns', async function () { it('Groupby desc sorted and with rollup table data list with required columns', async function () {
const firstNameColumn = customerColumns.find( const firstNameColumn = customerColumns.find(
(col) => col.title === 'FirstName' (col) => col.title === 'FirstName',
); );
const rollupColumn = await createRollupColumn(context, { const rollupColumn = await createRollupColumn(context, {
@ -1232,7 +1235,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/groupby` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/groupby`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1260,7 +1263,7 @@ function tableTest() {
const readResponse = await request(context.app) const readResponse = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${row['CustomerId']}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${row['CustomerId']}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1273,6 +1276,39 @@ function tableTest() {
} }
}); });
it('Read table row with nested fields', async () => {
const rowId = 1;
const actorTable = await getTable({
project: sakilaProject,
name: 'actor',
});
const response = await request(context.app)
.get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/`,
)
.set('xc-auth', context.token)
.query({
'nested[Film List][fields]': 'Title,ReleaseYear,Language',
})
.expect(200);
const record = response.body;
expect(record['Film List']).length(19);
expect(record['Film List'][0]).to.have.all.keys(
'Title',
'ReleaseYear',
'Language',
);
// for SQLite Sakila, Language is null
if (isPg(context)) {
expect(record['Film List'][0]['Language']).to.have.all.keys(
'Name',
'LanguageId',
);
}
});
it('Update table row', async function () { it('Update table row', async function () {
const table = await createTable(context, project); const table = await createTable(context, project);
const row = await createRow(context, { project, table }); const row = await createRow(context, { project, table });
@ -1396,7 +1432,7 @@ function tableTest() {
if ( if (
!(response.body.message[0] as string).includes( !(response.body.message[0] as string).includes(
'is a LinkToAnotherRecord of' 'is a LinkToAnotherRecord of',
) )
) { ) {
throw new Error('Should give ltar foreign key error'); throw new Error('Should give ltar foreign key error');
@ -1411,7 +1447,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${row['CustomerId']}/exist` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${row['CustomerId']}/exist`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1424,7 +1460,7 @@ function tableTest() {
it('Exist should be false table row when it does not exists', async function () { it('Exist should be false table row when it does not exists', async function () {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/998546/exist` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/998546/exist`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1531,7 +1567,7 @@ function tableTest() {
.patch(`/api/v1/db/data/bulk/noco/${project.id}/${table.id}`) .patch(`/api/v1/db/data/bulk/noco/${project.id}/${table.id}`)
.set('xc-auth', context.token) .set('xc-auth', context.token)
.send( .send(
rows.map((row) => ({ title: `new-${row['Title']}`, id: row['Id'] })) rows.map((row) => ({ title: `new-${row['Title']}`, id: row['Id'] })),
) )
.expect(200); .expect(200);
const updatedRows: Array<any> = await listRow({ project, table }); const updatedRows: Array<any> = await listRow({ project, table });
@ -1612,7 +1648,7 @@ function tableTest() {
it('Export csv', async () => { it('Export csv', async () => {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.title}/export/csv` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.title}/export/csv`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1631,14 +1667,14 @@ function tableTest() {
it('Export excel', async () => { it('Export excel', async () => {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.title}/export/excel` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.title}/export/excel`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
if ( if (
!response['header']['content-disposition'].includes( !response['header']['content-disposition'].includes(
'Customer-export.xlsx' 'Customer-export.xlsx',
) )
) { ) {
throw new Error('Wrong file name'); throw new Error('Wrong file name');
@ -1653,11 +1689,11 @@ function tableTest() {
it('Nested row list hm', async () => { it('Nested row list hm', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1672,11 +1708,11 @@ function tableTest() {
it('Nested row list hm with limit and offset', async () => { it('Nested row list hm with limit and offset', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1698,11 +1734,11 @@ function tableTest() {
it('Row list hm with invalid table id', async () => { it('Row list hm with invalid table id', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/wrong-id/${rowId}/hm/${rentalListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/wrong-id/${rowId}/hm/${rentalListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1750,11 +1786,11 @@ function tableTest() {
}); });
const filmTable = await getTable({ project: sakilaProject, name: 'film' }); const filmTable = await getTable({ project: sakilaProject, name: 'film' });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1774,11 +1810,11 @@ function tableTest() {
}); });
const filmTable = await getTable({ project: sakilaProject, name: 'film' }); const filmTable = await getTable({ project: sakilaProject, name: 'film' });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -1805,11 +1841,11 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1823,12 +1859,12 @@ function tableTest() {
it('Create hm relation with invalid table id', async () => { it('Create hm relation with invalid table id', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const refId = 1; const refId = 1;
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/hm/${rentalListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/hm/${rentalListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1841,12 +1877,12 @@ function tableTest() {
it('Create hm relation with non ltar column', async () => { it('Create hm relation with non ltar column', async () => {
const rowId = 1; const rowId = 1;
const firstNameColumn = (await customerTable.getColumns()).find( const firstNameColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'FirstName' (column) => column.title === 'FirstName',
)!; )!;
const refId = 1; const refId = 1;
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${firstNameColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${firstNameColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1863,7 +1899,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/invalid-column/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/invalid-column/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1898,20 +1934,20 @@ function tableTest() {
it('Create list hm', async () => { it('Create list hm', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const refId = 1; const refId = 1;
const lisResponseBeforeUpdate = await request(context.app) const lisResponseBeforeUpdate = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
await request(context.app) await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1919,7 +1955,7 @@ function tableTest() {
const lisResponseAfterUpdate = await request(context.app) const lisResponseAfterUpdate = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -1942,7 +1978,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/invalid-column/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/invalid-column/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1962,12 +1998,12 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const firstNameColumn = (await actorTable.getColumns()).find( const firstNameColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'FirstName' (column) => column.title === 'FirstName',
)!; )!;
const refId = 1; const refId = 1;
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${firstNameColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${firstNameColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -1985,13 +2021,13 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const refId = 1; const refId = 1;
await request(context.app) await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(400); .expect(400);
@ -2007,20 +2043,20 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const refId = 2; const refId = 2;
const lisResponseBeforeUpdate = await request(context.app) const lisResponseBeforeUpdate = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
await request(context.app) await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2028,7 +2064,7 @@ function tableTest() {
const lisResponseAfterUpdate = await request(context.app) const lisResponseAfterUpdate = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2044,12 +2080,12 @@ function tableTest() {
it('List hm with non ltar column', async () => { it('List hm with non ltar column', async () => {
const rowId = 1; const rowId = 1;
const firstNameColumn = (await customerTable.getColumns()).find( const firstNameColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'FirstName' (column) => column.title === 'FirstName',
)!; )!;
await request(context.app) await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${firstNameColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${firstNameColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(400); .expect(400);
@ -2058,12 +2094,12 @@ function tableTest() {
it('List mm with non ltar column', async () => { it('List mm with non ltar column', async () => {
const rowId = 1; const rowId = 1;
const firstNameColumn = (await customerTable.getColumns()).find( const firstNameColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'FirstName' (column) => column.title === 'FirstName',
)!; )!;
await request(context.app) await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/mm/${firstNameColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/mm/${firstNameColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(400); .expect(400);
@ -2076,20 +2112,20 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const refId = 1; const refId = 1;
const lisResponseBeforeDelete = await request(context.app) const lisResponseBeforeDelete = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
await request(context.app) await request(context.app)
.delete( .delete(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2097,7 +2133,7 @@ function tableTest() {
const lisResponseAfterDelete = await request(context.app) const lisResponseAfterDelete = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2116,13 +2152,13 @@ function tableTest() {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const refId = 76; const refId = 76;
const response = await request(context.app) const response = await request(context.app)
.delete( .delete(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/${refId}` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/${refId}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(400); .expect(400);
@ -2130,7 +2166,7 @@ function tableTest() {
// todo: only keep generic error message once updated in noco catchError middleware // todo: only keep generic error message once updated in noco catchError middleware
if ( if (
!response.body.message?.includes( !response.body.message?.includes(
"The column 'customer_id' cannot be null" "The column 'customer_id' cannot be null",
) && ) &&
!response.body.message?.includes("Column 'customer_id' cannot be null") && !response.body.message?.includes("Column 'customer_id' cannot be null") &&
!response.body.message?.includes('Cannot add or update a child row') && !response.body.message?.includes('Cannot add or update a child row') &&
@ -2139,7 +2175,7 @@ function tableTest() {
) { ) {
console.log( console.log(
'Delete list hm with existing ref row id with non nullable clause', 'Delete list hm with existing ref row id with non nullable clause',
response.body response.body,
); );
throw new Error('Wrong error message'); throw new Error('Wrong error message');
} }
@ -2169,7 +2205,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.delete( .delete(
`/api/v1/db/data/noco/${project.id}/${table.id}/${row['Id']}/hm/${ltarColumn.id}/${childRow['Id']}` `/api/v1/db/data/noco/${project.id}/${table.id}/${row['Id']}/hm/${ltarColumn.id}/${childRow['Id']}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2180,7 +2216,9 @@ function tableTest() {
throw new Error('Was not deleted'); throw new Error('Was not deleted');
} }
if (response.body['msg'] !== 'The relation data has been deleted successfully') { if (
response.body['msg'] !== 'The relation data has been deleted successfully'
) {
throw new Error('Response incorrect'); throw new Error('Response incorrect');
} }
}); });
@ -2188,12 +2226,12 @@ function tableTest() {
it('Exclude list hm', async () => { it('Exclude list hm', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2207,12 +2245,12 @@ function tableTest() {
it('Exclude list hm with limit and offset', async () => { it('Exclude list hm with limit and offset', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}/${rowId}/hm/${rentalListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -2239,12 +2277,12 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2262,12 +2300,12 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${actorTable.id}/${rowId}/mm/${filmListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -2294,12 +2332,12 @@ function tableTest() {
name: 'address', name: 'address',
}); });
const cityColumn = (await addressTable.getColumns()).find( const cityColumn = (await addressTable.getColumns()).find(
(column) => column.title === 'City' (column) => column.title === 'City',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${addressTable.id}/${rowId}/bt/${cityColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${addressTable.id}/${rowId}/bt/${cityColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);
@ -2315,12 +2353,12 @@ function tableTest() {
name: 'address', name: 'address',
}); });
const cityColumn = (await addressTable.getColumns()).find( const cityColumn = (await addressTable.getColumns()).find(
(column) => column.title === 'City' (column) => column.title === 'City',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/${addressTable.id}/${rowId}/bt/${cityColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/${addressTable.id}/${rowId}/bt/${cityColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.query({ .query({
@ -2336,12 +2374,12 @@ function tableTest() {
it('Create nested hm relation with invalid table id', async () => { it('Create nested hm relation with invalid table id', async () => {
const rowId = 1; const rowId = 1;
const rentalListColumn = (await customerTable.getColumns()).find( const rentalListColumn = (await customerTable.getColumns()).find(
(column) => column.title === 'Rental List' (column) => column.title === 'Rental List',
)!; )!;
const refId = 1; const refId = 1;
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/hm/${rentalListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/hm/${rentalListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -2359,11 +2397,11 @@ function tableTest() {
name: 'actor', name: 'actor',
}); });
const filmListColumn = (await actorTable.getColumns()).find( const filmListColumn = (await actorTable.getColumns()).find(
(column) => column.title === 'Film List' (column) => column.title === 'Film List',
)!; )!;
const response = await request(context.app) const response = await request(context.app)
.post( .post(
`/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/mm/${filmListColumn.id}/exclude` `/api/v1/db/data/noco/${sakilaProject.id}/invalid-table-id/${rowId}/mm/${filmListColumn.id}/exclude`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(404); .expect(404);
@ -2383,7 +2421,7 @@ function tableTest() {
const response = await request(context.app) const response = await request(context.app)
.get( .get(
`/api/v1/db/data/noco/${sakilaProject.id}/Film/group/${ratingColumn.id}` `/api/v1/db/data/noco/${sakilaProject.id}/Film/group/${ratingColumn.id}`,
) )
.set('xc-auth', context.token) .set('xc-auth', context.token)
.expect(200); .expect(200);

2
packages/nocodb/tests/unit/rest/tests/viewRow.test.ts

@ -901,7 +901,7 @@ function viewRowTests() {
); );
const nestedFields = { const nestedFields = {
'Rental List': ['RentalDate', 'ReturnDate'], 'Rental List': { f: 'RentalDate,ReturnDate' },
}; };
const nestedFilter = [ const nestedFilter = [

Loading…
Cancel
Save