No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

19 Días
13 Hrs
1 Min
18 Seg

Tu primer modelo en Sequelize

10/27
Recursos

Aportes 53

Preguntas 34

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Aclaraciones de la documentación

🔥Nuestra documentación nos permite aclarar unos detalles que quedaron volando:

  • Podemos utilizar define o extend Model.
  • Se infiere el nombre de la tabla y se generaliza en plural, sequelize.define('user', userSchema); definirá la tabla users.
  • Existe el modo de sincronización global sequelize.sync() o particular modelo.sync()` donde tendremos parámetros:
    • force: true. Eliminar la existencia previa y creando en secuencia.
    • alter: true. Revisa si se cambiará alguna estructura, la nueva vs la previa.

.

Configuración de ORM

ℹ️Repositorio: link
.
♻️Reutilizando las variables de entorno, las organizamos para determinar aquellas para database.

config.js . Archivo de definición de variables de entorno

/**
 * @description variables of database server
 */
export const database = {
    dbName: process.env.PGDATABASE,
    dbHost: process.env.PGHOST || 'localhost',
    dbPort: process.env.PGPORT || '5432',
    dbUser: process.env.PGUSER,
    dbPassword: process.env.PGPASSWORD,
};

.
♻️Definimos la librería de sequelize mediante la abstracción OOP.

Sequelize.js . Archivo de definición de variables de entorno

import { Sequelize as SequelizeClient } from 'sequelize';
import { database } from '../config/config';
import Error from '../utils/Error';

const USER = encodeURIComponent(database.dbUser);
const PASSWORD = encodeURIComponent(database.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${database.dbHost}:${database.dbPort}/${database.dbName}`;

export default class Sequelize {
    /**
     * @private
     * @description singleton pattern for pool connection
     * @returns {object} - connection client
     */
    async #connect() {
        try {
            if (!Sequelize.connection) {
                Sequelize.connection = new SequelizeClient(URI, {
                    logging: false,
                });
                await Sequelize.connection.authenticate();
            }
            return Sequelize.connection;
        } catch ({ message }) {
            throw new Error(message, 'DRIVER');
        }
    }
    /**
     * @description process definition for create database tables
     * @param {string} name - table name
     * @param {string} schema - table description
     * @returns {Promise} - response of library
     */
    async define(name, schema) {
        try {
            const db = await this.#connect();
            const model = await db.define(name, schema);
            return await model.sync();
        } catch (error) {
            if (!error) throw new Error(message, 'DEFINITION');
            throw error;
        }
    }
}

.
✨Creamos el schema

user.js

import { DataTypes, Sequelize as SequelizeClient } from 'sequelize';

/**
 * @description description of each field in the table
 * @typedef {Object} field definition
 * @property {boolean} allowNull - false=NOT NULL
 * @property {boolean} autoIncrement - each insert, increase the counter
 * @property {boolean} primaryKey - define is primary key
 * @property {boolean} type - expresion to match SQL type
 * @property {boolean} unique - difne as unique the field
 * @property {boolean} field - rename the field
 */
export default {
    id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
    },
    email: {
        allowNull: false,
        type: DataTypes.STRING,
        unique: true,
    },
    password: {
        allowNull: false,
        type: DataTypes.STRING,
    },
    createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: SequelizeClient.DATE,
    },
    updatedAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'updated_at',
        defaultValue: SequelizeClient.DATE,
    },
};

.
✨Creamos nuestro seed

seed.js . Archivo de creación de entorno limpio npm run seed

import Sequelize from './../libs/sequelize';
import userSchema from './models/user';
import { complete, fail } from '../utils/Log';

const sequelize = new Sequelize();
const user = sequelize.define('user', userSchema);

Promise.all([user])
    .then((responses) => complete('Creation process', responses))
    .catch(({ message }) => fail('Creation process', message));

Wow sinceramente esta clase la senti pesada, es la configuración más compleja de base de datos/ORM que haya realizado, comparado con Java Spring, Nest JS, Node con Mongo, Laravel…

