denodb icon indicating copy to clipboard operation
denodb copied to clipboard

UUID is not auto generated

Open autsada opened this issue 3 years ago • 16 comments

Hi,

I have one issue that would like to ask here.

If I set the id to INTEGER it will be auto-generated, but if I use UUID it's not. This is my model.

class User extends Model {
  static table = 'users'
  static timestamps = true
  static fields = {
    id: {
      type: DataTypes.UUID,
      primaryKey: true,
    },
    ....
}

Do I miss anything to have this auto-generated?

autsada avatar Jan 24 '21 04:01 autsada

Hi autsada,

For now, UUID fields are not auto-generated indeed.

I just found that Deno has a uuid helper in the standard library, so here's how you can do it:

import { v4 } from "https://deno.land/[email protected]/uuid/mod.ts";

class User extends Model {
  static table = 'users';
  static timestamps = true;
  
  static fields = {
    id: {
      type: DataTypes.UUID,
      primaryKey: true,
    },
  };
  
  static defaults = {
    id: () => v4.generate(),
    // id: v4.generate, should work as well
  };
}

Let me know if this works for you.

Keep in touch

eveningkid avatar Jan 28 '21 15:01 eveningkid

Hi eveningkid,

I will test it, thank you for your help.

Cheers,

autsada avatar Jan 29 '21 01:01 autsada

Hi eveningkid,

I have tested it, and it has to be

static defaults = {
    id: v4.generate()
  };

But it will work for the first time only, after I tried to add the second one it failed. Here is the error I got.

PostgresError: duplicate key value violates unique constraint "id"
    at parseError (error.ts:106:10)
    at Connection._processError (connection.ts:434:19)
    at Connection._simpleQuery (connection.ts:298:20)
    at async Connection.query (connection.ts:546:16)
    at async Client.query (client.ts:25:12)
    at async PostgresConnector.query (postgres-connector.ts:63:22)
    at async Database.query (database.ts:227:21)
    at async Function._runQuery (model.ts:217:21)
    at async Function.create (model.ts:417:21)
    at async addProduct (admin.ts:102:21)

For now, I solved this by adding the v4 generate function directly to the database.

Cheers,

autsada avatar Jan 29 '21 02:01 autsada

I have tested it, and it has to be

static defaults = {
  id: v4.generate()
};

Doing so sets the default value as the immediate return value of generate() which is a constant string. In his example @eveningkid gave a function:

 static defaults = {
   id: () => v4.generate(),
   // id: v4.generate, should work as well
 };

juliendargelos avatar Mar 24 '21 22:03 juliendargelos

Hey,

I think @juliendargelos said it well, this should work!

Hope the problem has been solved on your end.

Have a great day :)

eveningkid avatar Mar 30 '21 18:03 eveningkid

I feel like I might have won an award for the weirdest bug I have ever see, consider the following user model:

export class User extends Model {
  static table = "users";
  static timestamps = true;

  static fields = {
    id: { primaryKey: true, type: DataTypes.UUID },
    provider: DataTypes.STRING,
    providerUserId: DataTypes.STRING,
    displayName: DataTypes.STRING,
    email: DataTypes.STRING,
  };

  static defaults = {
    id: v4.generate,
  };
}

On running I get a TS error:

Uncaught (in promise) PostgresError: invalid input syntax for type uuid: "function generate() {
    const rnds = crypto.getRandomValues(new Uint8Array(16));
    rnds[6] = (rnds[6] & 0x0f) | 0x40;
    rnds[8] = (rnds[8] & 0x3f) | 0x80;
    return bytesToUuid(rnds);
}"

If I flip the ID type to DataTypes.STRING - it boots up fine, but then when a row is added to the DB the ID is

function generate() {
    const rnds = crypto.getRandomValues(new Uint8Array(16));
    rnds[6] = (rnds[6] & 0x0f) | 0x40;
    rnds[8] = (rnds[8] & 0x3f) | 0x80;
    return bytesToUuid(rnds);
}

It's evaling the string of the function....?

royletron avatar Apr 21 '21 07:04 royletron

Screenshot 2021-04-21 at 08 10 17 Like literally in the ID column...

royletron avatar Apr 21 '21 07:04 royletron

Hey Darren,

Thanks a lot for sharing all the details :)

Could you please show me how you're creating an instance of that user? I think I might have an idea.

This seems related to #198.

Let's see how we can fix this once and for all!

eveningkid avatar Apr 21 '21 10:04 eveningkid

