sebelga / gstore-node

Google Datastore Entities Modeling for Node.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

ZackKnopp opened this issue · comments

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?

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.

@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.

Maybe related issue: #172

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))

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.