node.js - Folosește ENUM cu Sequelize și Typescript


Încerc să creez un API cu o clasă USER care poate avea mai mult de o modalitate de a se autentifica cu API-ul.

Am reușit să îl fac să funcționeze cu 1 singur utilizator având doar 1 acreditiv, dar atunci când am încercat să extind pentru a permite mai multe acreditive am primit eroarea: UnhandledPromiseRejectionWarning: SequelizeDatabaseError: (conn=498, no: 1265, SQLState: 01000) Data truncated for column 'type' at row 1

Ceea ce am în prezent este acesta:

User.hasMany(Credential, { foreignKey: 'id', sourceKey: 'id' });

Și asta:

//Credential.ts
export function CredentialInit(sequelize: Sequelize) {
    let cred = Object.keys(CredentialType);
    let credArr: string[] = [];
    for(let i = 0; i < cred.length/2; i++) {
        credArr.push(`${i}`);
    };
    Credential.init({
        email: {
            type: DataTypes.STRING,
            allowNull: true
        },
        password: {
            type: DataTypes.STRING,
            allowNull: true
        },
        token: {
            type: DataTypes.STRING,
            allowNull: true
        },
        type: {
            type: DataTypes.ENUM,
            values: credArr,
            allowNull: false
        }
    }, {
        sequelize: sequelize,
        tableName: 'credentials'
    });
}

export enum CredentialType {
    EMAIL,
    TOKEN
}

export class Credential extends BaseModel {
    public type!: CredentialType;
    public token?: string;
    public email?: string;
    public password?: string;
}

De asemenea, am acest model pentru a elimina aceste lucruri din toate celelalte modele ale mele.

//BaseModel.ts
export class BaseModel extends Model {
    public id?: number;
    public readonly createdAt?: Date;
    public readonly updatedAt?: Date;
}

Ai vreo idee de ce primesc acest mesaj? L-am scris așa pentru că nu vreau să trebuiască să declar conținutul enum-ului de două ori.. Dacă se schimbă, vreau să se schimbe peste tot....

Răspuns #1

Deoarece un enum în TypeScript este o valoare, poți răspândi valorile enum în DataTypes.ENUM din Sequelize, astfel:

enum CredentialType {
  EMAIL,
  TOKEN
}

Credential.init({
  // ...
  type: {
    type: DataTypes.ENUM(...Object.values(CredentialType)),
    allowNull: false
  }
}, {
  sequelize: sequelize,
  tableName: 'credentials'
});

Sau cu biblioteca sequelize-typescript, astfel:

import { Column, DataType, Model, Table } from "sequelize-typescript";

enum CredentialType {
  EMAIL = "EMAIL",
  TOKEN = "TOKEN",
}

@Table
class Credential extends Model {
  @Column({
    defaultValue: CredentialType.EMAIL,
    type: DataType.ENUM(...Object.values(CredentialType)),
  })
  type!: CredentialType;
}

Rețineți că valorile implicite pentru un enum în TypeScript sunt indexate, dar pot fi suprascrise cu propriile valori, astfel:

enum CredentialType {
  EMAIL = "EMAIL",
  TOKEN = "TOKEN"
}

Răspunsul #2

Ok, după multe experimente am găsit o modalitate. Deoarece o opțiune de tip enum este reprezentată ca un număr în TypeScript/JavaScript, am schimbat tipul bazei de date corespunzător enumului:

Credential.init({
    email: {
        type: DataTypes.STRING,
        allowNull: true
    },
    password: {
        type: DataTypes.STRING,
        allowNull: true
    },
    token: {
        type: DataTypes.STRING,
        allowNull: true
    },
    type: {
        type: DataTypes.INTEGER,
        allowNull: false
    }
}, {
    sequelize: sequelize,
    tableName: 'credentials'
});

Când a fost salvat în baza de date ca integer, eroarea a dispărut.