Hey @eveningkid

const user = await User.create({
  provider: "google",
  providerUserId: userInfo.providerUserId,
  displayName: userInfo.displayName,
  email: userInfo.emails[0],
});

I have added on id: v4.generate() for the short term!

royletron avatar Apr 21 '21 10:04 royletron

@eveningkid

const user = new User();
user.provider = "google";
user.providerUserId = userInfo.providerUserId;
user.displayName = userInfo.displayName;
user.email = userInfo.emails[0];
await user.save();

Works! I still get errors from Typescript if i set the id in the model with id: { primaryKey: true, type: DataTypes.UUID } the error is:

error: Uncaught (in promise) PostgresError: invalid input syntax for type uuid: "() => v4.generate()"
  return new PostgresError(errorFields);
         ^
    at parseError (https://deno.land/x/[email protected]/error.ts:106:10)
    at Connection._processError (https://deno.land/x/[email protected]/connection.ts:434:19)
    at Connection._simpleQuery (https://deno.land/x/[email protected]/connection.ts:298:20)
    at async Connection.query (https://deno.land/x/[email protected]/connection.ts:546:16)
    at async Client.query (https://deno.land/x/[email protected]/client.ts:25:12)
    at async PostgresConnector.query (https://deno.land/x/[email protected]/lib/connectors/postgres-connector.ts:63:22)
    at async Database.query (https://deno.land/x/[email protected]/lib/database.ts:239:21)
    at async Function.createTable (https://deno.land/x/[email protected]/lib/model.ts:172:5)
    at async Database.sync (https://deno.land/x/[email protected]/lib/database.ts:209:7)
    at async file:///Users/darren/Workspace/Deno/toto/database.ts:38:1

but no error if I set it to string.

royletron avatar Apr 21 '21 10:04 royletron

Hey Darren,

We discussed this issue on #198 and @stillalivx implemented the fix in #248 :)

The issue should go away using 1.0.37.

Thanks again for reporting this issue and have a great day!

eveningkid avatar Apr 29 '21 09:04 eveningkid

id: v4.generate with DataTypes.String (id is uuid) works while DataTypes.UUID throws error with 1.0.37

error: Uncaught (in promise) PostgresError: invalid input syntax for type uuid: "function generate() {
    const rnds = crypto.getRandomValues(new Uint8Array(16));
    rnds[6] = (rnds[6] & 0x0f) | 0x40;
    rnds[8] = (rnds[8] & 0x3f) | 0x80;
    return bytesToUuid(rnds);
}"
  return new PostgresError(parseWarning(msg));
         ^
    at parseError (https://deno.land/x/[email protected]/connection/warning.ts:48:10)
    at Connection.processError (https://deno.land/x/[email protected]/connection/connection.ts:689:19)
    at Connection._simpleQuery (https://deno.land/x/[email protected]/connection/connection.ts:550:20)
    at async Connection.query (https://deno.land/x/[email protected]/connection/connection.ts:795:16)
    at async PostgresConnector.query (https://raw.githubusercontent.com/eveningkid/denodb/master/lib/connectors/postgres-connector.ts:63:22)
    at async Database.query (https://raw.githubusercontent.com/eveningkid/denodb/master/lib/database.ts:240:21)
    at async Function.createTable (https://raw.githubusercontent.com/eveningkid/denodb/master/lib/model.ts:172:5)
    at async Database.sync (https://raw.githubusercontent.com/eveningkid/denodb/master/lib/database.ts:210:7)
    at async file:///home/mb/my/career/deno/denodb/demo/users-demo-oak-graphql-server/src/models.ts:24:1
Watcher Process finished! Restarting on file change...

image

borsemayur2 avatar Apr 30 '21 03:04 borsemayur2

@borsemayur2 would you mind sharing the full model file that throws an error (with DataTypes.UUID)?

This indeed seems abnormal...

eveningkid avatar May 01 '21 10:05 eveningkid

@eveningkid Here's the file: models.ts

borsemayur2 avatar May 01 '21 10:05 borsemayur2

Is there an update here? What is the best way to generate a random uuid as a default? Seems like v4.generate is deprecated.

hirefrank avatar Sep 19 '22 13:09 hirefrank

Is there an update here? What is the best way to generate a random uuid as a default? Seems like v4.generate is deprecated.

crypto.randomUUID()

https://examples.deno.land/uuids

jacoborus avatar Dec 01 '22 01:12 jacoborus