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

parseId in entity.js and model.js are different, leads to problems with keyType:name #168

Closed
ZackKnopp opened this issue May 29, 2019 · 5 comments · Fixed by #179
Closed

Comments

@ZackKnopp
Copy link

related to #86

I'm using gstore-node v6.0.2 and I'm having an issue updating an entity that uses a non-numeric id. The id is automatically parsed into a numeric one, which changes the value. I have set the keyType to "name" on my schema.

My datastore entity id/name is "200200000000000016353" and it gets turned into "200200000000000000000" because of rounding from parseInt and integer limits of js.

Why does gstore-node still use parseId, even when keyType is set on the schema? Is this expected?

Possible solutions?

  • make parseId a public member of Schema, then reference it on the schema when using it in Entity and Model
  • add a check for Number​.MAX_SAFE_INTEGER?

Here is my schema:

const classSchema = new Schema(
  {
    Name: { type: String, required: true },
    customer: { type: Schema.Types.Key, ref: "Customer", required: true }
  },
  { keyType: "name" }
);

In model.js of your library you have an update function:

static update(id, data, ancestors, namespace, transaction, options) {
        this.__hooksEnabled = true;
        const _this = this;

        let entityUpdated;
        let error = {};

        id = parseId(id);  <--- problem

        ...
}

What do you think?

@sebelga
Copy link
Owner

sebelga commented May 30, 2019

Hello,
Thanks for reporting! This is a bug... and I am surprised it did not come up earlier. 😊 I must admit that I am not sure anymore about the design decision of parsing the id, but to avoid introducing a breaking change I will update the parseId() function or maybe make it public on the schema as you suggest 👍
Unfortunately, I won't be able to add the fix before a couple of weeks as I am currently traveling.

@ZackKnopp
Copy link
Author

ZackKnopp commented May 30, 2019

@sebelga I worked on a patch on my fork yesterday and all I need to do is squash the commits, then make a PR, and you can see if that fix works for you. I couldn't run any of your tests though, because I'm on windows so your package.json tasks were throwing errors.

Until you have a fix, or incorporate my fix, I can just keep running gstore-node from my fork.

Cheers for the great library by the way! Docs are great and it's very user friendly.

@jacobg
Copy link

jacobg commented Jul 19, 2019

Maybe related issue: #172

@jacobg
Copy link

jacobg commented Jul 19, 2019

It's also weird that the Model.key() function takes an id: string | number, but returns a datastore entity Key which has an id: string, and still somehow the returned key has a number id. I'm not sure how typescript allows that, but this ambiguity of the id type seems to make it vulnerable to application bugs.

// When an entity key is constructed via the model, a string id is parsed into a number.
// It's kind of weird, because a datastore entity key id is a string.
expect(EntityModel.key(savedEntity.entityKey.id as string).id).to.equal(Number.parseInt(savedEntity.entityKey.id as string))

@sebelga
Copy link
Owner

sebelga commented Sep 10, 2019

Hi!

Sorry for the very late response. I finally can dedicate some time and look into this. Historically Google Datastore was making a difference between an integer being passed and a string.

This would mean that, when using the auto-allocated id, it would be numeric (and returned in the EntityKey as numeric value). Then, when trying to GET the entity, if we didn't pass an integer it would not return it. So, when building an API and reading the id from the URL param, we had to parseInt it before trying to fetch it. So this is where the parseId() came from.

But now, after a few tests, I realized that saving 123 or "123" is the same. It is considered as an id (and returned in the entity Key as a string). Then we can fetch using either the integer or string and still get the entity.

Model.key() accepts both id: string | number because both are valid and supported by the Datastore. And indeed, always a string is returned.

After this analysis, I will remove all the logic around the parseInt that is not necessary anymore.

Cheers! 👍

[EDIT] Actually, when we run the local Datastore Emulator, the behaviour is different. The auto-allocated id is indeed an integer, but the Key returns it as a string id. Trying to fetch this string id does not return the entity and we need to convert it to integer before.

sebelga added a commit that referenced this issue Sep 10, 2019
…ity key id

The live Datastore treats the same way User.get("123") than User.get(123). Both return the entity
with the Key.id being "123". The convertion from string to integer has been removed inside gstore
and let to the consumer to implement if needed.

BREAKING CHANGE: The "keyType" Schema option has been removed as it is no longer needed. Also, as
gstore does not parse the id anymore, running your project against the Datastore emulator locally
might break as the emulator treats differently User.get(123) than User.get("123"). Auto-allocated
ids are integer and need to be provided as integer for the Emulator.

#168
sebelga added a commit that referenced this issue Sep 10, 2019
…ity key id (#179)

The live Datastore treats the same way User.get("123") than User.get(123). Both return the entity with the Key.id being "123". The conversion from string to an integer has been removed inside gstore and let to the consumer to implement if needed.

BREAKING CHANGE: The "keyType" Schema option has been removed as it is no longer needed. Also, as gstore does not parse the id anymore, running your project against the Datastore emulator locally might break as the emulator treats differently User.get(123) than User.get("123"). Auto-allocated ids are integers and need to be provided as integers for the Emulator.

#168
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants