Browse Source

Merge pull request #6928 from nocodb/nc-fix/use-exec

fix: use exec
pull/6945/head
mertmit 10 months ago committed by GitHub
parent
commit
7e713e7ca6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 499
      packages/nocodb/src/db/BaseModelSqlv2.ts
  2. 13
      packages/nocodb/src/db/CustomKnex.ts
  3. 10
      packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts
  4. 194
      packages/nocodb/src/db/sql-client/lib/KnexClient.ts
  5. 38
      packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts
  6. 68
      packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts
  7. 35
      packages/nocodb/src/models/Source.ts
  8. 46
      packages/nocodb/src/services/columns.service.ts
  9. 2
      packages/nocodb/src/services/tables.service.ts
  10. 4
      tests/playwright/pages/Dashboard/ProjectView/Metadata.ts
  11. 2
      tests/playwright/tests/db/features/metaSync.spec.ts

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

@ -165,7 +165,7 @@ class BaseModelSqlv2 {
let data;
try {
data = (await this.execAndParse(qb))?.[0];
data = await this.execAndParse(qb, null, { first: true });
} catch (e) {
if (validateFormula || !haveFormulaColumn(await this.model.getColumns()))
throw e;
@ -194,7 +194,7 @@ class BaseModelSqlv2 {
return false;
}
qb.where(_wherePk(pks, id)).first();
return !!(await qb);
return !!(await this.execAndParse(qb, null, { raw: true, first: true }));
}
// todo: add support for sortArrJson
@ -240,7 +240,7 @@ class BaseModelSqlv2 {
let data;
try {
data = await qb.first();
data = await this.execAndParse(qb, null, { first: true });
} catch (e) {
if (validateFormula || !haveFormulaColumn(await this.model.getColumns()))
throw e;
@ -452,10 +452,8 @@ class BaseModelSqlv2 {
sql = unsanitize(qb.toQuery());
}
const res = (await this.dbDriver.raw(sql)) as any;
return (this.isPg || this.isSnowflake ? res.rows[0] : res[0][0] ?? res[0])
.count;
return (await this.execAndParse(sql, null, { raw: true, first: true }))
?.count;
}
async groupByAndAggregate(
@ -516,7 +514,7 @@ class BaseModelSqlv2 {
qb.orderBy(args.sortBy.column_name, args.sortBy.direction);
}
applyPaginate(qb, rest);
return await qb;
return await this.execAndParse(qb);
}
async groupBy(args: {
@ -680,7 +678,7 @@ class BaseModelSqlv2 {
qb.groupBy(...groupBySelectors);
applyPaginate(qb, rest);
return await qb;
return await this.execAndParse(qb);
}
async groupByCount(args: {
@ -819,7 +817,8 @@ class BaseModelSqlv2 {
.count('*', { as: 'count' })
.from(qb.as('groupby'));
return (await qbP.first())?.count;
return (await this.execAndParse(qbP, null, { raw: true, first: true }))
?.count;
}
async multipleHmList(
@ -947,22 +946,26 @@ class BaseModelSqlv2 {
const childTn = this.getTnPath(childTable);
const parentTn = this.getTnPath(parentTable);
const children = await this.dbDriver.unionAll(
ids.map((p) => {
const query = this.dbDriver(childTn)
.count(`${chilCol?.column_name} as count`)
.whereIn(
chilCol.column_name,
this.dbDriver(parentTn)
.select(parentCol.column_name)
// .where(parentTable.primaryKey.cn, p)
.where(_wherePk(parentTable.primaryKeys, p)),
)
.first();
const children = await this.execAndParse(
this.dbDriver.unionAll(
ids.map((p) => {
const query = this.dbDriver(childTn)
.count(`${chilCol?.column_name} as count`)
.whereIn(
chilCol.column_name,
this.dbDriver(parentTn)
.select(parentCol.column_name)
// .where(parentTable.primaryKey.cn, p)
.where(_wherePk(parentTable.primaryKeys, p)),
)
.first();
return this.isSqlite ? this.dbDriver.select().from(query) : query;
}),
!this.isSqlite,
return this.isSqlite ? this.dbDriver.select().from(query) : query;
}),
!this.isSqlite,
),
null,
{ raw: true },
);
return children.map(({ count }) => count);
@ -1069,7 +1072,8 @@ class BaseModelSqlv2 {
await conditionV2(this, filterObj, query);
return (await query.first())?.count;
return (await this.execAndParse(query, null, { raw: true, first: true }))
?.count;
} catch (e) {
console.log(e);
throw e;
@ -1249,22 +1253,26 @@ class BaseModelSqlv2 {
.count(`${vtn}.${vcn}`, { as: 'count' });
// await childModel.selectObject({ qb });
const children = await this.dbDriver.unionAll(
parentIds.map((id) => {
const query = qb
.clone()
.whereIn(
`${vtn}.${vcn}`,
this.dbDriver(parentTn)
.select(cn)
// .where(parentTable.primaryKey.cn, id)
.where(_wherePk(parentTable.primaryKeys, id)),
)
.select(this.dbDriver.raw('? as ??', [id, GROUP_COL]));
// this._paginateAndSort(query, { sort, limit, offset }, null, true);
return this.isSqlite ? this.dbDriver.select().from(query) : query;
}),
!this.isSqlite,
const children = await this.execAndParse(
this.dbDriver.unionAll(
parentIds.map((id) => {
const query = qb
.clone()
.whereIn(
`${vtn}.${vcn}`,
this.dbDriver(parentTn)
.select(cn)
// .where(parentTable.primaryKey.cn, id)
.where(_wherePk(parentTable.primaryKeys, id)),
)
.select(this.dbDriver.raw('? as ??', [id, GROUP_COL]));
// this._paginateAndSort(query, { sort, limit, offset }, null, true);
return this.isSqlite ? this.dbDriver.select().from(query) : query;
}),
!this.isSqlite,
),
null,
{ raw: true },
);
const gs = groupBy(children, GROUP_COL);
@ -1312,7 +1320,8 @@ class BaseModelSqlv2 {
const filterObj = extractFilterFromXwhere(where, aliasColObjMap);
await conditionV2(this, filterObj, qb);
return (await qb.first())?.count;
return (await this.execAndParse(qb, null, { raw: true, first: true }))
?.count;
}
// todo: naming & optimizing
@ -1363,7 +1372,8 @@ class BaseModelSqlv2 {
const filterObj = extractFilterFromXwhere(where, aliasColObjMap);
await conditionV2(this, filterObj, qb);
return (await qb.first())?.count;
return (await this.execAndParse(qb, null, { raw: true, first: true }))
?.count;
}
// todo: naming & optimizing
@ -1486,7 +1496,8 @@ class BaseModelSqlv2 {
await conditionV2(this, filterObj, qb);
return (await qb.first())?.count;
return (await this.execAndParse(qb, null, { raw: true, first: true }))
?.count;
}
// todo: naming & optimizing
@ -1601,7 +1612,8 @@ class BaseModelSqlv2 {
const filterObj = extractFilterFromXwhere(where, aliasColObjMap);
await conditionV2(this, filterObj, qb);
return (await qb.first())?.count;
return (await this.execAndParse(qb, null, { raw: true, first: true }))
?.count;
}
// todo: naming & optimizing
@ -2256,16 +2268,24 @@ class BaseModelSqlv2 {
if (this.isSqlite) {
// sqlite doesnt return id after insert
id = (
await this.dbDriver(this.tnPath)
.select(ai.column_name)
.max(ai.column_name, { as: 'id' })
)[0].id;
await this.execAndParse(
this.dbDriver(this.tnPath)
.select(ai.column_name)
.max(ai.column_name, { as: '__nc_ai_id' }),
null,
{ raw: true, first: true },
)
)?.__nc_ai_id;
} else if (this.isSnowflake) {
id = (
(await this.dbDriver(this.tnPath).max(ai.column_name, {
as: 'id',
})) as any
)[0].id;
await this.execAndParse(
this.dbDriver(this.tnPath).max(ai.column_name, {
as: 'id',
}),
null,
{ raw: true, first: true },
)
).id;
}
response = await this.readByPk(
id,
@ -2399,23 +2419,31 @@ class BaseModelSqlv2 {
let cnt = 0;
if (colOptions.type === RelationTypes.HAS_MANY) {
cnt = +(
await this.dbDriver(this.getTnPath(childModel.table_name))
.count(childColumn.column_name, { as: 'cnt' })
.where(childColumn.column_name, rowId)
)[0].cnt;
await this.execAndParse(
this.dbDriver(this.getTnPath(childModel.table_name))
.count(childColumn.column_name, { as: 'cnt' })
.where(childColumn.column_name, rowId),
null,
{ raw: true, first: true },
)
).cnt;
} else if (colOptions.type === RelationTypes.MANY_TO_MANY) {
const mmModel = await colOptions.getMMModel();
const mmChildColumn = await colOptions.getMMChildColumn();
cnt = +(
await this.dbDriver(this.getTnPath(mmModel.table_name))
.where(
`${this.getTnPath(mmModel.table_name)}.${
mmChildColumn.column_name
}`,
rowId,
)
.count(mmChildColumn.column_name, { as: 'cnt' })
)[0].cnt;
await this.execAndParse(
this.dbDriver(this.getTnPath(mmModel.table_name))
.where(
`${this.getTnPath(mmModel.table_name)}.${
mmChildColumn.column_name
}`,
rowId,
)
.count(mmChildColumn.column_name, { as: 'cnt' }),
null,
{ first: true },
)
).cnt;
}
if (cnt) {
res.push(
@ -2569,7 +2597,7 @@ class BaseModelSqlv2 {
query.returning(
`${this.model.primaryKey.column_name} as ${this.model.primaryKey.title}`,
);
response = await query;
response = await this.execAndParse(query);
}
const ai = this.model.columns.find((c) => c.ai);
@ -2580,23 +2608,40 @@ class BaseModelSqlv2 {
if (response?.length) {
rowId = response[0];
} else {
rowId = (await query)[0];
rowId = await this.execAndParse(query, null, {
raw: true,
first: true,
});
if (this.isMySQL) {
rowId = rowId?.insertId;
}
}
if (ai) {
if (this.isSqlite) {
// sqlite doesnt return id after insert
rowId = (
await this.dbDriver(this.tnPath)
.select(ai.column_name)
.max(ai.column_name, { as: 'id' })
)[0].id;
await this.execAndParse(
this.dbDriver(this.tnPath)
.select(ai.column_name)
.max(ai.column_name, { as: '__nc_ai_id' }),
null,
{
raw: true,
first: true,
},
)
)?.__nc_ai_id;
} else if (this.isSnowflake) {
rowId = (
(await this.dbDriver(this.tnPath).max(ai.column_name, {
as: 'id',
})) as any
).rows[0].id;
await this.execAndParse(
this.dbDriver(this.tnPath).max(ai.column_name, {
as: 'id',
}),
null,
{ raw: true, first: true },
)
)?.id;
}
// response = await this.readByPk(
// id,
@ -3115,9 +3160,20 @@ class BaseModelSqlv2 {
await conditionV2(this, conditionObj, qb);
count = (
await this.execAndParse(
qb.clone().count('*', { as: 'count' }),
null,
{
raw: true,
first: true,
},
)
)?.count;
qb.update(updateData);
count = (await qb) as any;
await this.execAndParse(qb, null, { raw: true });
}
await this.afterBulkUpdate(null, count, this.dbDriver, cookie, true);
@ -3704,52 +3760,68 @@ class BaseModelSqlv2 {
.where(_wherePk(childTable.primaryKeys, rowId))
.first();
await this.dbDriver.raw(
`INSERT INTO ?? (??, ??) SELECT (${parentPK.toQuery()}), (${childPK.toQuery()})`,
[vTn, vParentCol.column_name, vChildCol.column_name],
await this.execAndParse(
this.dbDriver.raw(
`INSERT INTO ?? (??, ??) SELECT (${parentPK.toQuery()}), (${childPK.toQuery()})`,
[vTn, vParentCol.column_name, vChildCol.column_name],
) as any,
null,
{ raw: true },
);
} else {
await this.dbDriver(vTn).insert({
[vParentCol.column_name]: this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first(),
[vChildCol.column_name]: this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
});
await this.execAndParse(
this.dbDriver(vTn).insert({
[vParentCol.column_name]: this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first(),
[vChildCol.column_name]: this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
}),
null,
{ raw: true },
);
}
}
break;
case RelationTypes.HAS_MANY:
{
await this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, rowId))
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, childId));
await this.execAndParse(
this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, rowId))
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, childId)),
null,
{ raw: true },
);
}
break;
case RelationTypes.BELONGS_TO:
{
await this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, rowId));
await this.execAndParse(
this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, rowId)),
null,
{ raw: true },
);
}
break;
}
@ -3827,44 +3899,56 @@ class BaseModelSqlv2 {
const vTn = this.getTnPath(vTable);
await this.dbDriver(vTn)
.where({
[vParentCol.column_name]: this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first(),
[vChildCol.column_name]: this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
})
.delete();
await this.execAndParse(
this.dbDriver(vTn)
.where({
[vParentCol.column_name]: this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childId))
.first(),
[vChildCol.column_name]: this.dbDriver(childTn)
.select(childColumn.column_name)
.where(_wherePk(childTable.primaryKeys, rowId))
.first(),
})
.delete(),
null,
{ raw: true },
);
}
break;
case RelationTypes.HAS_MANY:
{
await this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, rowId)
// .first()
// })
.where(_wherePk(childTable.primaryKeys, childId))
.update({ [childColumn.column_name]: null });
await this.execAndParse(
this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, rowId)
// .first()
// })
.where(_wherePk(childTable.primaryKeys, childId))
.update({ [childColumn.column_name]: null }),
null,
{ raw: true },
);
}
break;
case RelationTypes.BELONGS_TO:
{
await this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, childId)
// .first()
// })
.where(_wherePk(childTable.primaryKeys, rowId))
.update({ [childColumn.column_name]: null });
await this.execAndParse(
this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, childId)
// .first()
// })
.where(_wherePk(childTable.primaryKeys, rowId))
.update({ [childColumn.column_name]: null }),
null,
{ raw: true },
);
}
break;
}
@ -3931,9 +4015,11 @@ class BaseModelSqlv2 {
} else {
groupingValues = new Set(
(
await this.dbDriver(this.tnPath)
.select(column.column_name)
.distinct()
await this.execAndParse(
this.dbDriver(this.tnPath).select(column.column_name).distinct(),
null,
{ raw: true },
)
).map((row) => row[column.column_name]),
);
groupingValues.add(null);
@ -4132,13 +4218,36 @@ class BaseModelSqlv2 {
columns: [new Column({ ...column, title: 'key' })],
});
return await qb;
return await this.execAndParse(qb);
}
protected async execAndParse(qb: Knex.QueryBuilder, childTable?: Model) {
let query = qb.toQuery();
public async execAndParse(
qb: Knex.QueryBuilder | string,
childTable?: Model,
options: {
skipDateConversion?: boolean;
skipAttachmentConversion?: boolean;
raw?: boolean; // alias for skipDateConversion and skipAttachmentConversion
first?: boolean;
} = {
skipDateConversion: false,
skipAttachmentConversion: false,
raw: false,
first: false,
},
) {
if (options.raw) {
options.skipDateConversion = true;
options.skipAttachmentConversion = true;
}
if (options.first && typeof qb !== 'string') {
qb = qb.limit(1);
}
let query = typeof qb === 'string' ? qb : qb.toQuery();
if (!this.isPg && !this.isMssql && !this.isSnowflake) {
query = unsanitize(qb.toQuery());
query = unsanitize(query);
} else {
query = sanitize(query);
}
@ -4153,10 +4262,18 @@ class BaseModelSqlv2 {
: await this.dbDriver.raw(query);
// update attachment fields
data = await this.convertAttachmentType(data, childTable);
if (!options.skipAttachmentConversion) {
data = await this.convertAttachmentType(data, childTable);
}
// update date time fields
data = this.convertDateFormat(data, childTable);
if (!options.skipDateConversion) {
data = this.convertDateFormat(data, childTable);
}
if (options.first) {
return data?.[0];
}
return data;
}
@ -4543,7 +4660,9 @@ class BaseModelSqlv2 {
}
// todo: use bulk insert
await this.dbDriver(vTn).insert(insertData);
await this.execAndParse(this.dbDriver(vTn).insert(insertData), null, {
raw: true,
});
}
break;
case RelationTypes.HAS_MANY:
@ -4613,7 +4732,7 @@ class BaseModelSqlv2 {
: childIds,
);
}
await updateQb;
await this.execAndParse(updateQb, null, { raw: true });
}
break;
case RelationTypes.BELONGS_TO:
@ -4634,18 +4753,22 @@ class BaseModelSqlv2 {
}
}
await this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childIds[0]))
// .whereIn(parentTable.primaryKey.column_name, childIds)
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, rowId));
await this.execAndParse(
this.dbDriver(childTn)
.update({
[childColumn.column_name]: this.dbDriver.from(
this.dbDriver(parentTn)
.select(parentColumn.column_name)
.where(_wherePk(parentTable.primaryKeys, childIds[0]))
// .whereIn(parentTable.primaryKey.column_name, childIds)
.first()
.as('___cn_alias'),
),
})
.where(_wherePk(childTable.primaryKeys, rowId)),
null,
{ raw: true },
);
}
break;
}
@ -4777,7 +4900,7 @@ class BaseModelSqlv2 {
)
: childIds,
);
await delQb;
await this.execAndParse(delQb, null, { raw: true });
}
break;
case RelationTypes.HAS_MANY:
@ -4823,7 +4946,11 @@ class BaseModelSqlv2 {
);
}
await childRowsQb.update({ [childColumn.column_name]: null });
await this.execAndParse(
childRowsQb.update({ [childColumn.column_name]: null }),
null,
{ raw: true },
);
}
break;
case RelationTypes.BELONGS_TO:
@ -4849,16 +4976,20 @@ class BaseModelSqlv2 {
}
}
await this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, childId)
// .first()
// })
// .where(_wherePk(childTable.primaryKeys, rowId))
.where(childTable.primaryKey.column_name, rowId)
.update({ [childColumn.column_name]: null });
await this.execAndParse(
this.dbDriver(childTn)
// .where({
// [childColumn.cn]: this.dbDriver(parentTable.tn)
// .select(parentColumn.cn)
// .where(parentTable.primaryKey.cn, childId)
// .first()
// })
// .where(_wherePk(childTable.primaryKeys, rowId))
.where(childTable.primaryKey.column_name, rowId)
.update({ [childColumn.column_name]: null }),
null,
{ raw: true },
);
}
break;
}
@ -4887,9 +5018,11 @@ class BaseModelSqlv2 {
(c) => c.id === colId,
);
const row = await this.dbDriver(this.tnPath)
.where(await this._wherePk(id))
.first();
const row = await this.execAndParse(
this.dbDriver(this.tnPath).where(await this._wherePk(id)),
null,
{ raw: true, first: true },
);
// validate rowId
if (!row) {
@ -4927,7 +5060,9 @@ class BaseModelSqlv2 {
await parentModel.selectObject({ qb, fieldsSet: args.fieldSet });
const parent = (await this.execAndParse(qb, childTable))?.[0];
const parent = await this.execAndParse(qb, childTable, {
first: true,
});
const proto = await parentModel.getProto();

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

@ -1020,7 +1020,10 @@ function parseNestedCondition(obj, qb, pKey?, table?, tableAlias?) {
type CustomKnex = Knex;
function CustomKnex(arg: string | Knex.Config<any> | any): CustomKnex {
function CustomKnex(
arg: string | Knex.Config<any> | any,
extDb?: any,
): CustomKnex {
// sqlite does not support inserting default values and knex fires a warning without this flag
if (arg?.client === 'sqlite3') {
arg.useNullAsDefault = true;
@ -1065,6 +1068,14 @@ function CustomKnex(arg: string | Knex.Config<any> | any): CustomKnex {
return arg?.searchPath?.[0];
},
},
extDb: {
enumerable: true,
value: extDb,
},
isExternal: {
enumerable: false,
value: !!extDb && process.env.NC_DISABLE_MUX !== 'true',
},
});
/**

10
packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts

@ -948,9 +948,13 @@ export default async function formulaQueryBuilderv2(
try {
// dry run qb.builder to see if it will break the grid view or not
// if so, set formula error and show empty selectQb instead
await knex(baseModelSqlv2.getTnPath(model, tableAlias))
.select(knex.raw(`?? as ??`, [qb.builder, '__dry_run_alias']))
.as('dry-run-only');
await baseModelSqlv2.execAndParse(
knex(baseModelSqlv2.getTnPath(model, tableAlias))
.select(knex.raw(`?? as ??`, [qb.builder, '__dry_run_alias']))
.as('dry-run-only'),
null,
{ raw: true },
);
// if column is provided, i.e. formula has been created
if (column) {

194
packages/nocodb/src/db/sql-client/lib/KnexClient.ts

@ -1157,7 +1157,7 @@ class KnexClient extends SqlClient {
migrationInit(_args) {}
async selectAll(tn) {
return await this.sqlClient(tn).select();
return await this.sqlClient.raw(this.sqlClient(tn).select().toQuery());
}
/**
@ -1180,15 +1180,19 @@ class KnexClient extends SqlClient {
const result = new Result();
try {
const countResult = await this.sqlClient(args.tn).count();
const countResult = await this.sqlClient.raw(
this.sqlClient(args.tn).count().toQuery(),
);
result.data.count = Object.values(countResult[0])[0];
const query = this.sqlClient(args.tn)
.select()
.limit(size)
.offset((page - 1) * size);
if (orderBy && orderBy.length)
result.data.list = await query.orderBy(orderBy);
else result.data.list = await query;
result.data.list = await this.sqlClient.raw(
query.orderBy(orderBy).toQuery(),
);
else result.data.list = await this.sqlClient.raw(query.toQuery());
} catch (e) {
console.log(e);
result.data.list = [];
@ -1226,26 +1230,32 @@ class KnexClient extends SqlClient {
// Todo: error handling
async insert(args) {
const { tn, data } = args;
const res = await this.sqlClient(tn).insert(data);
const res = await this.sqlClient.raw(
this.sqlClient(tn).insert(data).toQuery(),
);
log.debug(res);
return res;
}
async update(args) {
const { tn, data, whereConditions } = args;
const res = await this.sqlClient(tn).where(whereConditions).update(data);
const res = await this.sqlClient.raw(
this.sqlClient(tn).where(whereConditions).update(data).toQuery(),
);
return res;
}
async delete(args) {
const { tn, whereConditions } = args;
const res = await this.sqlClient(tn).where(whereConditions).del();
const res = await this.sqlClient.raw(
this.sqlClient(tn).where(whereConditions).del().toQuery(),
);
log.debug(res);
return res;
}
async remove(tn, where) {
await this.sqlClient(tn).del().where(where);
await this.sqlClient.raw(this.sqlClient(tn).del().where(where).toQuery());
}
hasTable(_tn) {}
@ -1712,31 +1722,36 @@ class KnexClient extends SqlClient {
args.sqlClient = this.sqlClient;
/** ************** create table *************** */
await this.sqlClient.schema.createTable(args.table, function (table) {
const multiplePks = [];
const columns = JSON.parse(JSON.stringify(args.columns));
// copy PKs to new array and set PK metadata to false in original columns
for (let i = 0; i < columns.length; ++i) {
if (columns[i].pk) {
multiplePks.push(i);
columns[i].pk = false;
columns[i].ai = false;
}
}
const query = this.sqlClient.schema.createTable(
args.table,
function (table) {
const multiplePks = [];
const columns = JSON.parse(JSON.stringify(args.columns));
if (multiplePks.length > 1) {
// copy PKs to new array and set PK metadata to false in original columns
for (let i = 0; i < columns.length; ++i) {
columnCreate(args.sqlClient, table, columns[i]);
if (columns[i].pk) {
multiplePks.push(i);
columns[i].pk = false;
columns[i].ai = false;
}
}
createPks(table, args.columns, multiplePks);
} else {
for (let i = 0; i < args.columns.length; ++i) {
columnCreate(args.sqlClient, table, args.columns[i]);
if (multiplePks.length > 1) {
for (let i = 0; i < columns.length; ++i) {
columnCreate(args.sqlClient, table, columns[i]);
}
createPks(table, args.columns, multiplePks);
} else {
for (let i = 0; i < args.columns.length; ++i) {
columnCreate(args.sqlClient, table, args.columns[i]);
}
}
}
});
},
);
await this.sqlClient.raw(query.toQuery());
/** ************** create up & down statements *************** */
const upStatement = this.sqlClient.schema
@ -1799,7 +1814,9 @@ class KnexClient extends SqlClient {
args.table = args.tn;
/** ************** create table *************** */
await this.sqlClient.schema.renameTable(args.tn_old, args.tn);
await this.sqlClient.raw(
this.sqlClient.schema.renameTable(args.tn_old, args.tn).toQuery(),
);
/** ************** create up & down statements *************** */
const upStatement =
@ -2013,41 +2030,46 @@ class KnexClient extends SqlClient {
/** ************** END : has PK changed *************** */
/** ************** update table *************** */
await this.sqlClient.schema.alterTable(args.table, function (table) {
if (pksChanged) {
pkUpdate(table, args.columns, args.originalColumns);
} else {
for (let i = 0; i < args.columns.length; ++i) {
const column = find(originalColumns, {
cn: args.columns[i].cno,
});
if (args.columns[i].altered & 8) {
// TODO: If a column is getting renamed then
// any change to column data type
// or changes to other columns are ignored
renamed = true;
renamedUpDownStatement = renameColumn(
args.sqlClient,
args.connectionConfig,
table,
column,
args.columns[i],
);
result.data.object = renamedUpDownStatement;
} else if (args.columns[i].altered & 4) {
// col remove
removeColumn(table, args.columns[i], column);
} else if (args.columns[i].altered & 2) {
// col edit
columnUpdate(args.sqlClient, table, args.columns[i], column);
} else if (args.columns[i].altered & 1) {
// col addition
columnUpdate(args.sqlClient, table, args.columns[i], null);
const query = this.sqlClient.schema.alterTable(
args.table,
function (table) {
if (pksChanged) {
pkUpdate(table, args.columns, args.originalColumns);
} else {
for (let i = 0; i < args.columns.length; ++i) {
const column = find(originalColumns, {
cn: args.columns[i].cno,
});
if (args.columns[i].altered & 8) {
// TODO: If a column is getting renamed then
// any change to column data type
// or changes to other columns are ignored
renamed = true;
renamedUpDownStatement = renameColumn(
args.sqlClient,
args.connectionConfig,
table,
column,
args.columns[i],
);
result.data.object = renamedUpDownStatement;
} else if (args.columns[i].altered & 4) {
// col remove
removeColumn(table, args.columns[i], column);
} else if (args.columns[i].altered & 2) {
// col edit
columnUpdate(args.sqlClient, table, args.columns[i], column);
} else if (args.columns[i].altered & 1) {
// col addition
columnUpdate(args.sqlClient, table, args.columns[i], null);
}
}
}
}
});
},
);
await this.sqlClient.raw(query.toQuery());
// log.debug('after column change', r);
@ -2199,7 +2221,9 @@ class KnexClient extends SqlClient {
this.emit(`Success : ${upStatement}`);
/** ************** drop tn *************** */
await this.sqlClient.schema.dropTable(args.tn);
await this.sqlClient.raw(
this.sqlClient.schema.dropTable(args.tn).toQuery(),
);
/** ************** return files *************** */
result.data.object = {
@ -2234,7 +2258,7 @@ class KnexClient extends SqlClient {
args.table = args.tn;
// s = await this.sqlClient.schema.index(Object.keys(args.columns));
await this.sqlClient.schema.table(args.table, function (table) {
const query = this.sqlClient.schema.table(args.table, function (table) {
if (args.non_unique) {
table.index(args.columns, indexName);
} else {
@ -2242,6 +2266,8 @@ class KnexClient extends SqlClient {
}
});
await this.sqlClient.raw(query.toQuery());
const upStatement =
this.querySeparator() +
this.sqlClient.schema
@ -2305,7 +2331,7 @@ class KnexClient extends SqlClient {
args.table = args.tn;
// s = await this.sqlClient.schema.index(Object.keys(args.columns));
await this.sqlClient.schema.table(args.table, function (table) {
const query = this.sqlClient.schema.table(args.table, function (table) {
if (args.non_unique_original) {
table.dropIndex(args.columns, indexName);
} else {
@ -2313,6 +2339,8 @@ class KnexClient extends SqlClient {
}
});
await this.sqlClient.raw(query.toQuery());
const upStatement =
this.querySeparator() +
this.sqlClient.schema
@ -2385,7 +2413,7 @@ class KnexClient extends SqlClient {
},
);
await upQb;
await this.sqlClient.raw(upQb.toQuery());
const upStatement = this.querySeparator() + upQb.toQuery();
@ -2444,9 +2472,14 @@ class KnexClient extends SqlClient {
try {
// const self = this;
await this.sqlClient.schema.table(args.childTable, function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
});
const query = this.sqlClient.schema.table(
args.childTable,
function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
},
);
await this.sqlClient.raw(query.toQuery());
const upStatement =
this.querySeparator() +
@ -2456,16 +2489,19 @@ class KnexClient extends SqlClient {
})
.toQuery();
const downStatement =
this.querySeparator() +
(await this.sqlClient.schema
.table(args.childTable, function (table) {
table
.foreign(args.childColumn, foreignKeyName)
.references(args.parentColumn)
.on(args.parentTable);
})
.toQuery());
const downQuery = this.sqlClient.schema.table(
args.childTable,
function (table) {
table
.foreign(args.childColumn, foreignKeyName)
.references(args.parentColumn)
.on(args.parentTable);
},
);
await this.sqlClient.raw(downQuery.toQuery());
const downStatement = this.querySeparator() + downQuery.toQuery();
// let files = this.evolutionFilesCreate(args, upStatement, downStatement);
//

38
packages/nocodb/src/db/sql-client/lib/mysql/MysqlClient.ts

@ -355,20 +355,26 @@ class MysqlClient extends KnexClient {
try {
/** ************** START : create _evolution table if not exists *************** */
const exists = await this.sqlClient.schema.hasTable(args.tn);
const exists = await this.sqlClient.raw(
this.sqlClient.schema.hasTable(args.tn).toQuery(),
);
if (!exists) {
await this.sqlClient.schema.createTable(args.tn, function (table) {
table.increments();
table.string('title').notNullable();
table.string('titleDown').nullable();
table.string('description').nullable();
table.integer('batch').nullable();
table.string('checksum').nullable();
table.integer('status').nullable();
table.dateTime('created');
table.timestamps();
});
await this.sqlClient.raw(
this.sqlClient.schema
.createTable(args.tn, function (table) {
table.increments();
table.string('title').notNullable();
table.string('titleDown').nullable();
table.string('description').nullable();
table.integer('batch').nullable();
table.string('checksum').nullable();
table.integer('status').nullable();
table.dateTime('created');
table.timestamps();
})
.toQuery(),
);
log.debug('Table created:', `${args.tn}`);
} else {
log.debug(`${args.tn} tables exists`);
@ -411,7 +417,9 @@ class MysqlClient extends KnexClient {
log.api(`${func}:args:`, args);
try {
const response = await this.sqlClient.schema.hasTable(args.tn);
const response = await this.sqlClient.raw(
this.sqlClient.schema.hasTable(args.tn).toQuery(),
);
result.data.value = response;
} catch (e) {
log.ppe(e, func);
@ -2205,7 +2213,9 @@ class MysqlClient extends KnexClient {
this.emit(`Success : ${upStatement}`);
/** ************** drop table_name *************** */
await this.sqlClient.schema.dropTable(args.table_name);
await this.sqlClient.raw(
this.sqlClient.schema.dropTable(args.table_name).toQuery(),
);
/** ************** return files *************** */
result.data.object = {

68
packages/nocodb/src/db/sql-client/lib/pg/PgClient.ts

@ -575,19 +575,20 @@ class PGClient extends KnexClient {
);
if (exists.rows.length === 0) {
const data = await this.sqlClient.schema.createTable(
args.tn,
function (table) {
table.increments();
table.string('title').notNullable();
table.string('titleDown').nullable();
table.string('description').nullable();
table.integer('batch').nullable();
table.string('checksum').nullable();
table.integer('status').nullable();
table.dateTime('created');
table.timestamps();
},
const data = await this.sqlClient.raw(
this.sqlClient.schema
.createTable(args.tn, function (table) {
table.increments();
table.string('title').notNullable();
table.string('titleDown').nullable();
table.string('description').nullable();
table.integer('batch').nullable();
table.string('checksum').nullable();
table.integer('status').nullable();
table.dateTime('created');
table.timestamps();
})
.toQuery(),
);
log.debug('Table created:', `${args.tn}`, data);
} else {
@ -1039,11 +1040,12 @@ class PGClient extends KnexClient {
try {
// const self = this;
await this.sqlClient.schema.table(
args.childTableWithSchema,
function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
},
await this.sqlClient.raw(
this.sqlClient.schema
.table(args.childTableWithSchema, function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
})
.toQuery(),
);
const upStatement =
@ -1056,14 +1058,14 @@ class PGClient extends KnexClient {
const downStatement =
this.querySeparator() +
(await this.sqlClient.schema
this.sqlClient.schema
.table(args.childTableWithSchema, function (table) {
table
.foreign(args.childColumn, foreignKeyName)
.references(args.parentColumn)
.on(args.parentTableWithSchema);
})
.toQuery());
.toQuery();
result.data.object = {
upStatement: [{ sql: upStatement }],
@ -2507,9 +2509,8 @@ class PGClient extends KnexClient {
relationsList = relationsList.data.list;
for (const relation of relationsList) {
downQuery +=
this.querySeparator() +
(await this.sqlClient.schema
const query = this.sqlClient.raw(
this.sqlClient.schema
.table(relation.tn, function (table) {
table = table
.foreign(relation.cn, null)
@ -2523,7 +2524,12 @@ class PGClient extends KnexClient {
table.onDelete(relation.dr);
}
})
.toQuery());
.toQuery(),
);
downQuery += this.querySeparator() + query;
await query;
}
let indexList: any = await this.indexList(args);
@ -2565,7 +2571,9 @@ class PGClient extends KnexClient {
this.emit(`Success : ${upStatement}`);
/** ************** drop tn *************** */
await this.sqlClient.schema.dropTable(args.tn);
await this.sqlClient.raw(
this.sqlClient.schema.dropTable(args.tn).toQuery(),
);
/** ************** return files *************** */
result.data.object = {
@ -2989,9 +2997,13 @@ class PGClient extends KnexClient {
args.table = args.tn;
/** ************** create table *************** */
await this.sqlClient.schema.renameTable(
this.sqlClient.raw('??.??', [this.schema, args.tn_old]),
args.tn,
await this.sqlClient.raw(
this.sqlClient.schema
.renameTable(
this.sqlClient.raw('??.??', [this.schema, args.tn_old]),
args.tn,
)
.toQuery(),
);
/** ************** create up & down statements *************** */

35
packages/nocodb/src/models/Source.ts

@ -80,15 +80,15 @@ export default class Source implements SourceType {
insertObj,
);
// call before reorder to update cache
const returnBase = await this.get(id, false, ncMeta);
await NocoCache.appendToList(
CacheScope.BASE,
[source.baseId],
`${CacheScope.BASE}:${id}`,
);
// call before reorder to update cache
const returnBase = await this.get(id, false, ncMeta);
await this.reorderBases(source.baseId);
return returnBase;
@ -101,6 +101,7 @@ export default class Source implements SourceType {
skipReorder?: boolean;
meta?: any;
deleted?: boolean;
fk_sql_executor_id?: string;
},
ncMeta = Noco.ncMeta,
) {
@ -108,12 +109,6 @@ export default class Source implements SourceType {
if (!oldBase) NcError.badRequest('Wrong source id!');
await NocoCache.deepDel(
CacheScope.BASE,
`${CacheScope.BASE}:${sourceId}`,
CacheDelDirection.CHILD_TO_PARENT,
);
const updateObj = extractProps(source, [
'alias',
'config',
@ -125,6 +120,7 @@ export default class Source implements SourceType {
'enabled',
'meta',
'deleted',
'fk_sql_executor_id',
]);
if (updateObj.config) {
@ -151,17 +147,14 @@ export default class Source implements SourceType {
oldBase.id,
);
await NocoCache.appendToList(
CacheScope.BASE,
[source.baseId],
`${CacheScope.BASE}:${oldBase.id}`,
);
await NocoCache.del(`${CacheScope.BASE}:${sourceId}`);
// call before reorder to update cache
const returnBase = await this.get(oldBase.id, false, ncMeta);
if (!source.skipReorder)
if (!source.skipReorder && source.order && source.order !== oldBase.order) {
await this.reorderBases(source.baseId, returnBase.id, ncMeta);
}
return returnBase;
}
@ -312,12 +305,6 @@ export default class Source implements SourceType {
// update order for sources
for (const [i, b] of Object.entries(sources)) {
await NocoCache.deepDel(
CacheScope.BASE,
`${CacheScope.BASE}:${b.id}`,
CacheDelDirection.CHILD_TO_PARENT,
);
b.order = parseInt(i) + 1;
await ncMeta.metaUpdate(
@ -330,12 +317,6 @@ export default class Source implements SourceType {
b.id,
);
await NocoCache.appendToList(
CacheScope.BASE,
[b.base_id],
`${CacheScope.BASE}:${b.id}`,
);
await NocoCache.set(`${CacheScope.BASE}:${b.id}`, b);
}
}

46
packages/nocodb/src/services/columns.service.ts

@ -293,7 +293,7 @@ export class ColumnsService {
) {
// MultiSelect to SingleSelect
if (driverType === 'mysql' || driverType === 'mysql2') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = SUBSTRING_INDEX(??, ',', 1) WHERE ?? LIKE '%,%';`,
[
baseModel.getTnPath(table.table_name),
@ -303,13 +303,13 @@ export class ColumnsService {
],
);
} else if (driverType === 'pg') {
await dbDriver.raw(`UPDATE ?? SET ?? = split_part(??, ',', 1);`, [
await sqlClient.raw(`UPDATE ?? SET ?? = split_part(??, ',', 1);`, [
baseModel.getTnPath(table.table_name),
column.column_name,
column.column_name,
]);
} else if (driverType === 'mssql') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = LEFT(cast(?? as varchar(max)), CHARINDEX(',', ??) - 1) WHERE CHARINDEX(',', ??) > 0;`,
[
baseModel.getTnPath(table.table_name),
@ -320,7 +320,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'sqlite3') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = substr(??, 1, instr(??, ',') - 1) WHERE ?? LIKE '%,%';`,
[
baseModel.getTnPath(table.table_name),
@ -352,7 +352,7 @@ export class ColumnsService {
);
const data = await baseModel.execAndParse(
dbDriver.raw('SELECT DISTINCT ?? FROM ??', [
sqlClient.raw('SELECT DISTINCT ?? FROM ??', [
column.column_name,
baseModel.getTnPath(table.table_name),
]),
@ -535,7 +535,7 @@ export class ColumnsService {
}
if (column.uidt === UITypes.SingleSelect) {
if (driverType === 'mssql') {
await dbDriver.raw(`UPDATE ?? SET ?? = NULL WHERE ?? LIKE ?`, [
await sqlClient.raw(`UPDATE ?? SET ?? = NULL WHERE ?? LIKE ?`, [
baseModel.getTnPath(table.table_name),
column.column_name,
column.column_name,
@ -551,7 +551,7 @@ export class ColumnsService {
} else if (column.uidt === UITypes.MultiSelect) {
if (driverType === 'mysql' || driverType === 'mysql2') {
if (colBody.dt === 'set') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), ',')) WHERE FIND_IN_SET(?, ??)`,
[
baseModel.getTnPath(table.table_name),
@ -563,7 +563,7 @@ export class ColumnsService {
],
);
} else {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), ','))`,
[
baseModel.getTnPath(table.table_name),
@ -574,7 +574,7 @@ export class ColumnsService {
);
}
} else if (driverType === 'pg') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = array_to_string(array_remove(string_to_array(??, ','), ?), ',')`,
[
baseModel.getTnPath(table.table_name),
@ -584,7 +584,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'mssql') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = substring(replace(concat(',', ??, ','), concat(',', ?, ','), ','), 2, len(replace(concat(',', ??, ','), concat(',', ?, ','), ',')) - 2)`,
[
baseModel.getTnPath(table.table_name),
@ -596,7 +596,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'sqlite3') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(REPLACE(',' || ?? || ',', ',' || ? || ',', ','), ',')`,
[
baseModel.getTnPath(table.table_name),
@ -716,7 +716,7 @@ export class ColumnsService {
if (column.uidt === UITypes.SingleSelect) {
if (driverType === 'mssql') {
await dbDriver.raw(`UPDATE ?? SET ?? = ? WHERE ?? LIKE ?`, [
await sqlClient.raw(`UPDATE ?? SET ?? = ? WHERE ?? LIKE ?`, [
baseModel.getTnPath(table.table_name),
column.column_name,
newOp.title,
@ -733,7 +733,7 @@ export class ColumnsService {
} else if (column.uidt === UITypes.MultiSelect) {
if (driverType === 'mysql' || driverType === 'mysql2') {
if (colBody.dt === 'set') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), CONCAT(',', ?, ','))) WHERE FIND_IN_SET(?, ??)`,
[
baseModel.getTnPath(table.table_name),
@ -746,7 +746,7 @@ export class ColumnsService {
],
);
} else {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), CONCAT(',', ?, ',')))`,
[
baseModel.getTnPath(table.table_name),
@ -758,7 +758,7 @@ export class ColumnsService {
);
}
} else if (driverType === 'pg') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = array_to_string(array_replace(string_to_array(??, ','), ?, ?), ',')`,
[
baseModel.getTnPath(table.table_name),
@ -769,7 +769,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'mssql') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = substring(replace(concat(',', ??, ','), concat(',', ?, ','), concat(',', ?, ',')), 2, len(replace(concat(',', ??, ','), concat(',', ?, ','), concat(',', ?, ','))) - 2)`,
[
baseModel.getTnPath(table.table_name),
@ -783,7 +783,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'sqlite3') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(REPLACE(',' || ?? || ',', ',' || ? || ',', ',' || ? || ','), ',')`,
[
baseModel.getTnPath(table.table_name),
@ -802,7 +802,7 @@ export class ColumnsService {
const newOp = ch.def_option;
if (column.uidt === UITypes.SingleSelect) {
if (driverType === 'mssql') {
await dbDriver.raw(`UPDATE ?? SET ?? = ? WHERE ?? LIKE ?`, [
await sqlClient.raw(`UPDATE ?? SET ?? = ? WHERE ?? LIKE ?`, [
baseModel.getTnPath(table.table_name),
column.column_name,
newOp.title,
@ -819,7 +819,7 @@ export class ColumnsService {
} else if (column.uidt === UITypes.MultiSelect) {
if (driverType === 'mysql' || driverType === 'mysql2') {
if (colBody.dt === 'set') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), CONCAT(',', ?, ','))) WHERE FIND_IN_SET(?, ??)`,
[
baseModel.getTnPath(table.table_name),
@ -832,7 +832,7 @@ export class ColumnsService {
],
);
} else {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', ??, ','), CONCAT(',', ?, ','), CONCAT(',', ?, ',')))`,
[
baseModel.getTnPath(table.table_name),
@ -846,7 +846,7 @@ export class ColumnsService {
);
}
} else if (driverType === 'pg') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = array_to_string(array_replace(string_to_array(??, ','), ?, ?), ',')`,
[
baseModel.getTnPath(table.table_name),
@ -857,7 +857,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'mssql') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = substring(replace(concat(',', ??, ','), concat(',', ?, ','), concat(',', ?, ',')), 2, len(replace(concat(',', ??, ','), concat(',', ?, ','), concat(',', ?, ','))) - 2)`,
[
baseModel.getTnPath(table.table_name),
@ -871,7 +871,7 @@ export class ColumnsService {
],
);
} else if (driverType === 'sqlite3') {
await dbDriver.raw(
await sqlClient.raw(
`UPDATE ?? SET ?? = TRIM(REPLACE(',' || ?? || ',', ',' || ? || ',', ',' || ? || ','), ',')`,
[
baseModel.getTnPath(table.table_name),

2
packages/nocodb/src/services/tables.service.ts

@ -491,7 +491,7 @@ export class TablesService {
system?: boolean;
}
> = (
await sqlClient.columnList({
await sqlMgr.sqlOpPlus(source, 'columnList', {
tn: tableCreatePayLoad.table_name,
schema: source.getConfig()?.schema,
})

4
tests/playwright/pages/Dashboard/ProjectView/Metadata.ts

@ -18,7 +18,7 @@ export class MetaDataPage extends BasePage {
// todo: Remove this wait
await this.rootPage.waitForTimeout(100);
// await this.get().locator(`.animate-spin`).waitFor({state: 'visible'});
await this.get().locator(`.animate-spin`).waitFor({ state: 'detached' });
await this.get().locator(`.animate-spin`).waitFor({ state: 'detached', timeout: 10000 });
}
async close() {
@ -32,7 +32,7 @@ export class MetaDataPage extends BasePage {
await this.get().locator(`button:has-text("Sync Now")`).click();
await this.verifyToast({ message: 'Table metadata recreated successfully' });
await this.get().locator(`.animate-spin`).waitFor({ state: 'visible' });
await this.get().locator(`.animate-spin`).waitFor({ state: 'detached' });
await this.get().locator(`.animate-spin`).waitFor({ state: 'detached', timeout: 10000 });
}
async verifyRow({ index, model, state }: { index: number; model: string; state: string }) {

2
tests/playwright/tests/db/features/metaSync.spec.ts

@ -43,7 +43,7 @@ test.describe('Meta sync', () => {
await dbExec(`CREATE TABLE table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`);
await metaData.clickReload();
await dashboard.rootPage.waitForTimeout(1000);
await dashboard.rootPage.waitForTimeout(5000);
await metaData.verifyRow({
index: isPg(context) ? 21 : 16,

Loading…
Cancel
Save