Skip to content

Commit

Permalink
Merge pull request #148 from vitaly-t/optimus
Browse files Browse the repository at this point in the history
Optimus
  • Loading branch information
vitaly-t committed May 23, 2016
2 parents cac6332 + ecd3ccb commit 21021d3
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 282 deletions.
19 changes: 5 additions & 14 deletions lib/query.js
Expand Up @@ -78,21 +78,12 @@ function $query(ctx, query, values, qrm, config) {
if (!pgFormatting && !$npm.utils.isText(query)) {
errMsg = isFunc ? "Invalid function name." : "Invalid query format.";
}
if (query instanceof PreparedStatement) {
var ps = query.parse(ctx.db.client.secretKey);
if (ps instanceof PreparedStatementError) {
errMsg = ps;
if (query instanceof QueryParameter) {
var qp = query.parse();
if (qp instanceof Error) {
errMsg = qp;
} else {
query = ps;
}
} else {
if (query instanceof ParameterizedQuery) {
var pq = query.parse();
if (pq instanceof ParameterizedQueryError) {
errMsg = pq;
} else {
query = pq;
}
query = qp;
}
}
}
Expand Down
57 changes: 32 additions & 25 deletions lib/queryFile.js
Expand Up @@ -71,7 +71,7 @@ var $npm = {
* @returns {QueryFile}
*
* @see QueryFileError
*
*
* @example
* // File sql.js
*
Expand Down Expand Up @@ -159,47 +159,54 @@ function QueryFile(file, options) {
* @method QueryFile.prepare
* @summary Prepares the query for execution.
* @description
* If the the query hasn't been prepared yet, it will read the file
* and process the contents according to the parameters passed into
* the constructor.
* If the the query hasn't been prepared yet, it will read the file and process the contents according
* to the parameters passed into the constructor.
*
* This method is meant primarily for internal use by the library.
*
* @returns {Boolean}
* The indication of a successful unchanged result:
* - `true` - successful and unchanged result
* - `false` - either changed or unsuccessful result
*/
this.prepare = function () {
var lastMod;
if (opt.debug && ready) {
try {
lastMod = $npm.fs.statSync(file).mtime.getTime();
if (lastMod !== modTime) {
ready = false;
if (lastMod === modTime) {
return true;
}
ready = false;
} catch (e) {
sql = undefined;
ready = false;
error = e;
return;
return false;
}
}
if (!ready) {
try {
sql = $npm.fs.readFileSync(file, 'utf8');
modTime = lastMod || $npm.fs.statSync(file).mtime.getTime();
if (opt.minify && !after) {
sql = $npm.minify(sql, {compress: opt.compress});
}
if (opt.params !== undefined) {
sql = $npm.format(sql, opt.params, {partial: true});
}
if (opt.minify && after) {
sql = $npm.minify(sql, {compress: opt.compress});
}
ready = true;
error = undefined;
} catch (e) {
sql = undefined;
error = new $npm.QueryFileError(e, this);
if (ready) {
return true;
}
try {
sql = $npm.fs.readFileSync(file, 'utf8');
modTime = lastMod || $npm.fs.statSync(file).mtime.getTime();
if (opt.minify && !after) {
sql = $npm.minify(sql, {compress: opt.compress});
}
if (opt.params !== undefined) {
sql = $npm.format(sql, opt.params, {partial: true});
}
if (opt.minify && after) {
sql = $npm.minify(sql, {compress: opt.compress});
}
ready = true;
error = undefined;
} catch (e) {
sql = undefined;
error = new $npm.QueryFileError(e, this);
}
return false;
};

/**
Expand Down
187 changes: 127 additions & 60 deletions lib/types/parameterized.js
Expand Up @@ -7,8 +7,6 @@ var $npm = {
QueryFile: require('../queryFile')
};

var advancedProperties = ['binary', 'rowMode'];

/**
* @constructor ParameterizedQuery
* @description
Expand Down Expand Up @@ -78,59 +76,113 @@ function ParameterizedQuery(text, values) {
return new ParameterizedQuery(text, values);
}

var currentError, PQ = {}, changed = true, state = {
text: text,
values: values,
binary: undefined,
rowMode: undefined
};

/**
* @name ParameterizedQuery#text
* @type {string|QueryFile}
* @description
* A non-empty query string or a {@link QueryFile} object.
*/
this.text = text;
Object.defineProperty(this, 'text', {
get: function () {
return state.text;
},
set: function (value) {
if (value !== state.text) {
state.text = value;
changed = true;
}
}
});

/**
* @name ParameterizedQuery#values
* @type {Array}
* @description
* Query formatting values. It can be either an `Array` or `null`/`undefined`.
*/
this.values = values;
Object.defineProperty(this, 'values', {
get: function () {
return state.values;
},
set: function (value) {
if (value !== state.values) {
state.values = value;
if ($npm.utils.isNull(value) || Array.isArray(value)) {
PQ.values = value;
} else {
changed = true;
}
}
}
});

/**
* @name ParameterizedQuery#binary
* @type {Boolean}
* @description
* Activates binary result mode. The default is the text mode.
*
* @see {@link http://www.postgresql.org/docs/devel/static/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY Extended Query}
*/
Object.defineProperty(this, 'binary', {
get: function () {
return state.binary;
},
set: function (value) {
if (value !== state.binary) {
state.binary = value;
changed = true;
}
}
});

/**
* @name ParameterizedQuery#rowMode
* @type {String}
* @description
* Changes the way data arrives to the client, with only one value supported by $[pg]:
* - `rowMode = 'array'` will make all data rows arrive as arrays of values.
* By default, rows arrive as objects.
*/
Object.defineProperty(this, 'rowMode', {
get: function () {
return state.rowMode;
},
set: function (value) {
if (value !== state.rowMode) {
state.rowMode = value;
changed = true;
}
}
});

/**
* @name ParameterizedQuery#error
* @type {ParameterizedQueryError}
* @readonly
* @description
* When in an error state, it is set to a {@link ParameterizedQueryError} object. Otherwise, it is `undefined`.
*
* This property is meant primarily for internal use by the library.
*/
this.error = undefined;
Object.defineProperty(this, 'error', {
get: function () {
return currentError;
}
});

if ($npm.utils.isObject(text, ['text'])) {
this.text = text.text;
this.values = text.values;

/**
* @name ParameterizedQuery#binary
* @type {Boolean}
* @description
* Activates binary result mode. The default is the text mode.
*
* @see {@link http://www.postgresql.org/docs/devel/static/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY Extended Query}
*/

/**
* @name ParameterizedQuery#rowMode
* @type {String}
* @description
* Changes the way data arrives to the client, with only one value supported by $[pg]:
* - `rowMode = 'array'` will make all data rows arrive as arrays of values.
* By default, rows arrive as objects.
*/

advancedProperties.$forEach(function (prop) {
if (prop in text) {
this[prop] = text[prop];
}
}, this);
state.text = text.text;
state.values = text.values;
state.binary = text.binary;
state.rowMode = text.rowMode;
}

/**
Expand All @@ -144,45 +196,57 @@ function ParameterizedQuery(text, values) {
* @returns {{text, values}|ParameterizedQueryError}
*/
this.parse = function () {
this.error = undefined;
var errors = [], pq = {};
if (this.text instanceof $npm.QueryFile) {
var qf = this.text;

var qf = state.text instanceof $npm.QueryFile ? state.text : null;

if (!changed && !qf) {
return PQ;
}

changed = true;
PQ = {};
currentError = undefined;
var errors = [];

if (qf) {
qf.prepare();
if (qf.error) {
pq.text = this.text;
PQ.text = state.text;
errors.push(qf.error);
} else {
pq.text = qf.query;
PQ.text = qf.query;
}
} else {
pq.text = this.text;
PQ.text = state.text;
}
if (!$npm.utils.isText(pq.text)) {
if (!$npm.utils.isText(PQ.text)) {
errors.push("Property 'text' must be a non-empty text string.");
}
if (!$npm.utils.isNull(this.values)) {
if (Array.isArray(this.values)) {
if (this.values.length > 0) {
pq.values = this.values;
if (!$npm.utils.isNull(state.values)) {
if (Array.isArray(state.values)) {
if (state.values.length > 0) {
PQ.values = state.values;
}
} else {
errors.push("Property 'values' must be an array or null/undefined.");
}
}

advancedProperties.$forEach(function (prop) {
if (prop in this) {
pq[prop] = this[prop];
}
}, this);
if (state.binary !== undefined) {
PQ.binary = state.binary;
}

if (state.rowMode !== undefined) {
PQ.rowMode = state.rowMode;
}

if (errors.length) {
this.error = new $npm.errors.ParameterizedQueryError(errors[0], pq);
return this.error;
return currentError = new $npm.errors.ParameterizedQueryError(errors[0], PQ);
}

return pq;
changed = false;

return PQ;
};
}

Expand All @@ -201,20 +265,23 @@ function ParameterizedQuery(text, values) {
ParameterizedQuery.prototype.toString = function (level) {
level = level > 0 ? parseInt(level) : 0;
var gap = $npm.utils.messageGap(level + 1);
var ps = this.parse();
var pq = this.parse();
var lines = [
'ParameterizedQuery {',
gap + 'text: ' + JSON.stringify(ps.text)
'ParameterizedQuery {'
];
if ($npm.utils.isText(pq.text)) {
lines.push(gap + 'text: "' + pq.text + '"');
}
if (this.values !== undefined) {
lines.push(gap + 'values: ' + JSON.stringify(this.values));
}
advancedProperties.$forEach(function (prop) {
if (prop in this) {
lines.push(gap + prop + ': ' + JSON.stringify(this[prop]));
}
}, this);
if (this.error) {
if (this.binary !== undefined) {
lines.push(gap + 'binary: ' + JSON.stringify(this.binary));
}
if (this.rowMode !== undefined) {
lines.push(gap + 'rowMode: ' + JSON.stringify(this.rowMode));
}
if (this.error !== undefined) {
lines.push(gap + 'error: ' + this.error.toString(level + 1));
}
lines.push($npm.utils.messageGap(level) + '}');
Expand Down

0 comments on commit 21021d3

Please sign in to comment.