Esta clase fue genial, no sabía que se podía persistir datos con un esquema de una manera tan fácil.
Adicional me gustaría compartir la diferencia entre un método static y uno no static.

Cuando se crea un método no estático en una clase. primero se tiene que crear un objeto (instancia) de la clase.
Ej.

class Users {
	metodoNoEstatico() {
		//  Una lógica loca...
	}
}

// Para hacer uso del método no estático se crea un objeto de la clase.
const user = new Users();
user.metodoNoEstatico();

Cuando el método es static no se requiere crear un objeto de la clase. Ej.

class Users {
	static metodoEstatico() {
		//  Una lógica loca...
	}
}

// Para hacer uso del método estático no se necesita crear un objeto.
Users.metodoEstatico();

Esto es porque los métodos static se cargan en memoria sin la necesidad de cargar/crear el objeto de la clase.

Se empieza a trabajar con esquemas de bases de datos para aprovechar las ventajas del ORM.

Dentro de la carpeta db habrá una carpeta models donde se guardarán los modelos de la BD.

Una buena practica para el naming en Sequelize y en las bases de datos es NO usar camelCase, más bien, usar snake_case. Cabe mencionar que en las variables de JavaScript sí es posible (ver ejemplo):

createdAt: { // Variable JavaScript
    allowNull: false,
    type: DataTypes.DATE,
    field: 'created_at', // Naming en Sequelize
    defaultValue: Sequelize.NOW // Valor por defecto (cómo se registró en Sequelize)
  }

Se puede definir una clase del modelo y extenderlo de Model el cual contiene todas las formas de hacer queries. Ejemplo class User extends Model.

Un método estático significa que no necesito una declaración (no se necesita declarar el objeto) para acceder a esos métodos. Va a funcionar para definir las asociaciones.

Se define otro método estático para la configuración, recibe una conexión que usualmente se llama sequelize y se retorna una configuración con la conexión, el nombre de la tabla, el nombre del modelo y el timestamps (por default).

user.model.js:

const { Model, DataTypes, Sequelize } = require('sequelize');
const USER_TABLE = 'users'; // nombre de la tabla

const UserSchema = {
  // El esquema define la estructura de la BD.
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER,
  },
  email: {
    allowNull: false,
    type: DataTypes.STRING,
    unique: true,
  },
  password: {
    allowNull: false,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'created_at',
    defaultValue: Sequelize.NOW,
  },
};

class User extends Model {
  static associate() {
    // models
  }

  static config(sequelize) {
    return {
      sequelize,
      tableName: USER_TABLE,
      modelName: 'User',
      timestamps: false,
    };
  }
}

module.exports = { USER_TABLE, UserSchema, User };

Dentro de la carpeta db/models se crea un archivo index.js el cual se va a encargar de enviar la conexión hacia los modelos, y con esto podrá hacer todo el mapeo y serialización de datos. Ahí se incluyen todos los modelos.

La función setupModels tendrá la configuración de los modelos, recibe la conexión como parámetro. Ahí se incluye todo el setup inicial de los modelos.

Al .init() se le envía el schema, posteriormente la configuración con el método estático. Ejemplo: User.init(UserSchema, User.config(sequelize));

index.js:

const { User, UserSchema } = require('./user.model');

function setupModels(sequelize) {
  User.init(UserSchema, User.config(sequelize));
}

module.exports = setupModels;

En el archivo sequelize.js se corre la función setupModels, dentro del archivo se require la función, se inicializa pasándole la conexión y se hace una sincronización, es decir, leer los modelos y crear una estructura incluyendo las tablas.

sequelize.js:

const { Sequelize } = require('sequelize');

const { config } = require('../config/config');
const setupModels = require('../db/models/');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

const sequelize = new Sequelize(URI, { dialect: 'postgres', logging: true }); // Se crea una instancia de Sequelize.

setupModels(sequelize);
sequelize.sync();

module.exports = sequelize;

Para hacer una consulta, en el archivo de servicios se require el archivo sequelize de la capa de librerías. Cada vez que en sequelize se le envía setupModels y se le da el .init(), se crea un namespace, un espacio reservado para guardar los modelos, o al menos la forma de acceder a ellos. El nombre del modelo será el asignado en modelName del archivo de un modelo especifico (ej. user.model.js).

El método para consultar todos los registros de una tabla es .findAll(). y se hace de la siguiente manera:

const { models } = require('../libs/sequelize');

async find() {
    const rta = await models.User.findAll();
    return rta;
  }

En .Net es 100 veces más sencillo.

CamelCase
snake_case

Si necesitas un poco de ayuda visual para entender como se van haciendo las relaciones en la base de datos te comparto la siguiente imagen.

En este curso, básicamente yo seleccione como Base de datos Mysql, en vista que no pude configurar dockers con la imagen de Postgress, al final casi que son hermanas estas BD, pero he podido avanzar tal cual lo que el profesor indica. Esto demuestra que no importa la BD que uses (Tipo SQL) con un ORM o Pool, es la misma configuración para distintas BD. 👽

Síganme por instagram como: mrandycode y twitter mrandycode

Mediante el CLI de sequelize podemos generar todo más rápido y fácil.

  1. Instalas el cli como dependencia de desarrollo
    npm i -S sequelize-cli.
  2. Crea un archivo con el nombre .sequelizerc a la altura de tu package.json.
  3. Ingresa a este link Sequelize cli y busca la sección donde definen su contenido.
  4. Copia ese contenido, que en resumen crea las rutas de tu config, models, migratios y seeders. Esta es la config que yo usé:
// path ./.sequelizerc
const path = require('path');

module.exports = {
  'config': path.resolve('database', 'config.js'),
  'models-path': path.resolve('database', 'models'),
  'seeders-path': path.resolve('database', 'seeders'),
  'migrations-path': path.resolve('database', 'migrations')
};
  1. Como puedes ver, por defecto el archivo config es un json, aquí está la original, pero yo lo cambié por un .js como lo hace más adelante el profesor. Aquí te dejo el código.
// path ./database/config.js
require('dotenv/config')

const { DB_PORT, DB_HOST, DB_NAME, DB_PASS, DB_USER } = process.env

module.exports = {
  development: {
    username: DB_USER || "postgres",
    password: DB_PASS || "admin",
    database: DB_NAME || "littleStore",
    dialect: "postgres",
    host: DB_HOST || "127.0.0.1",
    port: DB_PORT || 5432,
    logging: false
  }
}
  1. Corre el comando npx sequelize-cli init, y te creará todas las carpetas que necesitas, excepto por el config.js que ya lo tienes.
  2. Edita y crea tus modelos, migraciones y seeds mediante la guía porque el profesor en esta clase lo hace a mano. Es cierto que necesitas saber que son los seeds para poder usarlos, pero no hay mejor manera de aprender que hechandolo a perder. O siguiendo una guía de youtube o aquí.

Estuvo potente la clase

Dato:
Supongo es bastante intuitivo, pero si se preguntan, ¿Por que en createdAt utilizamos field y en las otras no?

Por defecto el nombre de la columna tendra el nombre de la llave, en el caso de createdAt, debiamos cambiar la convención de camelCase a snake_case, por lo mismo renombramos la columna con el atributo field

Si hemos puesto primary key en el UserSchema no sería redundante poner allowNull: false?

les dejo mi repo hasta le momento https://github.com/bdavidegonzalez/my-store yo utilice typescript tal vez alguno le sirva

Estos temas estan muy muy interesantes, estas librerias para las BD estan buenisimas.

Tengo el siguiente error: (node:15884) \[SEQUELIZE0002] DeprecationWarning: The logging-option should be either a function or false. Default: console.log (Use `node --trace-deprecation ...` to show where the warning was created) Mi port3000 node:assert:171 throw err; ^ AssertionError \[ERR\_ASSERTION]: unknown message code: 4a No se cómo solucionarlo..

