Browse Source

fix: MSSQL connection with different schema

re #438

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/445/head
Pranav C 3 years ago
parent
commit
a34b10a30e
  1. 8
      packages/nocodb/package-lock.json
  2. 2
      packages/nocodb/package.json
  3. 46
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts
  4. 8
      packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts
  5. 8
      packages/nocodb/src/lib/migrator/SqlMigrator/lib/KnexMigrator.ts
  6. 2
      packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts

8
packages/nocodb/package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.11.11", "version": "0.11.13",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -11817,9 +11817,9 @@
"integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw==" "integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw=="
}, },
"nc-help": { "nc-help": {
"version": "0.2.11", "version": "0.2.12",
"resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.11.tgz", "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.12.tgz",
"integrity": "sha512-588PlynqD01a6XXR1jX5mYqP2kXrkXeCv4bpPAElumiwJKdFZI/A5maaAQU7yVz/t7Qid1Lwz9TUyMG/XTptzg==", "integrity": "sha512-fuKK0EbtZr5L5Jil47D6M/CbVPvpSATYI6y745hIv2NsYKF4XXv+/YwJARXmrD/pTSCop8YyJ6DapLXpFJ700g==",
"requires": { "requires": {
"axios": "^0.21.1", "axios": "^0.21.1",
"boxen": "^4.2.0", "boxen": "^4.2.0",

2
packages/nocodb/package.json

@ -145,7 +145,7 @@
"mysql2": "^2.2.5", "mysql2": "^2.2.5",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-common": "0.0.6", "nc-common": "0.0.6",
"nc-help": "^0.2.11", "nc-help": "^0.2.12",
"nc-lib-gui": "^0.2.16", "nc-lib-gui": "^0.2.16",
"nc-plugin": "^0.1.1", "nc-plugin": "^0.1.1",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",

46
packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts

@ -118,8 +118,14 @@ class BaseModelSql extends BaseModel {
* *
* @returns {Object} knex instance attached to a table * @returns {Object} knex instance attached to a table
*/ */
get $db() { public get $db() {
return this.dbDriver(this.tn); return this.dbDriver(this.tnPath);
}
public get tnPath(){
const schema = (this.dbDriver as any).searchPath?.();
const table = this.isMssql() && schema ? this.dbDriver.raw('??.??', [schema, this.tn]) : this.tn;
return table;
} }
/** /**
@ -258,7 +264,7 @@ class BaseModelSql extends BaseModel {
await this.validate(insertObj); await this.validate(insertObj);
const query = driver(this.tn).insert(insertObj); const query = driver(this.tnPath).insert(insertObj);
if (this.isPg() || this.dbDriver.clientType() === 'mssql') { if (this.isPg() || this.dbDriver.clientType() === 'mssql') {
query.returning(Object.entries(this.aliasToColumn).map(([val, key]) => `${key} as ${val}`)); query.returning(Object.entries(this.aliasToColumn).map(([val, key]) => `${key} as ${val}`));
@ -321,7 +327,7 @@ class BaseModelSql extends BaseModel {
const driver = trx ? trx : this.dbDriver const driver = trx ? trx : this.dbDriver
// this.validate(data); // this.validate(data);
const response = await this._run(driver(this.tn).update(mappedData).where(this._wherePk(id))); const response = await this._run(driver(this.tnPath).update(mappedData).where(this._wherePk(id)));
await this.afterUpdate(data, trx, cookie); await this.afterUpdate(data, trx, cookie);
return response; return response;
} catch (e) { } catch (e) {
@ -345,7 +351,7 @@ class BaseModelSql extends BaseModel {
const dbDriver = trx ? trx : this.dbDriver; const dbDriver = trx ? trx : this.dbDriver;
const response = await this._run(dbDriver(this.tn).del().where(this._wherePk(id))); const response = await this._run(dbDriver(this.tnPath).del().where(this._wherePk(id)));
await this.afterDelete({id}, trx, cookie); await this.afterDelete({id}, trx, cookie);
return response; return response;
} catch (e) { } catch (e) {
@ -378,7 +384,7 @@ class BaseModelSql extends BaseModel {
await this.validate(insertObj); await this.validate(insertObj);
Object.assign(insertObj, this._whereFk({parentId, tnp})) Object.assign(insertObj, this._whereFk({parentId, tnp}))
const query = dbDriver(this.tn).insert(insertObj); const query = dbDriver(this.tnPath).insert(insertObj);
if (this.dbDriver.clientType() === 'pg' || this.dbDriver.clientType() === 'mssql') { if (this.dbDriver.clientType() === 'pg' || this.dbDriver.clientType() === 'mssql') {
query.returning(this.selectQuery('')); query.returning(this.selectQuery(''));
@ -438,7 +444,7 @@ class BaseModelSql extends BaseModel {
const dbDriver = trx ? trx : this.dbDriver; const dbDriver = trx ? trx : this.dbDriver;
// this.validate(data); // this.validate(data);
const response = await this._run(dbDriver(this.tn).update(data).where(this._wherePk(id)).andWhere(this._whereFk({ const response = await this._run(dbDriver(this.tnPath).update(data).where(this._wherePk(id)).andWhere(this._whereFk({
tnp, tnp,
parentId parentId
}))); })));
@ -469,7 +475,7 @@ class BaseModelSql extends BaseModel {
const driver = trx ? trx : this.dbDriver const driver = trx ? trx : this.dbDriver
const response = await this._run(driver(this.tn).update(data).xwhere(where, this.selectQuery('')).condition(condition, this.selectQuery(''))); const response = await this._run(driver(this.tnPath).update(data).xwhere(where, this.selectQuery('')).condition(condition, this.selectQuery('')));
// await this.afterUpdate(data); // await this.afterUpdate(data);
return response; return response;
@ -497,7 +503,7 @@ class BaseModelSql extends BaseModel {
await this.beforeDelete({id, parentId, tnp}, trx, cookie); await this.beforeDelete({id, parentId, tnp}, trx, cookie);
const dbDriver = trx ? trx : this.dbDriver; const dbDriver = trx ? trx : this.dbDriver;
const response = await this._run(dbDriver(this.tn).del().where(this._wherePk(id)).andWhere(this._whereFk({ const response = await this._run(dbDriver(this.tnPath).del().where(this._wherePk(id)).andWhere(this._whereFk({
tnp, tnp,
parentId parentId
}))); })));
@ -525,7 +531,7 @@ class BaseModelSql extends BaseModel {
const driver = trx ? trx : this.dbDriver const driver = trx ? trx : this.dbDriver
const response = await this._run(driver(this.tn).del().xwhere(where, this.selectQuery('')).condition(condition, this.selectQuery(''))); const response = await this._run(driver(this.tnPath).del().xwhere(where, this.selectQuery('')).condition(condition, this.selectQuery('')));
// await this.afterUpdate(data); // await this.afterUpdate(data);
return response; return response;
@ -1123,7 +1129,7 @@ class BaseModelSql extends BaseModel {
parent.map(p => { parent.map(p => {
const query = const query =
this this
.dbDriver(child) .dbDriver(this.dbModels[child].tnPath)
.where(cn, p[this.columnToAlias?.[this.pks[0].cn] || this.pks[0].cn]) .where(cn, p[this.columnToAlias?.[this.pks[0].cn] || this.pks[0].cn])
.xwhere(where, this.dbModels[child].selectQuery('')) .xwhere(where, this.dbModels[child].selectQuery(''))
.select(this.dbModels[child].selectQuery(fields)) // ...fields.split(',')); .select(this.dbModels[child].selectQuery(fields)) // ...fields.split(','));
@ -1178,7 +1184,7 @@ class BaseModelSql extends BaseModel {
parentIds.map(id => { parentIds.map(id => {
const query = const query =
this this
.dbDriver(child) .dbDriver(this.dbModels[child].tnPath)
.join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`) .join(vtn, `${vtn}.${vrcn}`, `${rtn}.${rcn}`)
.where(`${vtn}.${vcn}`, id) // p[this.columnToAlias?.[this.pks[0].cn] || this.pks[0].cn]) .where(`${vtn}.${vcn}`, id) // p[this.columnToAlias?.[this.pks[0].cn] || this.pks[0].cn])
.xwhere(where, this.dbModels[child].selectQuery('')) .xwhere(where, this.dbModels[child].selectQuery(''))
@ -1221,7 +1227,7 @@ class BaseModelSql extends BaseModel {
fields = `${child}.*` fields = `${child}.*`
} }
const query = this.dbDriver(child) const query = this.dbDriver(this.dbModels[child].tnPath)
// .select(...fields.split(',')) // .select(...fields.split(','))
.select(this.dbModels?.[child]?.selectQuery(fields) || fields) .select(this.dbModels?.[child]?.selectQuery(fields) || fields)
.where(cn, parentId) .where(cn, parentId)
@ -1421,7 +1427,7 @@ class BaseModelSql extends BaseModel {
.condition(condition, childModel.selectQuery('')) .condition(condition, childModel.selectQuery(''))
.conditionGraph(conditionGraph) .conditionGraph(conditionGraph)
.whereNotIn(rcn, .whereNotIn(rcn,
childModel.dbDriver(rtn) childModel.dbDriver(this.dbModels[rtn].tnPath)
.select(`${rtn}.${rcn}`) .select(`${rtn}.${rcn}`)
.join(vtn, `${rtn}.${rcn}`, `${vtn}.${vrcn}`) .join(vtn, `${rtn}.${rcn}`, `${vtn}.${vrcn}`)
.where(`${vtn}.${vcn}`, pid) .where(`${vtn}.${vcn}`, pid)
@ -1450,7 +1456,7 @@ class BaseModelSql extends BaseModel {
.condition(condition, childModel.selectQuery('')) .condition(condition, childModel.selectQuery(''))
.conditionGraph(conditionGraph) .conditionGraph(conditionGraph)
.whereNotIn(rcn, .whereNotIn(rcn,
childModel.dbDriver(rtn) childModel.dbDriver(this.dbModels[rtn].tnPath)
.select(`${rtn}.${rcn}`) .select(`${rtn}.${rcn}`)
.join(vtn, `${rtn}.${rcn}`, `${vtn}.${vrcn}`) .join(vtn, `${rtn}.${rcn}`, `${vtn}.${vrcn}`)
.where(`${vtn}.${vcn}`, pid) .where(`${vtn}.${vcn}`, pid)
@ -1521,7 +1527,7 @@ class BaseModelSql extends BaseModel {
} }
const parents = await this._run( const parents = await this._run(
this.dbDriver(parent) this.dbDriver(this.dbModels[parent].tnPath)
// .select(...fields.split(',') // .select(...fields.split(',')
.select( .select(
this.dbModels[parent].selectQuery(fields) this.dbModels[parent].selectQuery(fields)
@ -1562,7 +1568,7 @@ class BaseModelSql extends BaseModel {
const childs = await this._run(this._paginateAndSort(this.dbDriver.union( const childs = await this._run(this._paginateAndSort(this.dbDriver.union(
ids.map(p => { ids.map(p => {
const query = this const query = this
.dbDriver(child) .dbDriver(this.dbModels[child].tnPath)
.where({[cn]: p}) .where({[cn]: p})
.conditionGraph(conditionGraph) .conditionGraph(conditionGraph)
.xwhere(where, this.selectQuery('')) .xwhere(where, this.selectQuery(''))
@ -1588,6 +1594,10 @@ class BaseModelSql extends BaseModel {
return this.clientType === 'sqlite3'; return this.clientType === 'sqlite3';
} }
isMssql() {
return this.clientType === 'mssql';
}
/** /**
* Returns key value paired grouped children list * Returns key value paired grouped children list
* *
@ -1609,7 +1619,7 @@ class BaseModelSql extends BaseModel {
const childs = await this._run(this.dbDriver.unionAll( const childs = await this._run(this.dbDriver.unionAll(
ids.map(p => { ids.map(p => {
const query = this const query = this
.dbDriver(child) .dbDriver(this.dbModels[child].tnPath)
.where({[cn]: p}) .where({[cn]: p})
.xwhere(where, this.selectQuery('')) .xwhere(where, this.selectQuery(''))
.conditionGraph(conditionGraph) .conditionGraph(conditionGraph)

8
packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts

@ -678,7 +678,7 @@ function parseNestedCondition(obj, qb, pKey?, table?, tableAlias?) {
type CustomKnex = Knex; type CustomKnex = Knex;
function CustomKnex(arg: string | Knex.Config<any>): CustomKnex { function CustomKnex(arg: string | Knex.Config<any>|any): CustomKnex {
const knex: any = Knex(arg); const knex: any = Knex(arg);
@ -706,6 +706,12 @@ function CustomKnex(arg: string | Knex.Config<any>): CustomKnex {
return typeof arg === 'string' ? arg.match(/^(\w+):/) ?? [1] : arg.client; return typeof arg === 'string' ? arg.match(/^(\w+):/) ?? [1] : arg.client;
} }
}, },
searchPath: {
enumerable: true,
value: () => {
return arg?.searchPath?.[0]
}
}
}); });
/** /**

8
packages/nocodb/src/lib/migrator/SqlMigrator/lib/KnexMigrator.ts

@ -501,7 +501,7 @@ export default class KnexMigrator extends SqlMigrator {
args.env args.env
); );
const sqlClient = args.sqlClient || SqlClientFactory.create(connection); const sqlClient = args.sqlClient || SqlClientFactory.create(connection);
const migrations = await sqlClient.selectAll(connection.meta.tn); const migrations = await sqlClient.selectAll(sqlClient.getTnPath(connection.meta.tn));
/** ************** END : get files and migrations *************** */ /** ************** END : get files and migrations *************** */
if (files.length === migrations.length) { if (files.length === migrations.length) {
@ -667,7 +667,7 @@ export default class KnexMigrator extends SqlMigrator {
vm.emit(`'${query}' : Executed SQL query`); vm.emit(`'${query}' : Executed SQL query`);
} }
for (const data of metaTableInserts) { for (const data of metaTableInserts) {
await trx(connection.meta.tn).insert(data); await trx(sqlClient.getTnPath(connection.meta.tn)).insert(data);
vm.emit(`'${data.title}' : Updating bookkeeping of SQL UP migration - done`); vm.emit(`'${data.title}' : Updating bookkeeping of SQL UP migration - done`);
} }
await trx.commit(); await trx.commit();
@ -743,7 +743,7 @@ export default class KnexMigrator extends SqlMigrator {
args.env args.env
); );
const sqlClient = SqlClientFactory.create(connection); const sqlClient = SqlClientFactory.create(connection);
const migrations = await sqlClient.selectAll(connection.meta.tn); const migrations = await sqlClient.selectAll(sqlClient.getTnPath(connection.meta.tn));
if (migrations.length) { if (migrations.length) {
try { try {
@ -820,7 +820,7 @@ export default class KnexMigrator extends SqlMigrator {
} }
for (const condition of metaDownDeletes) { for (const condition of metaDownDeletes) {
vm.emit(`'${condition.titleDown}' : Updating bookkeeping of SQL DOWN migration - done`); vm.emit(`'${condition.titleDown}' : Updating bookkeeping of SQL DOWN migration - done`);
await trx(connection.meta.tn).where(condition).del(); await trx(sqlClient.getTnPath(connection.meta.tn)).where(condition).del();
} }

2
packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts

@ -1762,4 +1762,4 @@ export class RestApiBuilder extends BaseApiBuilder<Noco> {
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */

Loading…
Cancel
Save