From 79464de3750bff3d68d4824d2cbc0e6675b82c44 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:44:27 -0300 Subject: [PATCH 01/15] Add create datasource from adapter --- lib/methods/create-datasource-from-adapter.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 lib/methods/create-datasource-from-adapter.js diff --git a/lib/methods/create-datasource-from-adapter.js b/lib/methods/create-datasource-from-adapter.js new file mode 100644 index 0000000..914439b --- /dev/null +++ b/lib/methods/create-datasource-from-adapter.js @@ -0,0 +1,11 @@ +module.exports = function(adapter, config, identity, schema, callback) { + adapter.registerDatastore({ host: config.host, + port: config.port, + schema: config.schema, + adapter: config.adapter, + user: config.user, + password: config.password, + database: config.database, + identity: identity + }, schema, callback); +} \ No newline at end of file From bf1fd5a3995b5a4cb1b215d88fea3bad22c6556c Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:44:42 -0300 Subject: [PATCH 02/15] Add adapter support --- lib/methods/adapter-support-verify.js | 65 +++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 lib/methods/adapter-support-verify.js diff --git a/lib/methods/adapter-support-verify.js b/lib/methods/adapter-support-verify.js new file mode 100644 index 0000000..6d63a93 --- /dev/null +++ b/lib/methods/adapter-support-verify.js @@ -0,0 +1,65 @@ +var flaverr = require('flaverr'); +var _ = require('@sailshq/lodash'); + +module.exports = function adapterSupportVerify(adapter, datastoreName) { + let genericDoesNotSupportDatastoreMethodsError; + + var GENERIC_UNSUPPORTED_DSM_ERROR_MSG_SUFFIX = ''+ + 'If there is an older/ newer version of this adapter, try updating the semver range for this dependency '+ + 'in your package.json file. If you aren\'t sure, check the repo on GitHub, or contact the adapter\'s '+ + 'maintainer. If you *are* the maintainer of this adapter and need help, visit http://sailsjs.com/support.'; + + // If this adapter doesn't expose its datastores, then we can't provide any + // functional datastore methods to allow userland code to work with them. + // + // > This is relevant for older adapters, or adapters which only support usage + // > via models. Note that this partial level of support may no longer be an + // > option in future versions of Sails and Waterline. + if (!_.has(adapter, 'datastores')) { + genericDoesNotSupportDatastoreMethodsError = flaverr('E_NOT_SUPPORTED', new Error( + 'The adapter used by the `' + datastoreName + '` datastore does not expose '+ + 'direct access to its internal datastore entries for use outside the adapter. '+ + '(It would need to set its own `datastores` property in order to use this method.)\n'+ + GENERIC_UNSUPPORTED_DSM_ERROR_MSG_SUFFIX + )); + } else { + + // Try to find the adapter datastore being used. + // + // > This should exist in a standardized form to allow us to talk directly to + // > the driver and access the live manager instance.) + var adapterDSEntry = adapter.datastores[datastoreName]; + + if (!adapterDSEntry) { + genericDoesNotSupportDatastoreMethodsError = flaverr('E_NOT_SUPPORTED', new Error( + 'The adapter used by the `' + datastoreName + '` datastore does not fully support '+ + 'this method. The adapter\'s exposed `datastores` dictionary is invalid, or is '+ + 'missing the expected entry for `' + datastoreName + '`. (There may be a bug! '+ + 'Or... this adapter might just not support the thing you\'re trying to do.)\n'+ + GENERIC_UNSUPPORTED_DSM_ERROR_MSG_SUFFIX + )); + } + else { + + // Validate that the raw adapter datastore entry we just located provides the right + // information in the right format. If it conforms to the spec, it should have + // `manager`, `driver`, and `config` keys. + // + // > Otherwise, we wouldn't actually be capable of running the datastore methods. + if (!_.has(adapterDSEntry, 'manager') || !_.has(adapterDSEntry, 'driver') || !_.has(adapterDSEntry, 'config')) { + genericDoesNotSupportDatastoreMethodsError = flaverr('E_NOT_SUPPORTED', new Error( + 'The adapter used by the `' + datastoreName + '` datastore does not fully support '+ + 'this method. The adapter exposes its internal datastore entries as `datastores`, '+ + 'and that dictionary even contains the expected datastore entry for `' + datastoreName + '`. '+ + 'But the entry is missing one or more mandatory keys, like `driver`, `manager`, '+ + 'or `config`. (There may be a bug! Or... this adapter might just not support '+ + 'the thing you\'re trying to do.)\n'+ + GENERIC_UNSUPPORTED_DSM_ERROR_MSG_SUFFIX + )); + } + + } + } + + return genericDoesNotSupportDatastoreMethodsError; +} \ No newline at end of file From e903794687677f47687db9b6f3db8781f784c58b Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:45:07 -0300 Subject: [PATCH 03/15] Add multitenancy send native query --- lib/internal/helpers/send-native-query.js | 146 ++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 lib/internal/helpers/send-native-query.js diff --git a/lib/internal/helpers/send-native-query.js b/lib/internal/helpers/send-native-query.js new file mode 100644 index 0000000..bc6be02 --- /dev/null +++ b/lib/internal/helpers/send-native-query.js @@ -0,0 +1,146 @@ +var _ = require('@sailshq/lodash'); +var parley = require('parley'); +var flaverr = require('flaverr'); +var _datasources = require('../../methods/getdatasources'); +var helpSendNativeQuery = require('sails-hook-orm/lib/datastore-method-utils/help-send-native-query'); +var adapterSupportVerify = require('../../methods/adapter-support-verify'); + +module.exports = function(req, _nativeQuery, _valuesToEscape, explicitCb, _meta, more) { + + // ███╗ ███╗██╗ ██╗██╗ ████████╗██╗████████╗███████╗███╗ ██╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗ + // ████╗ ████║██║ ██║██║ ╚══██╔══╝██║╚══██╔══╝██╔════╝████╗ ██║██╔══██╗████╗ ██║██╔════╝╚██╗ ██╔╝ + // ██╔████╔██║██║ ██║██║ ██║ ██║ ██║ █████╗ ██╔██╗ ██║███████║██╔██╗ ██║██║ ╚████╔╝ + // ██║╚██╔╝██║██║ ██║██║ ██║ ██║ ██║ ██╔══╝ ██║╚██╗██║██╔══██║██║╚██╗██║██║ ╚██╔╝ + // ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║ ██║ ███████╗██║ ╚████║██║ ██║██║ ╚████║╚██████╗ ██║ + // ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ + + const _self = this; + _self.datastore = _self.s_datastore; + var ignore_tenancy = true; + // Get datasource + const datasources = _datasources(null, true); + // Define the args array to get the tenancy var + var args = Array.from(arguments); + // Tenancy req argument analisis + if ((typeof args[0] === 'string' && typeof args[1] === 'string') + || typeof args[0] === 'object') { + if(typeof args[0] === 'string' && datasources.searchStringIdentity(args[0])) { + ignore_tenancy = false; + } else if (typeof args[0] === 'object' && (args[0].constructor.name === 'IncomingMessage' || args[0].constructor.name === 'DataStoreConfig')) { + ignore_tenancy = false; + } else { + _nativeQuery = args[0]; + _valuesToEscape = args[1]; + explicitCb = args[2]; + _meta = args[3]; + more = args[4] + } + } else { + _nativeQuery = args[0]; + _valuesToEscape = args[1]; + explicitCb = args[2]; + _meta = args[3]; + more = args[4] + } + + // Handle variadic usage: + // ``` + // sendNativeQuery('foo', function(){...}) + // ``` + + if (arguments.length === 2 && _.isFunction(_valuesToEscape)) { + explicitCb = _valuesToEscape; + _valuesToEscape = undefined; + } + // ``` + // sendNativeQuery('foo', function(){...}, ()=>{…}) + // ``` + else if (arguments.length === 3 && _.isFunction(_valuesToEscape)) { + _meta = explicitCb; + explicitCb = _valuesToEscape; + _valuesToEscape = undefined; + } + + return parley(function _handleExec(done){ + + // ████████╗ ███████╗███████╗██╗ ███████╗ ██████╗████████╗ ██████╗ ██████╗ + // ╚══██╔══╝ ██╔════╝██╔════╝██║ ██╔════╝██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗ + // ██║ ███████╗█████╗ ██║ █████╗ ██║ ██║ ██║ ██║██████╔╝ + // ██║ ╚════██║██╔══╝ ██║ ██╔══╝ ██║ ██║ ██║ ██║██╔══██╗ + // ██║██╗ ███████║███████╗███████╗███████╗╚██████╗ ██║ ╚██████╔╝██║ ██║ + // ╚═╝╚═╝ ╚══════╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ + + sails.nativeTenancy(req, ignore_tenancy, _self).then(datastore => { + + const adapter = sails.hooks.orm.adapters[datastore.config.adapter]; + let genericDoesNotSupportDatastoreMethodsError = adapterSupportVerify(adapter, datastore.name); + + // Verifiy driver query capability + var driverMethodNames = _.keys(datastore.driver); + + var isConnectable = _.difference([ + 'createManager', + 'destroyManager', + 'getConnection', + 'releaseConnection' + ], driverMethodNames) + .length === 0; + + var isQueryable = isConnectable && _.difference([ + 'sendNativeQuery', + 'compileStatement', + 'parseNativeQueryResult', + 'parseNativeQueryError' + ], driverMethodNames) + .length === 0; + + if (genericDoesNotSupportDatastoreMethodsError) { + return done(genericDoesNotSupportDatastoreMethodsError); + } + + var options = { + manager: datastore.manager, + driver: datastore.driver, + connection: undefined, + + nativeQuery: _nativeQuery, + valuesToEscape: _valuesToEscape, + meta: _meta, + }; + + if (more) { + _.extend(options, more); + } + + if (!isQueryable) { + return done(flaverr('E_NOT_SUPPORTED', new Error( + 'Cannot use `.sendNativeQuery()` with this datastore because the underlying adapter '+ + 'does not implement the "queryable" interface layer. This may be because of a '+ + 'natural limitation of the technology, or it could just be that the adapter\'s '+ + 'developer(s) have not finished implementing one or more driver methods.' + ))); + } + + if (!options.nativeQuery) { + return done(flaverr({ name: 'UsageError' }, new Error( + 'Invalid native query passed in to `.sendNativeQuery()`. (Must be truthy-- e.g. "SELECT * FROM foo")' + ))); + } + + helpSendNativeQuery(options, done); + }); + }, explicitCb, { + + meta: function(_meta){ + options.meta = _meta; + return this; + }, + + usingConnection: function(_usingConnection){ + options.connection = _usingConnection; + return this; + }, + + });// + +}; \ No newline at end of file From 83b537182bfe2a644b3e2a29a6d665fb0d71d9f7 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:45:32 -0300 Subject: [PATCH 04/15] Remove unused code archive --- lib/internal/querys/archive.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/internal/querys/archive.js b/lib/internal/querys/archive.js index a39f624..0c9cd76 100644 --- a/lib/internal/querys/archive.js +++ b/lib/internal/querys/archive.js @@ -144,8 +144,6 @@ module.exports = function archive(/* criteria, explicitCbMaybe, metaContainer */ query.meta = args[1]; } - - // ██████╗ ███████╗███████╗███████╗██████╗ // ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗ // ██║ ██║█████╗ █████╗ █████╗ ██████╔╝ @@ -192,6 +190,7 @@ module.exports = function archive(/* criteria, explicitCbMaybe, metaContainer */ // This ensures a normalized format. // Make the tenancy decition _self.tenancy(req, ignore_tenancy).then(model => { + try { forgeStageTwoQuery(query, orm); } catch (err) { @@ -248,7 +247,7 @@ module.exports = function archive(/* criteria, explicitCbMaybe, metaContainer */ // Then just leverage those methods here in `.archive()`. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // console.log(WLModel); // ╔═╗═╗ ╦╔═╗╔═╗╦ ╦╔╦╗╔═╗ ┌─┐┬┌┐┌┌┬┐ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬ // ║╣ ╔╩╦╝║╣ ║ ║ ║ ║ ║╣ ├┤ ││││ ││ │─┼┐│ │├┤ ├┬┘└┬┘ // ╚═╝╩ ╚═╚═╝╚═╝╚═╝ ╩ ╚═╝ └ ┴┘└┘─┴┘ └─┘└└─┘└─┘┴└─ ┴ From 1bc36d3ec2f2141298a35f1576bb903a857dd657 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:46:05 -0300 Subject: [PATCH 05/15] Method add adapter datasource created --- lib/methods/add-adapter-datasource.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 lib/methods/add-adapter-datasource.js diff --git a/lib/methods/add-adapter-datasource.js b/lib/methods/add-adapter-datasource.js new file mode 100644 index 0000000..c426065 --- /dev/null +++ b/lib/methods/add-adapter-datasource.js @@ -0,0 +1,22 @@ +var datasources = require('./getdatasources'); +var d = require('./datasource'); + +module.exports = function(sails, SchemaMap, config, identity) { + return new Promise(async (resolve,reject) => { + // Method to create a datasource in all models + const d_config = new d.datasource(config.host, config.port, config.schema, config.adapter, config.user, config.password, config.database); + d_config.identity = "Mt_" + Buffer.from(identity).toString('base64') + "_" + identity; + + let adapter = sails.hooks.orm.adapters[config.adapter]; + const _datasources = datasources(null, true); + + if(!_datasources.search(d_config.identity)) { + adapter.registerDatastore(d_config, SchemaMap, function(){ + console.log("Datasource " + identity + " registered."); + resolve(_self); + }); + } else { + resolve(_self); + } + }) +} \ No newline at end of file From dc890ae946ef185a9e990a832e3b4b823ab4cbe2 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:46:50 -0300 Subject: [PATCH 06/15] Fix string addDatasource --- lib/methods/adddatasource.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/methods/adddatasource.js b/lib/methods/adddatasource.js index 3840330..8c18b30 100644 --- a/lib/methods/adddatasource.js +++ b/lib/methods/adddatasource.js @@ -5,7 +5,7 @@ module.exports = function(Model, _self, sails, SchemaMap, config, identity) { return new Promise(async (resolve,reject) => { // Method to create a datasource in all models const d_config = new d.datasource(config.host, config.port, config.schema, config.adapter, config.user, config.password, config.database); - d_config.identity = "Mt_"+Buffer.from(identity).toString('base64')+"_"+identity; + d_config.identity = "Mt_" + Buffer.from(identity).toString('base64') + "_" + identity; // Iterate all models models_count = Object.keys(sails.hooks.orm.models).length; models_process = 0; @@ -13,9 +13,9 @@ module.exports = function(Model, _self, sails, SchemaMap, config, identity) { const model = sails.hooks.orm.models[key]; const _datasources = datasources(model); // Create the datasource only if not exists - if(!_datasources.search(identity)) { + if(!_datasources.search(d_config.identity)) { model._adapter.registerDatastore(d_config, SchemaMap, function(){ - console.log("Datasource "+identity+" registered."); + console.log("Datasource " + d_config.identity + " registered."); if(++models_process == models_count) resolve(_self); }); } else { From 38e0ab694cb2749872257a9a0e1409ca379bb9e7 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:47:04 -0300 Subject: [PATCH 07/15] Remove unused lines in create --- lib/internal/querys/create.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/querys/create.js b/lib/internal/querys/create.js index 42502fe..3eceaf2 100644 --- a/lib/internal/querys/create.js +++ b/lib/internal/querys/create.js @@ -180,6 +180,7 @@ module.exports = function create(newRecord, explicitCbMaybe, metaContainer) { // Forge a stage 2 query (aka logical protostatement) // This ensures a normalized format. _self.tenancy(req, ignore_tenancy).then(model => { + try { forgeStageTwoQuery(query, orm); } catch (e) { From 291d65db80a9d92ff89b6ad55b18f3310f85018d Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:49:06 -0300 Subject: [PATCH 08/15] get Tenancy datastore method add to get multitenancy datastore and driver --- lib/methods/get-tenancy-datastore.js | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 lib/methods/get-tenancy-datastore.js diff --git a/lib/methods/get-tenancy-datastore.js b/lib/methods/get-tenancy-datastore.js new file mode 100644 index 0000000..16c636d --- /dev/null +++ b/lib/methods/get-tenancy-datastore.js @@ -0,0 +1,86 @@ +var datasources = require("./getdatasources"); +var createDatasource = require("./createdatasource"); +const loadAdapterFromAppDependencies = require('sails-hook-orm/lib/load-adapter-from-app-dependencies'); +const validateAdapter = require('sails-hook-orm/lib/validate-adapter'); +const createDatasourceFromAdapter = require('./create-datasource-from-adapter'); + +var d = require("./datasource"); + +module.exports = function getTenancyAdapter(req, datasource, sails) { + const _self = this; + const adapters = sails.hooks.orm.adapters; + return new Promise(async (resolve, reject) => { + // Check the type of call used for multitenant + if (req && req.constructor.name === "IncomingMessage") { + if (typeof sails.config.multitenancy !== "function") { + throw new Error( + "The multitenancy configuration function is not defined. Please define a configuration option to use the Request Object Way." + ); + } + + const config = await sails.config.multitenancy(req); + if (!config) { + throw new Error( + "The tenant selection is undefined, please check your tenancy selector function" + ); + } + if (!adapters[config.adapter]) { + const newAdapter = loadAdapterFromAppDependencies(config.adapter, config.indentity, sails); + if (!newAdapter) newAdapter = validateAdapter(config.adapter, config.indentity); + if (!newAdapter) { + throw new Error( + "The adapter driver not exist or the custom adapter is not set" + ); + } + sails.hooks.orm.adapters[config.adapter] = newAdapter; + } + + const _datasource = datasources(null, true); + if (_datasource.search(config.identity)) { + resolve(_datasource[config.identity]); + } else { + if (d.isDatasource(config) && config.identity) { + const adapter = adapters[config.adapter]; + var _newdatasource = new d.datasource(config.host, config.port, + config.schema, config.adapter, config.user, config.password, + config.database); + await createDatasourceFromAdapter(adapter, _newdatasource, config.identity, config.schema, function() { + adapter.datastores[config.identity].name = config.identity; + sails.hooks.orm.datastores[config.identity] = adapter.datastores[config.identity]; + resolve(adapter.datastores[config.identity]); + }); + } else { + throw new Error( + "The return of multitenancy configuration function is not adaptable to Datasource Object. Please check the properties of Datasource object in the configuration function" + ); + } + } + } else if (req && req.constructor.name === "DataStoreConfig") { + const hash = Buffer.from(JSON.stringify(req)).toString("base64"); + const _datasource = datasources(null, true); + if (_datasource.search(hash)) { + resolve(_datasource[hash]); + } else { + await createDatasourceFromAdapter(adapter, req, hash, req.schema, function() { + adapter.datastores[config.identity].name = hash; + sails.hooks.orm.datastores[config.identity] = adapter.datastores[config.identity]; + resolve(adapter.datastores[config.identity]); + }); + } + } else if (req && typeof req === "string") { + const _datasource = datasources(null, true); + const m64identity = Buffer.from(req).toString("base64"); + if (_datasource.search("Mt_" + m64identity + "_"+ req)) { + resolve(_datasource["Mt_" + m64identity + "_" + req]); + } else { + throw new Error( + "The datasource " + + req + + "was not created. Please create the datasource to use with the name." + ); + } + } else { + resolve(datasource); + } + }); +}; From c8fa1a909be40a85fcdec623d5bd65b1ef830640 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:50:32 -0300 Subject: [PATCH 09/15] Modify main datastores --- lib/methods/getdatasources.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/methods/getdatasources.js b/lib/methods/getdatasources.js index 9089fef..afa9419 100644 --- a/lib/methods/getdatasources.js +++ b/lib/methods/getdatasources.js @@ -1,6 +1,6 @@ -module.exports = function getDatasources(model) { +module.exports = function getDatasources(model, main) { // extract the datasources from model - var datastores = Object.keys(model._adapter.datastores); + var datastores = (main) ? Object.keys(sails.hooks.orm.datastores) : Object.keys(model._adapter.datastores); return { collection: datastores, search: function(identity) { @@ -8,8 +8,8 @@ module.exports = function getDatasources(model) { return false; }, searchStringIdentity: function(identity) { - const m64identity = Buffer.from(req).toString('base64'); - if (datastores.indexOf("Mt_"+m64identity+"_cf") != -1) return true; + const m64identity = Buffer.from(identity).toString('base64'); + if (datastores.indexOf("Mt_" + m64identity+ "_" + identity) != -1) return true; return false; } }; From bd4e803874a08c3ab3aa7a2739eb470bc987cb3c Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:50:54 -0300 Subject: [PATCH 10/15] Fix datastore string selection on multitenant --- lib/methods/multitenant.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/methods/multitenant.js b/lib/methods/multitenant.js index 6e0000c..48d1e32 100644 --- a/lib/methods/multitenant.js +++ b/lib/methods/multitenant.js @@ -42,8 +42,8 @@ module.exports = function multitenant(req, model, self, sails, schema, WLModel) } else if (req && typeof req === 'string') { const _datasource = datasources(model); const m64identity = Buffer.from(req).toString('base64'); - if(_datasource.search("Mt_"+m64identity+"_cf")) { - _self.datastore = "Mt_"+m64identity+"_cf"; + if(_datasource.search("Mt_" + m64identity + "_" + req)) { + _self.datastore = "Mt_" + m64identity + "_" + req; resolve(_self); } else { throw new Error('The datasource ' + req + 'was not created. Please create the datasource to use with the name.'); From 3bdac9594560cd1c63c0720c72e77f1cc955093d Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:51:10 -0300 Subject: [PATCH 11/15] Add send Native querys to GetDatastore method --- lib/internal/methods.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/internal/methods.js b/lib/internal/methods.js index 594733b..d5c7900 100644 --- a/lib/internal/methods.js +++ b/lib/internal/methods.js @@ -14,6 +14,7 @@ var removeFromCollection = require('./querys/remove-from-collection'); var replaceCollection = require('./querys/replace-collection'); var addToCollection = require('./querys/add-to-collection'); var validate = require('./querys/validate'); +const sendNativeQuery = require('../internal/helpers/send-native-query'); module.exports = { create: create, @@ -35,10 +36,16 @@ module.exports = { getDatastore: function(req) { const _self = this; _self.datastore = _self.s_datastore; - if(!req) return _self.s_getDatastore(); + if (!req) { + let datastore = _self.s_getDatastore(); + datastore.sendNativeQuery = sendNativeQuery.bind(datastore); + return datastore; + } return new Promise(async (resolve,reject) => { _self.tenancy(req).then((model_in) => { - resolve(model_in.s_getDatastore()); + let datastore = model_in.s_getDatastore(); + datastore.sendNativeQuery = sendNativeQuery.bind(datastore); + resolve(datastore); }); }); } From b87de93d6e20b83b82c5f9f7fcd47c423f98a8dc Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:51:30 -0300 Subject: [PATCH 12/15] Add native query support to hook --- lib/initialize.js | 54 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/initialize.js b/lib/initialize.js index 199d6b1..229a396 100644 --- a/lib/initialize.js +++ b/lib/initialize.js @@ -1,19 +1,22 @@ var schemas = require('./methods/getschemas'); var multitenant = require('./methods/multitenant'); var addDatasource = require('./methods/adddatasource'); +var addDatasourceAdapter = require('./methods/add-adapter-datasource'); var d = require('./methods/datasource'); var actions = require('./internal/methods'); +const sendNativeQuery = require('./internal/helpers/send-native-query'); +const getTenancyDatastore = require('./methods/get-tenancy-datastore'); module.exports = function inicialize(sails, cb) { - console.log - (` + console.log(` ========================================================== - _____ _____ _ _ _____ __ __ _____ -| ___| | _ | | | | | | ___| | \\/ | |_ _| -| |___ | |_| | | | | | | |___ | | | | -|____ | | _ | | | | | |____ | | |\\/| | | | - ___| | | | | | | | | |__ ___| | | | | | | | -|_____| |_| |_| |_| |____||_____| |_| |_| |_| + +███████╗ █████╗ ██╗██╗ ███████╗ ███╗ ███╗████████╗ +██╔════╝██╔══██╗██║██║ ██╔════╝ ████╗ ████║╚══██╔══╝ +███████╗███████║██║██║ ███████╗ ██╔████╔██║ ██║ +╚════██║██╔══██║██║██║ ╚════██║ ██║╚██╔╝██║ ██║ +███████║██║ ██║██║███████╗███████║ ██║ ╚═╝ ██║ ██║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ Waterline Multitenant ORM Project License: MIT @@ -37,10 +40,18 @@ If you use the Request Object way, please define a multitenancy function in a co ================================================================================`) }; - // Alter the schemas to add Multitenancy properties + // ███╗ ███╗ ██████╗ ██████╗ ███████╗██╗ ███████╗ + // ████╗ ████║██╔═══██╗██╔══██╗██╔════╝██║ ██╔════╝ + // ██╔████╔██║██║ ██║██║ ██║█████╗ ██║ ███████╗ + // ██║╚██╔╝██║██║ ██║██║ ██║██╔══╝ ██║ ╚════██║ + // ██║ ╚═╝ ██║╚██████╔╝██████╔╝███████╗███████╗███████║ + // ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ + + // Alter the schemas to add Multitenancy properties for (let key in sails.hooks.orm.models) { let Model = sails.hooks.orm.models[key]; + // Add the tenancy function to make posible the multitenancy select Model.tenancy = async function(req, ignore_tenancy, ParentModel) { const _self = this; @@ -81,6 +92,31 @@ If you use the Request Object way, please define a multitenancy function in a co Model[key] = actions[key]; } } + + // ███╗ ██╗ █████╗ ████████╗██╗██╗ ██╗███████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗ + // ████╗ ██║██╔══██╗╚══██╔══╝██║██║ ██║██╔════╝ ██╔═══██╗██║ ██║██╔════╝██╔══██╗╚██╗ ██╔╝ + // ██╔██╗ ██║███████║ ██║ ██║██║ ██║█████╗ ██║ ██║██║ ██║█████╗ ██████╔╝ ╚████╔╝ + // ██║╚██╗██║██╔══██║ ██║ ██║╚██╗ ██╔╝██╔══╝ ██║▄▄ ██║██║ ██║██╔══╝ ██╔══██╗ ╚██╔╝ + // ██║ ╚████║██║ ██║ ██║ ██║ ╚████╔╝ ███████╗ ╚██████╔╝╚██████╔╝███████╗██║ ██║ ██║ + // ╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ + + sails.sendNativeQuery = sendNativeQuery.bind(sails.getDatastore()); + // Add the tenancy function to make posible the multitenancy select + sails.nativeTenancy = async function(req, ignore_tenancy, datasource) { + // If the model not have a multitenant return self; + if (ignore_tenancy) { + return datasource; + } + // If diferent go to search the multitentant; + return await getTenancyDatastore(req, datasource, sails); + } + // Add addDatasource + sails.addDatasource = async function(identity, config){ + const _self = this; + if(config.constructor.name === 'DataStoreConfig'){ + return await addDatasourceAdapter(sails, SchemaMap, config, identity); + } + } }) // Do some stuff here to initialize hooks // And then call `cb` to continue From b10dc202e24ae2adf479a5561447335866ff6bc5 Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 21:52:06 -0300 Subject: [PATCH 13/15] Modify version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fe8c9a3..ab7313a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sails-hook-multitenant", - "version": "0.5.19", + "version": "0.6.1", "description": "A multi tenancy ORM hook to transform Waterline ORM into Multitenant ORM for Sails.js 1.X", "main": "index.js", "sails": { From 9a3aff7390a7132f2cbee92567ba39a721456c5b Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 22:09:41 -0300 Subject: [PATCH 14/15] Updating readme --- README.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 590c124..12e504b 100644 --- a/README.md +++ b/README.md @@ -388,12 +388,35 @@ afterDestroy(newRecord, proceed, req); ``` -## 6. Examples +## 6. Native Queries + +The hook support native queries in each adapters that can support sendNativeQuery Method. + +To use native query method in the datastore, we can use the same ways used in the ORM methods to interact with database using the three posible ways to handle multitenancy shown in this hook. + +To use native queries you can use this ways, if you want use request object. + + +```javascript +let QUERY = "SELECT * FROM test_table"; + +// Using native queries from sails object, using request object +let query = await sails.sendNativeQuery(req, QUERY); + +// Using native queries from model, using request object +// Test is a declared Sails Model. +let query = Test.getDatastore().sendNativeQuery(req, QUERY); + +``` + +If you want to use Datasource creation or Configuration object Way, you can use them like a Multi Tenancy model action, replacing request object with the with the corresponding variables. + +## 7. Examples An example project for study is in the example folder. If you have any question of how to use, or any question, please contact. -## 7. Tests +## 8. Tests Follow the Sails documentation, the hook is tested with mocha. ```bash @@ -431,7 +454,7 @@ Git: https://www.github.com/acalvoa/sails-hook-multitenant ``` -## 8. Contributors +## 9. Contributors Thanks to all people that can do this possible. @@ -440,7 +463,7 @@ Thanks to all people that can do this possible. **Knownledge is power, share the Knownledge.** -## 9. License +## 10. License This project is develop by Parley for free use by the community, under MIT license. Made with ❤ in Chile From 8dc504c3a44fe930513f9dc0a36af95342878a6f Mon Sep 17 00:00:00 2001 From: Angelo Calvo Alfaro Date: Sun, 29 Sep 2019 22:14:12 -0300 Subject: [PATCH 15/15] Clean code --- lib/internal/querys/validate.js | 1 - lib/methods/get-tenancy-datastore.js | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/internal/querys/validate.js b/lib/internal/querys/validate.js index d6b1e2b..e8ea878 100644 --- a/lib/internal/querys/validate.js +++ b/lib/internal/querys/validate.js @@ -6,7 +6,6 @@ var _ = require('@sailshq/lodash'); var flaverr = require('flaverr'); var normalizeValueToSet = require('waterline/lib/waterline/utils/query/private/normalize-value-to-set'); var verifyModelMethodContext = require('waterline/lib/waterline/utils/query/verify-model-method-context'); -var _datasources = require('../../methods/getdatasources'); /** diff --git a/lib/methods/get-tenancy-datastore.js b/lib/methods/get-tenancy-datastore.js index 16c636d..38992c7 100644 --- a/lib/methods/get-tenancy-datastore.js +++ b/lib/methods/get-tenancy-datastore.js @@ -1,5 +1,4 @@ var datasources = require("./getdatasources"); -var createDatasource = require("./createdatasource"); const loadAdapterFromAppDependencies = require('sails-hook-orm/lib/load-adapter-from-app-dependencies'); const validateAdapter = require('sails-hook-orm/lib/validate-adapter'); const createDatasourceFromAdapter = require('./create-datasource-from-adapter');