Si a alguno no le sirve la llamada al endpoint de users, intenten exportando en sí el modelo de Users, es decir, importan el archivo donde definen todo lo que trae “User”, y en el user.service.js harían:

  async find() {
    const response = await User.findAll();
    return response;
  }

La clase esta bien, aunque yo la encontré corta de explicaciones, entiendo que no es el propósito del curso enseñarte a usar sequelize, pero hubiese agradecido un par de explicaciones mas sobre como funcionan los modelos, y por que lo hace de la manera que lo hace. En fin si encontraste esto de la misma manera que yo, la documentación de la librería hace un buen trabajo resolviendo algunas dudas que puedas tener

productModel.js

const { Model, DataTypes, Sequelize } = require('sequelize');

const PRODUCT_TABLE = 'products';

const ProductSchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  productName: {
    allowNull: false,
    type: DataTypes.STRING,
    field: 'product_name',
  },
  price: {
    allowNull: false,
    type: DataTypes.REAL
  },
  stockNumber: {
    allowNull: true,
    type: DataTypes.REAL,
    field: 'stock_number',
  },
  category: {
    allowNull: true,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'create_at',
    defaultValue: Sequelize.NOW
  }
}

class Product extends Model {
  static associate(){

  }

  static config(sequelize){
    return {
      sequelize,
      tableName: PRODUCT_TABLE,
      modelName: 'Product',
      timestamps: false,
    }
  }
}

module.exports = { PRODUCT_TABLE, ProductSchema, Product }

categoryModel.js

const { Model, DataTypes, Sequelize } = require('sequelize');

const CATEGORY_TABLE = 'categories';

const CategorySchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  category: {
    allowNull: false,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'create_at',
    defaultValue: Sequelize.NOW
  },
}

class Category extends Model {
  static associate(){

  }

  static config(sequelize){
    return {
      sequelize,
      tableName: CATEGORY_TABLE,
      modelName: 'Category',
      timestamps: false,
    }
  }
}

module.exports = { Category, CategorySchema, CATEGORY_TABLE }

db/model/index.js

const { User, UserSchema } = require ('./userModel');
const { Product, ProductSchema } = require ('./productModel');
const { Portfolio, PortfolioSchema} = require ('./portfolioModel');
const { Category, CategorySchema } = require ('./categoryModel')


function setupModels(sequelize) {
  User.init(UserSchema, User.config(sequelize));
  Product.init(ProductSchema, Product.config(sequelize));
  Portfolio.init(PortfolioSchema, Portfolio.config(sequelize));
  Category.init(CategorySchema, Category.config(sequelize));
}

module.exports = setupModels;

El shema (Esquema)
Se refiere a la estructura de las tablas(Nombres y tipos de campo etc.)
Creamos una carpeta para guardar todo lo relacionado a la base de datos y se llama db, dentro ponemos la carpeta models y detro creamos un modelo llamado user.model.js , recuerda que es un modelo por tabla, en este archivo se importa sequelize y se traen 3 elementos: Model, DataTypes y Sequelize este archivo lleva 5 elementos importantes

  1. Se importa sequelize
  2. Se declara una constante que tendrá el nombre de la tabla
  3. Se declara el esquema (UserShema)
  4. Se extiende la clase Model en una nueva clase llamada como el modelo
  5. Por ultimo se exportan los elementos 2,3 y 4

Según entendí cómo funciona, en retrospectiva, el flujo de trabajo que está ocurriendo es el siguiente:

  • La ruta o endpoint, llama al servicio. (users.router.js)
  • El servicio, genera la conexión sequelize al modelo. (users.service.js)
  • Se llama a setupModels, enviando la conexión. (sequelize.js)
  • Dentro de setupModels, se inicializa el modelo con init(), pasando el modelo y la configuración. (models/index.js)
  • El modelo, extiende los métodos de sequelize, tal como findAll() para realizar el query. (user.model.js)
  • Se retorna la respuesta obtenida de la DB.

