Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add uuid type with primary key coercion #32

Merged
merged 7 commits into from
May 18, 2016
Merged

Add uuid type with primary key coercion #32

merged 7 commits into from
May 18, 2016

Conversation

dgb
Copy link

@dgb dgb commented May 13, 2016

https://www.pivotaltracker.com/story/show/117363295

This patch adds coercion behavior when a model attribute is specified as a uuid type and designated a primary key. This is similar to existing behavior in waterline where numbers and strings are coerced, and this patch extends this behavior. In other words, you can pass {id: 'foo_0b6c28e0-a117-4a9e-9a0d-60f0992edbee'} to a .where and waterline will strip the "foo_" from the id.

Note that this will not coerce uuid types that aren't primary keys. There's no mechanism in waterline for this (that I know of), so it'd be a larger change, both behavior and code-wise.

Derek Barnes added 2 commits April 22, 2016 12:37
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.
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.
coercePK = function(pk) {
var pattern = /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/i
var matches = pattern.exec(pk);
return matches && matches[0];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return null if the input doesn't match the uuid pattern. Do we care? Or should this throw an error (TypeError maybe?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather throw an error, though let's check to make sure the callers wrap this in a try/catch block.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er, oh. I believe we'll still pass this to lusitania at some point?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should do the UUID validation there https://github.com/shyp/lusitania

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the right place for this. From what I can tell, the coercion/normalization behavior is supposed to be independent of the higher level model-level validation, because it's on the query criteria, and not the model instance, and gets used on reads (AFAICT there's no validation on reads). "foo_abc123..." isn't invalid per-se, it's like passing "123" to an integer primary key.

As for errors, I don't think you can have a null primary key in PG, but "this should never happen" is a good reason to throw. I believe it'll behave like a WLError being thrown when something goes wrong with the query--otherwise I don't think there are any other errors being thrown in the places where these are being called (e.g. here). I can look a little further into that and see what's normal/expected in the caller.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok SGTM. any chance we can add a small doc block explaining what's going on?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Should it be doc'd anywhere else you know of?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i mean there's a waterline-docs project but we don't really use that :( maybe api/db or something, I don't know

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah I can put a note in the API about how to use this when I get the trackingevents stuff up.

@dgb dgb self-assigned this May 13, 2016
@kevinburkeshyp
Copy link

Some of our tables store references to other tables primary keys, e.g. pickups.userId - do we have a plan for those? or later?

@dgb
Copy link
Author

dgb commented May 13, 2016

I think this will only be an issue if we were querying for one model by a prefixed foreign key. Part of the plan is migrating associated keys (not least of which because removing the prefixes breaks any foreign key constraints), so for joins and internal queries, it should be fine. So in the example of pickups.userId, you'd have to be looking up pickups where the userId is usr_. This is an interesting case (and a good example) because there are probably a lot of places where we're looking something up by user id, but generally at that point, we've fetched the model itself, so the id attribute should be the non-prefixed version.

I didn't encounter that scenario in looking at trackingevents, but it could still be an issue, and it's good to keep in mind as we go through the rest of the tables. I think we can hook into the other behavior in normalize (like here), but it's distinct from the expandPK, and I'm not sure I fully understand the intention there.

@dgb dgb removed their assignment May 13, 2016
.where({ id: 'foo_b0aec906-81d1-401b-8622-2b01036793d5' })
.exec(function(err, results) {
assert(!err);
assert(results[0].where.id == 'b0aec906-81d1-401b-8622-2b01036793d5');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great test!

Derek Barnes added 2 commits May 13, 2016 12:56
Changes primary key type coercion on UUIDs to throw a TypeError when
attempting to coerce a value that is not a UUID.
@kevinburkeshyp
Copy link

Please ping me when this is ready for re-review as I'm not checking this project regularly :(

Derek Barnes added 2 commits May 17, 2016 14:23
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.
Change normalize.expandPK to only coerce the uuid when the underlying
schema is reported as UUID as well.
@dgb
Copy link
Author

dgb commented May 17, 2016

Alright, this is ready for another review. In addition to addressing feedback, I tweaked the coercion rule slightly to also look at context.schema which is the schema settings as reported by the database itself. This makes the patch backwards compatible with uuid fields with an underlying representation of text, so we can stage the model changes before running the actual database migration.

@kevinburkeshyp
Copy link

Looking!


// 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 extreneous characters from it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*extraneous

Fix typo and pull out UUID regex.
@kevinburkeshyp
Copy link

LGTM

@dgb
Copy link
Author

dgb commented May 18, 2016

Thanks for the review!

@dgb dgb merged commit 624690d into master May 18, 2016
@dgb dgb deleted the add-uuid-pk-coercion branch May 18, 2016 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants