Skip to content

Commit

Permalink
Add uuid type with primary key coercion (#32)
Browse files Browse the repository at this point in the history
* Coerce uuid primary keys

Adds a check to normalize.expandPK on uuid type primary keys, and
coerces them to a UUID-patterned string.

Adds normalize.expandPK to deferred so that chained `where` calls also
coerce the criteria.

* Add test for uuid primary key coercion

Adds a test in the finder query test for checking that UUIDs get
defered. The PK coercion behavior doesn't seem to be tested at this
level, but this seems like the most appropriate place.

* Throw TypeError when given non-uuid

Changes primary key type coercion on UUIDs to throw a TypeError when
attempting to coerce a value that is not a UUID.

* Add a comment around coercing uuids

* Simplify test for primary key normalization in deferred queries

This removes the uuid-specific test for testing normalization of primary
keys in deferred queries. This behavior can more simply be checked with
the pre-existing test setup by simply checking that string
representations of integers are properly coerced to their integer form.

* Only coerce uuid primary keys when schema is uuid

Change normalize.expandPK to only coerce the uuid when the underlying
schema is reported as UUID as well.

* Address PR feedback

Fix typo and pull out UUID regex.
  • Loading branch information
dgb committed May 18, 2016
1 parent 9f9dd1e commit 624690d
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 1 deletion.
3 changes: 3 additions & 0 deletions lib/waterline/query/deferred.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ Deferred.prototype.where = function(criteria) {

if(!criteria) return this;

// Normalize any primary keys in criteria
criteria = normalize.expandPK(this._context, criteria);

// Normalize criteria
criteria = normalize.criteria(criteria);

Expand Down
20 changes: 20 additions & 0 deletions lib/waterline/utils/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var switchback = require('node-switchback');
var errorify = require('../error');
var WLUsageError = require('../error/WLUsageError');

var uuidPattern = /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/i

var normalize = module.exports = {

// Expand Primary Key criteria into objects
Expand Down Expand Up @@ -50,6 +52,24 @@ var normalize = module.exports = {
else if (context.attributes[pk].type == 'string') {
coercePK = function(pk) {return String(pk).toString();};
}

// If the the data type is uuid (both according to the model definition
// as well as the database schema) attempt to coerce the value to a
// properly formatted uuid, stripping any extraneous characters from it.
else if (context.attributes[pk].type == 'uuid' &&
context.schema &&
context.schema[pk] &&
context.schema[pk].type == 'uuid') {
coercePK = function(pk) {
var matches = uuidPattern.exec(pk);
var uuid = matches && matches[0];
if (uuid) {
return uuid;
} else {
throw new TypeError("value '" + pk + "' cannot be coerced to UUID");
}
};
}
// If the data type is unspecified, return the key as-is
else {
coercePK = function(pk) {return pk;};
Expand Down
10 changes: 10 additions & 0 deletions test/unit/query/query.find.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ describe('Collection Query', function() {
});
});

it('should normalize primary keys when using deferreds', function(done) {
query.find()
.where({ id: '123' })
.exec(function(err, results) {
assert(!err);
assert(results[0].where.id === 123);
done();
});
});

describe('.paginate()', function() {
it('should skip to 0 and limit to 10 by default', function(done) {
query.find()
Expand Down
126 changes: 125 additions & 1 deletion test/unit/utils/utils.normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,128 @@ describe("Normalize utility", function() {

});

});
describe(".expandPK()", function() {
it("casts integers", function() {
var context = {
attributes: {
id: {
type: 'integer',
primaryKey: true
}
}
};

var options = {
id: '123'
}

var result = normalize.expandPK(context, options);

assert(result.id === 123);
});

it("casts uuids", function() {
var context = {
attributes: {
id: {
type: 'uuid',
primaryKey: true
}
},
schema: {
id: {
type: 'uuid'
}
}
};

var options = {
id: 'prefix_0b6c28e0-a117-4a9e-9a0d-60f0992edbee'
}

var result = normalize.expandPK(context, options);

assert(result.id === '0b6c28e0-a117-4a9e-9a0d-60f0992edbee');
});

it("casts uuids with capitals", function() {
var context = {
attributes: {
id: {
type: 'uuid',
primaryKey: true
}
},
schema: {
id: {
type: 'uuid'
}
}
};

var options = {
id: '0B6C28E0-A117-4A9E-9A0D-60F0992EDBEE'
}

var result = normalize.expandPK(context, options);

assert(result.id === '0B6C28E0-A117-4A9E-9A0D-60F0992EDBEE');
});

it("does not cast uuids with an underlying non-uuid type", function() {
var context = {
attributes: {
id: {
type: 'uuid',
primaryKey: true
}
},
schema: {
id: {
type: 'text'
}
}
};

var options = {
id: 'prefix_0b6c28e0-a117-4a9e-9a0d-60f0992edbee'
}

var result = normalize.expandPK(context, options);

assert(result.id === 'prefix_0b6c28e0-a117-4a9e-9a0d-60f0992edbee');

});

it("throws a TypeError when attempting to cast a non-uuid", function() {
var context = {
attributes: {
id: {
type: 'uuid',
primaryKey: true
}
},
schema: {
id: {
type: 'uuid'
}
}
};

var options = {
id: 'hello'
}

try {
normalize.expandPK(context, options);
throw new Error('wrong error');
} catch (e) {
assert(e);
assert(e instanceof TypeError);
assert(e.message === "value 'hello' cannot be coerced to UUID");
}

});
});

});

0 comments on commit 624690d

Please sign in to comment.