Me ha encantado! Muy similar a las migraciones de laravel.

Este curso anda con todo 😄

Si alguien desea ver una configuración rápida de Sequelize pueden revisar este repositorio, exactamente en la carpeta server.
Repo: https://github.com/omar11011/serena_bot_discord

Qué es un Modelo?


Primero recordemos que es un ORM…
.

  • Un ORM (Object Relational Mapping) es una técnica que utiliza ciertas librerías y frameworks para llevar la estructura de una Base de Datos Relacional a una estructura de Programación Orientada a Objetos. Es decir, nos permitirá interactuar con nuestra base de datos sin la necesidad de conocer SQL.
    .
  • Lo que son Tablas en Bases de datos, corresponden a Modelos que se expresan mediante clases, en POO. Las columnas se corresponden a Atributos de esas clases. Y los tipos de dato son Clases de esos Atributos.
    .
    Mega recomendada esta clase de Facundo García ¿Qué es ORM? ¿Qué es un modelo?

Por que mis tablas no se actualizan (ALTER) cuando corro sequelize.sync()?

Usen sequelize.sync( {alter: true} ) para que se actualizen sus tablas existentes (‘created_at’, ‘updated_at’).

Al parecer `Sequelize.NOW` se encuentra obsoleta desde la versión 4 de sequelize. La forma mas actualizada de declarar un valor por defecto para una columna de tipo fecha es con: `Sequelize.fn('NOW')` Fuente Gemini (la IA de google) Hice mis pruebas y al usar `Sequelize.NOW` el INSERT desde la api funciona pero si se ejecuta un INSERT directo con SQL, da error porque el **DEFAULT** no queda correctamente asignado. Después de cambiarme a `Sequelize.fn('NOW')` si me permitió hacer mi INSERT correctamente.

asi queda con TypeScript y ES6

sequelize.ts

import { Sequelize } from "sequelize";
import newConfig from "../../config/config";
import { setupUserModel } from "../../app/users/models";
const USER = encodeURIComponent(newConfig.dbUser);
const PASSWORD = encodeURIComponent(newConfig.dbPassword);

const URI = `postgres://${USER}:${PASSWORD}@${newConfig.dbHost}:${newConfig.dbPort}/${newConfig.dbName}`;

export const sequelize = new Sequelize(URI, {
  dialect: "postgres",
  logging: console.log,
});

setupUserModel(sequelize);
sequelize.sync({ logging: console.log });

setupModel.ts

import { Sequelize } from "sequelize";
import { User, userModel } from "./user.model";

export const setupUserModel = (sequelize: Sequelize): void => {
  User.init(userModel, User.config(sequelize));
};

user.model.ts

import { Model, DataTypes } from "sequelize";

export const USER_TABLE = "users";

export const userModel = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER,
  },
  email: {
    allowNull: false,
    type: DataTypes.STRING,
    unique: true,
  },
  password: {
    allowNull: false,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: "create_at",
    defaultValue: DataTypes.NOW,
    unique: true,
  },
};

export class User extends Model {
  static associate() {}

  static config(sequelize: any) {
    return {
      sequelize,
      tableName: USER_TABLE,
      modelName: "User",
      timestamps: false,
    };
  }
}

Query para insertar datos:
INSERT INTO public.users(id, email, password, create_at)
VALUES (1,‘[email protected]’, ‘123’, ‘2019-01-01’),
(2,‘[email protected]’, ‘345’, ‘2019-01-01’),
(3,‘[email protected]’, ‘7645’, ‘2019-01-01’),
(4,‘[email protected]’, ‘32423’, ‘2019-01-01’);

Bueno, hice varias cosillas, les dejo el commit específico de esta clase en mi repo de github

Algo común que se suele tener en las empresas es el uso de un campo updated_at, el cual registra la fecha de cada vez que se actualiza un registro de la base de datos. Esto es muy útil a la hora de realizar ciertas auditorías sobre la información que la empresa almacena en sus bases de datos 😃

  updatedAt: {
    allowNull: true,
    type: DataTypes.DATE,
    field: 'updated_at',
  },

Para crear la tabla es mas fácil con Define, tenemos la conexión en un archivo aparte:

import { Sequelize } from "sequelize";

const db = new Sequelize("platzi", "postgres", "postgres", {
  host: "localhost",
  dialect: "postgres",
  //logging:false
});

export default db;

y tenemos el modelo

import { DataTypes } from "sequelize";
import db from "../db/conection";

const Usuario = db.define("user",{
    id: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
    },
    email: {
      allowNull: false,
      unique: true,
      type: DataTypes.STRING,
    },
    password: {
      allowNull: false,
      type: DataTypes.STRING,
    },
    createAt: {
      allowNull: false,
      type: DataTypes.DATE,
      field: "create_at", // el verdadero nombre como quiero que se cree
      defaultValue: DataTypes.NOW,
    },
  },
  {
    timestamps: false, // Para que no se creen los timestamps: createdAt y updatedAt por default
  }
);

//Creamos la tabla
Usuario.sync();

export default Usuario;

Para hacer la consulta importamos el modelo :

import Usuario from "../models/usuario";

y consultamos:

import { Request, Response } from "express";
import Usuario from "../models/usuario";

export const getUsuarios = async (req: Request, res: Response) => {
  const usuarios = await Usuario.findAll();

  res.json({
    usuarios,
  });
};

y ya eso seria todo 😃

Excelente yo lo hice con Mssql y todo bien, con ello migrar bases se hace más facil !

Me sale este error de TIMEOUT: ```js reject(new sequelizeErrors.ConnectionError(err)); ConnectionError [SequelizeConnectionError]: connect ETIMEDOUT 172.22.0.2:5432 ``` Este es el archivo de sequelize: ```js const { Sequelize } = require('sequelize'); const { config } = require('./../config/config'); const setupModels = require('./../db/models'); const USER = encodeURIComponent(config.dbUser); const PASSWORD = encodeURIComponent(config.dbPassword); const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}` const sequelize = new Sequelize(URI, { dialect: 'postgres', logging: false, serviceTimeout:1200, }); setupModels(sequelize); sequelize.sync(); module.exports = sequelize; ```
Me causó confusión el porque llamó un Init de una clase y uso un método dentro de ese init dentro de la misma clase. No se si haya cambiado desde la creación del video, pero no es requerido crear ese metodo config. <https://sequelize.org/docs/v6/core-concepts/model-basics/> se requiere esa estructura, si... pero no debe ir dentro de esa clase. es confuso.
En este momento si se tiene una versión reciente de sequelize este crea automáticamente las columnas created\_at y updated\_at <https://sequelize.org/docs/v7/models/auto-timestamps/#:~:text=By%20default%2C%20Sequelize%20automatically%20adds>,attributes%20will%20be%20set%20correctly.
Demasiada dura la clase, me ahorro mucho trabajo en proyectos reales ver y aprender esto yupiiii!!!!!!
Ayuda por fa. No se ejecuta el CREATE TABLE como le muestra al profe, en mis logs veo que solo aparecen do SELECT, y no me crea la tabla. `Executing (default): SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'users'` `Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;`
Es buena práctica sincronizar siempre automáticamente los modelos con la DB?

Si no les funciona el .NOW usen Sequelize.fn("now")

https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#static-method-fn

saben que note, en el docker-compose.yml están todas las credenciales, no se debería usar las variables de entorno ahí también? :p

Cuanta información en una sola clase jajajaj

Hola compañeros, estuve teniendo problemas en esta clase ya que estaba utilizando typescript y me estaba dando este error:
ModelNotInitializedError: Model not initialized: Member “getTableName” cannot be called. “User” needs to be added to a Sequelize instance.

Instale sequelize-typescript

Y asi quedaron mis componentes

user.model.ts

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

@Table({
  tableName: "users",
  timestamps: false,
})
class User extends Model {
  @PrimaryKey
  @Column({
    autoIncrement: true,
    allowNull: false,
    type: DataType.INTEGER,
  })
  id!: number;

  @Column({
    allowNull: false,
    type: DataType.STRING,
  })
  email!: string;

  @Column({
    allowNull: false,
    type: DataType.STRING,
  })
  password!: string;
}

export default User;

index.ts

import User from "./user.model";
import { Sequelize } from "sequelize-typescript";

function setupModels(sequelize: Sequelize) {
  sequelize.addModels([User]); // Agregar los modelos que deseas inicializar
  sequelize.sync(); // Sincronizar los modelos con la base de datos
}

export { setupModels };

sequelize.ts

import { Sequelize } from "sequelize-typescript";
import { config } from "../config/config";
import { setupModels } from "../db/models";
import User from "../db/models/user.model";

const USER = encodeURIComponent(config.dbUser as string);
const PASSWORD = encodeURIComponent(config.dbPassword as string);
const URI: string = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

const sequelize = new Sequelize(URI, {
  dialect: "postgres",
  logging: true,
});

setupModels(sequelize);

export { sequelize, User };

user.service.ts

import { User } from "../libs/sequelize";

export class UserService {
  constructor() {}

  
  async find() {
    const res = await User.findAll();
    return res;
  }

  async create(data: User): Promise<User> {
    return data;
  }


  async findOne(id: string): Promise<{}> {
    return { id };
  }

  async update(id: string, changes: Partial<User>) {
    return {
      id,
      changes,
    };
  }

  async delete(id: string) {
    return { id };
  }
}

Espero que a alguien le sirva

Está pesadito el asunto …

en el minuto 17:48, al crear manualmente la información de los usuarios para probar que sequelize funcione correctamente, no se olviden de guardar los cambios en la información

Esto me recordó a como se montan los ORM con Django.

de esta manera genere el patch

  async update(id, changes) {
    const user = await models.User.findByPk(id)
    if (!user) {
      throw new boom.notFound('Product not found');
    }
    const {dataValues} = {...user}
    const newUser = {
      ...dataValues,
      ...changes
    }
    await models.User.update({...changes}, {where: { id: id}})
    return newUser;
  }

Hice un modelo para la tabla products basándome en el modelo de user que hizo el profesor:

const { Model, Sequelize, DataTypes } = require('sequelize');

const PRODUCT_TABLE = 'products';

const ProductSchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  name: {
    allowNull: false,
    type: DataTypes.STRING
  },
  price: {
    allowNull: false,
    type: DataTypes.INTEGER
  },
  category: {
    allowNull: false,
    type: DataTypes.STRING
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'create_at',
    defaultValue: Sequelize.NOW
  }
}

class Product extends Model {
  static associate() {}

  static config(sequelize) {
    return {
      sequelize,
      tableName: PRODUCT_TABLE,
      modelName: 'Product',
      timestamps: false
    }
  }
}

module.exports = { Product, ProductSchema, PRODUCT_TABLE };

Basicamente lo mismo luego añadí en el index el setup model de products:

const { User, UserSchema } = require('./user.model');
const { Product, ProductSchema } = require('./product.model');

function setupModels(sequelize) {
  User.init(UserSchema, User.config(sequelize));
  Product.init(ProductSchema, Product.config(sequelize));
}

module.exports = setupModels;

Y finalmente llame en el product.service.js al model de products tal cual como hizo el profesor con user en el metodo find usando findAll:

 async find() {
    const rta = await models.Product.findAll();
    return rta;
  }

Ya con eso debería crearse la tabla products en el pgadmin y después de llenarla se podrían pedir los datos por insomnia, yo obtuve lo siguiente probando:

[
	{
		"id": 5,
		"name": "gth",
		"price": 455,
		"category": "gxffxh",
		"createdAt": "2006-06-06T06:06:06.000Z"
	},
	{
		"id": 6,
		"name": "coke",
		"price": 3,
		"category": "Beverage",
		"createdAt": "2006-06-06T06:06:06.000Z"
	}
]

Sequelize también te permite generar los modelos de una forma un poco más agradable usando npx de esta manera

Para crear un sistema de carpetas por defecto al que sequelize va a hacer referencia

npx sequelize-cli init

Para crear un modelo

npx sequelize-cli model:generate --name Usuario --attributes nombre:string,apellido:string,fechaNacimiento:date,lugarNacimiento:string,correo:string,genero:boolean,direccion:string,temaLiterario:string,tipo:integer,usuario:string,password:string,imagenPerfil:string

A mí me creó una columna extra llamada “updatedAt” que yo ni la definí en el UserSchema… 👀

… Aliens? 👽👐

Comparto el código para crear el modelo “Service”:

const { Model, DataTypes } = require('sequelize');

const SERVICE_TABLE = 'services';

const ServiceSchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER,
  },
  title: {
    allowNull: false,
    type: DataTypes.STRING,
    unique: true
  },
  category: {
    allowNull: false,
    type: DataTypes.STRING
  },
  price: {
    allowNull: false,
    type: DataTypes.INTEGER
  },
  minutes: {
    allowNull: false,
    type: DataTypes.INTEGER
  },
  image: {
    allowNull: false,
    type: DataTypes.STRING,
    unique: true,
    defaultValue: ""
  },
  description: {
    allowNull: false,
    type: DataTypes.TEXT,
    unique: true,
    defaultValue: ""
  }
};

class Service extends Model {

  static associate() {
    // associate
  };

  static config(sequelize) {
    return {
      sequelize,
      tableName: SERVICE_TABLE,
      modelName: 'Service',
      timestamps: false
    }
  }
};

module.exports = { SERVICE_TABLE, ServiceSchema, Service };

Mientras que el código para implementar esto a nivel de servicios es este:

const boom = require('@hapi/boom');
const { models } = require('../libs/sequelize');

class ServicesService {

  constructor(){}

  async create(data) {
    let { title, category, price, minutes, image, description } = data;
    const newId = await models.Service.count() + 1;
    const response = await models.Service.create({
      id: newId,
      title: title,
      category: category,
      price: price,
      minutes: minutes,
      image: image,
      description: description
    })
    return response;
  };

  async find() {
    const response = await models.Service.findAll();
    return response;
  };

  async findOne(id) {
    const response = await models.Service.findByPk(id);
    if (!response) {
      throw boom.notFound('Service not found');
    }
    return response;
  };

  async update(id,changes) {
    const responseId = await models.Service.findByPk(id);
    if (!responseId) {
      throw boom.notFound('Service not found');
    };
    await models.Service.update(changes,{
      where: {
        id: responseId.id
      }
    });
    return {
      id: responseId.id,
      ...changes
    }
  };

  async delete(id) {
    const responseId = await models.Service.findByPk(id);
    if (!responseId) {
      throw boom.notFound('Service not found');
    };
    await models.Service.destroy({
      where: {
        id: responseId.id
      }
    });
    return {
      id: responseId.id
    }
  };
};

Holaaa les dejo un ejemplo para los que hariamos el insert en la terminal: INSERT INTO users(id,email,password,create_at) VALUES (1,‘[email protected]’,‘h4j3hb2’,‘2020-12-12 10:12:12’);

aparte de que esta clase si estuvo bastante pesada y avanzada, aprendi a irme a una funcion de otro archivo precionando ctrl click

Uff el ORM facilita mucho la ejecución de queries. En la práctica ¿Qué es mejor, simplificarte el trabajo un poco usando ORM o usar el lenguaje que nos proporciona el DBMS? ¿Hay algún estándar que nos diga cuando utilizar cada uno?

me sale error de findAll not defined