{"action":"opened","issue":{"url":"https://api.github.com/repos/balderdashy/sails-mongo/issues/433","repository_url":"https://api.github.com/repos/balderdashy/sails-mongo","labels_url":"https://api.github.com/repos/balderdashy/sails-mongo/issues/433/labels{/name}","comments_url":"https://api.github.com/repos/balderdashy/sails-mongo/issues/433/comments","events_url":"https://api.github.com/repos/balderdashy/sails-mongo/issues/433/events","html_url":"https://github.com/balderdashy/sails-mongo/issues/433","id":189370401,"number":433,"title":"use both .native query and ORM sugar","user":{"login":"cyrilchapon","id":10728426,"avatar_url":"https://avatars.githubusercontent.com/u/10728426?v=3","gravatar_id":"","url":"https://api.github.com/users/cyrilchapon","html_url":"https://github.com/cyrilchapon","followers_url":"https://api.github.com/users/cyrilchapon/followers","following_url":"https://api.github.com/users/cyrilchapon/following{/other_user}","gists_url":"https://api.github.com/users/cyrilchapon/gists{/gist_id}","starred_url":"https://api.github.com/users/cyrilchapon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cyrilchapon/subscriptions","organizations_url":"https://api.github.com/users/cyrilchapon/orgs","repos_url":"https://api.github.com/users/cyrilchapon/repos","events_url":"https://api.github.com/users/cyrilchapon/events{/privacy}","received_events_url":"https://api.github.com/users/cyrilchapon/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-11-15T11:45:20Z","updated_at":"2016-11-15T11:45:20Z","closed_at":null,"body":"Hey.\r\n\r\nI'm trying to execute a query that would take advantage of native mongo stuff but also of ORM sugar (parsing blueprint queries to mongodb queries, sort, limit, etc). The process is this one :\r\n\r\n- Parse blueprint criteria to extract non standard field. done :\r\n```\r\n    let criteria = ActionUtilService.parseCriteria(req);\r\n    if(!criteria.geoWithin || !GeojsonUtilService.isPolygon(criteria.geoWithin))\r\n      return res.badRequest('geoWithin');\r\n    let dbCriteria = _.omit(criteria, 'geoWithin');\r\n```\r\n\r\n- Parse standard blueprint / waterline query using both waterline and sails-mongo internal methods. I added a console.trace() [here](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/collection.js#L62) and looked up the stack trace to check where the normalization is done. For now I found [waterline's find](https://github.com/balderdashy/waterline/blob/b98978d7546acf0ad9dff85fb15945140a49d58c/lib/waterline/query/finders/basic.js#L194-L396) for waterline normalization, and sails-mongo's [Query() constructor](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/query/index.js#L13-L49) used in [collection.find()](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/collection.js#L53-L104)\r\n\r\n- Add it the non-standard clause (geoWithin in this case) and finally execute the query. It should be ok with a top-level `$and` I guess\r\n\r\n- Parse returned and hydrate standard waterline objects. I found [this line](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/collection.js#L102) which does the job, still inside `collection.find()` code\r\n\r\nI came up with this :\r\n```\r\nconst Promise = require('bluebird');\r\nconst Query = require('../../node_modules/sails-mongo/lib/query');\r\nconst utils = require('../../node_modules/sails-mongo/lib/utils');\r\nconst normalize = require('../../node_modules/waterline/lib/waterline/utils/normalize.js');\r\n\r\nmodule.exports = {\r\n\r\n  attributes: {\r\n    geometry: {\r\n      type: 'json',\r\n      object: true\r\n    }\r\n  },\r\n  findWithin: function(criteria, geometry, options) {\r\n    let self = this;\r\n    criteria = criteria || {};\r\n    options = options || {};\r\n  \r\n  \r\n  \r\n  \r\n  \r\n    // ##### WATERLINE NORMALIZATION\r\n    //From https://github.com/balderdashy/waterline/blob/b98978d7546acf0ad9dff85fb15945140a49d58c/lib/waterline/query/finders/basic.js#L194-L396\r\n    // If the criteria is an array of objects, wrap it in an \"or\"\r\n    if (Array.isArray(criteria) && _.all(criteria, function(crit) {return _.isObject(crit);})) {\r\n      criteria = {or: criteria};\r\n    }\r\n  \r\n    // Check if criteria is an integer or string and normalize criteria\r\n    // to object, using the specified primary key field.\r\n    criteria = normalize.expandPK(self, criteria);\r\n  \r\n    // Normalize criteria\r\n    criteria = normalize.criteria(criteria);\r\n  \r\n    // Fold in options\r\n    if (options === Object(options) && criteria === Object(criteria)) {\r\n      criteria = _.extend({}, criteria, options);\r\n    }\r\n  \r\n    criteria = self._transformer.serialize(criteria);\r\n  \r\n  \r\n  \r\n  \r\n  \r\n    return Promise.promisify(ElementChunk.native, {multiArgs:true})()\r\n    .spread(function(collection, rawCollection){\r\n      return new Promise(function(resolve, reject) {\r\n  \r\n  \r\n        // ##### SAILS-MONGO NORMALIZATION\r\n        // From https://github.com/balderdashy/sails-mongo/blob/fa8fe160cf801e34684fc15c2deb918d9bf2bb11/lib/collection.js#L61-L104\r\n        let query;\r\n  \r\n        try {\r\n          query = new Query(criteria, self.schema);\r\n          // THIS IS INCORRECT         ^^^^^^^^\r\n        } catch(err) {\r\n          return reject(err);\r\n        }\r\n  \r\n        let where = query.criteria.where || {};\r\n        let queryOptions = _.omit(query.criteria, 'where');\r\n  \r\n        // Run Normal Query on collection\r\n        collection.find(where, query.select, queryOptions).toArray(function(err, docs) {\r\n          if(err) return reject(err);\r\n          resolve(utils.normalizeResults(docs, self.schema));\r\n          // THIS IS INCORRECT                      ^^^^^^^^\r\n        });\r\n      });\r\n    });\r\n  },\r\n```\r\n\r\n(For now I ommited the geowithin stuff to concentrate on re-implenting the whole normalization / query chain)\r\n\r\nAs you can see (`THIS IS INCORRECT`), for the strategy to work, both the `Query` constructor and the `normalizeResults` method require a **`schema`** property. After debugging, I found that the expected schema is **not** the raw waterline model's schema, but rather a parsed version that went through [`_parseDefinition`](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/collection.js#L353-L386) method...\r\n And I'm struggling at gathering this `schema`... It's aparently a property of the sails-mongo [`Collection`](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/collection.js) prototype, which is **NOT** equal to my model static `ElementChunk` nor `this` nor the returned `collection` property from `native()`. I tried everything to retrieve this `Collection` prototype,\r\n- chrome-debugging the code and trying to retreive it from my element (`ElementChunk`), it's model (`ElementChunk._model`), nested sails-mongo stuff (like `ElementChunk.adapter.connections.mongo._adapter`), returned `collection` from `native()` but the code is well protected and I failed at it.\r\n- using [`describe()`](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/adapter.js#L172-L192) method. But [this test](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/adapter.js#L189) doesn't returns `true`\r\n- changing [this line](https://github.com/balderdashy/sails-mongo/blob/f6a9ce422a460126a537f5d3684aea6cf6ca6883/lib/adapter.js#L259) to\r\n```\r\ncb(null, connectionObject.connection.db.collection(collectionName), connectionObject.collections[collectionName]);\r\n```\r\nand gathering third param in callback. **which worked** ! But it's dead ugly, and I don't want to fork sails mongo just for this.\r\n\r\nSo any idea ? 😄 Thanks !"}}
{"actor":{"display_login":"cyrilchapon"}}