Refactoring + suggestions
vitaly-t opened this issue · comments
Your library is fresh, but got some good attention already. There is a bit of code refactoring you're likely to do later on. And as far as the database goes, I'd like to help you ;)
You are using wait
everywhere, but it doesn't do anything useful.
this.wait = Promise.resolve()
Some of the code I'm not sure how it is expected to work on your side, like this example:
db.many('SELECT doc FROM unnest(ARRAY[$1]) WITH ORDINALITY AS u(id, ord) LEFT JOIN pgjson.main AS m ON m.id = u.id ORDER BY u.ord', [ids])
When your parameter ids
is an array, it will be automatically formatted as array[va1,val2,...]
, so when you are inserting it as ARRY[$1]
, it will produce ARRAY[array[val1, val2,...]]
. I'm not sure if that's the expected behaviour, so I just wanted to point out at it.
Another example for refactoring, method manyOrNone
has alias any
, in case you want to use it ;)
If you want to get a good sense of what and how is being executed exactly against the database, I would really suggest to use pg-monitor, and here's an example.
Strange, in my tests this query had the correct results, so maybe in this query there's actually no problem with having ARRAY[array[val1, val2,...]]
instead of array[val1, val2,...]
. Anyway, thank you for informing me. I need a tool like pg-monitor, I just didn't know it existed.
Thanks for getting back to me. I surely could find a lot more, but you have time to polish this thing ;)
var r = opts.descending ? 'DESC' : 'ASC'
- declared but not used variable ;)
It is being used here:
Line 139 in f085c3d
It sure needs a lot of polishing, but please keep finding bugs whenever you have time!
Ok, here's then the method refactored, to show better use of the query formatting:
pgjson.prototype.query = function (opts) {
opts = opts || {}
var o = opts.orderby
var db = this.db
return this.wait.then(function () {
var params = {
limit: opts.limit || 1000,
offset: opts.offset || 0,
order: opts.descending ? 'DESC' : 'ASC'
};
if (opts.orderby) {
var terms = o.split(/[\.[]/).map(function (t) {
if (t.slice(-1)[0] == ']') {
t = t.slice(0, -1)
if (!isNaN(parseInt(t))) {
return t
}
}
return "'" + t + "'";
});
params.criteria = terms.join('->');
return db.any("SELECT doc FROM pgjson.main ORDER BY doc->${criteria^} ${order^}, doc->'_id' ${order^} LIMIT ${limit} OFFSET ${offset}", params);
}
return db.any('SELECT doc FROM pgjson.main ORDER BY id LIMIT ${limit} OFFSET ${offset}', params);
})
.then(function (rows) {
return rows.map(function (r) {
return r.doc;
})
})
}
Query formatting in pg-promise is powerful, you do not need to use manual string concatenation ever ;)
I'm not quite sure about the expected output there, so wouldn't be wise refactoring without understanding the formatting logic well. If you ask me a more specific formatting question, I'd be able to help you there.
One thing for sure, introducing global variables like sql
:
Line 59 in fa83fcc
is advised against.
Yeah, that's a Coffeescript vice. Coffeescript, that language that is exactly equal to Javascript, but where you don't have to write "var" before variables.
@vitaly-t the goal there is to insert a lot of rows at the same time. How am I supposed to do that without all that string concatenation I'm doing?
Something like this:
pgjson.prototype.postBulk = function (docs) {
var db = this.db;
var ids = [];
return this.wait.then(function () {
return db.none("INSERT INTO pgjson.main (id, doc) VALUES $1^", docs.map(function (d) {
var id = cuid();
d._id = id;
ids.push(id);
return pgp.as.format("($1, $2)", [id, d]);
}).join(','));
})
.then(function () {
return {ok: true, ids: ids}
})
.catch(handle('problem posting docs'))
};
@vitaly-t I searched for documentation on this kind of formatting on pg-promise docs, but couldn't find it. what does ^
mean?
again, thank you very much.
@fiatjaf Symbol ^
- that's Raw Text Injection, quite useful in your case, and in general, when formatting gets complex or multi-part.
@fiatjaf version 2.3.0 just became friendlier when it comes to JSON object formatting.
For example, the same code we changed the last time can become:
pgjson.prototype.postBulk = function (docs) {
var db = this.db
var ids = []
var values = docs.map(function (doc) {
var id = cuid()
ids.push(id)
doc._id = id
return pgp.as.format("(${_id}, ${this})", doc)
}).join(',')
return this.wait.then(function () {
return db.none("INSERT INTO pgjson.main (id, doc) VALUES $1^", values)
}).then(function () {
return {ok: true, ids: ids}
}).catch(handle('problem posting docs'))
}
i.e. the change is in the line:
return pgp.as.format("(${_id}, ${this})", doc)
I presume that you deliberately inject doc
as a text string formatted as JSON instead of JSON object.