El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

ORM perfecto para TypeScript

¿Qué es un ORM? Un ORM proporciona una forma más sencilla de interactuar con bases de datos en una aplicación, permite a los desarrolladores trabajar con datos utilizando objetos.

· 5 min de lectura
ORM perfecto para TypeScript

¿Qué es un ORM perfecto para TypeScript?
Veamos las características ideales que debería tener un ORM para TypeScript y NodeJS y por qué dichas características son tan importantes, así como el modo en que los ORM existentes se quedan cortos en algunas de estas áreas.

Características:

Las 5 características principales que un perfecto TypeScript ORM debe tener son:

Consultas serializables:

La capacidad de transportar consultas entre las capas de un sistema es genial para la flexibilidad y la simplicidad. Por ejemplo, el front/client podría transmitir las consultas al back/server usando la misma sintaxis (ORM) y evitar la necesidad de una sintaxis adicional como lo que ocurre con GraphQL en el flujo GraphQL => ORM => SQL.

En su lugar, el flujo podría simplificarse como ORM => SQL; con las siguientes ventajas:

  • Evitar la necesidad de un pseudo-lenguaje para definir las consultas (cambio de contexto). En su lugar, utiliza JSON estándar como sintaxis para las consultas, de modo que sean totalmente declarativas y serializables.
  • Evita servidores y pasos adicionales en el proceso de compilación de la aplicación.
  • Soporte nativo de los editores /IDEs para las consultas sin necesidad de plugins/extensiones personalizados.

TypeScript nativo:

Exprime la potencia de TypeScript con JSON, clases y decoradores.

  • Consultas y modelos seguros que son validados de forma nativa por el mismo lenguaje que utilizas para escribir tu aplicación.
  • Las consultas conscientes del contexto permiten autocompletar los operadores y campos adecuados según las diferentes partes de una consulta.
  • Definición de entidades con clases y decoradores estándar para evitar la necesidad de DSL propietarios, pasos adicionales en el proceso de compilación y extensiones personalizadas para los editores.

Operadores multinivel:

Operaciones como filtrar, ordenar, limitar, proyectar y otras funcionan en cualquier nivel de las consultas (incluidas las relaciones y sus campos).

API coherente en todas las bases de datos:

Escribe las consultas para cualquier base de datos de forma coherente y, a continuación, optimiza de forma transparente estas consultas para el dialecto de base de datos configurado.

Sintaxis universal (agnóstico al lenguaje):

La capacidad de escribir consultas en cualquier lenguaje abre la puerta a muchas posibilidades, incluso portar el ORM a otros lenguajes. Por ejemplo, JSON es un formato ciudadano de primera clase en casi cualquier lenguaje moderno que exista, incluidos los de JavaScript.

¿Por qué los 3 mejores ORM de TypeScript se quedan cortos en estas características?

¿Qué le falta a TypeORM para ser un ORM perfecto?

Falta de consultas 100% serializables

Observa cómo el operador LessThan es una función que tiene que ser importada y llamada para crear una consulta para negar una condición, y cómo eso impide cualquier capacidad de serializar la consulta.

import { LessThan } from 'typeorm';

const loadedPosts = await dataSource.getRepository(Post).findBy({
  likes: LessThan(10)
});

Falta de TypeScript nativo:

La consulta se disuelve en cadenas porque relations y  where puede aceptar cualquier cadena, por lo que cualquier cadena no válida se puede poner allí.

const posts = await connection.manager.find(Post, {
  select: ['id'],
  relations: ['< anything can go here >']
});

Falta de una API coherente en todas las bases de datos:

En la sección que TypeORM tiene para MongoDB, hay una advertencia autoexplicativa sobre esto.

Falta de sintaxis universal (agnóstico del lenguaje):

Depende de cierres para soportar consultas avanzadas (y no todos los lenguajes soportan cierres).

¿Qué le falta a Prisma para ser un ORM perfecto?

Falta de TypeScript nativo:

  • El cambio de contexto entre el DSL personalizado y TypeScript hace que este proceso sea molesto.
  • Pasos extra en el proceso de compilación para generar los archivos correspondientes del DSL personalizado.
  • Necesidad de instalar una extensión personalizada para VsCode para obtener autocompletado (básico) desde el editor para el DSL, que está lejos de ser tan bueno y fiable como con TypeScript.
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  posts     Post[]
}

Falta de una API consistente entre bases de datos

Prisma expone detalles de bajo nivel sobre MongoDB que podrían ser encapsulados por el ORM.

model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  // Other fields
}

Falta de sintaxis universal (agnóstico del lenguaje):

Depende de su propio DSL propietario para definir los modelos.

¿Qué le falta a Mikro-ORM para ser un ORM perfecto?

Falta de consultas 100% serializables

Observa como esa consulta utiliza dos métodos separados, uno para el update y otro para el where, esto impide la serialización de sus consultas.

const qb = orm.em.createQueryBuilder(Author);

qb.update({ name: 'test 123', type: PublisherType.GLOBAL })
  .where({ id: 123, type: PublisherType.LOCAL });

Falta de TypeScript nativo

Se disuelve en cadenas, cualquier cadena puede ir dentro del array fields, por lo que la consulta perdió la posibilidad de ser type-safe.

const author = await em.findOne(Author,
  {},
  {
    fields: ['name', 'books.title', 'books.author', 'books.price']
  }
);

Falta de operadores multinivel

¿Qué pasa si se necesita filtrar los registros de una relación u ordenarlos? esto parece inalcanzable de una manera segura por lo que se puede ver en los documentos de Mikro-ORM.

Falta de una API coherente en todas las bases de datos

import { EntityManager } from '@mikro-orm/mongodb';
const em = orm.em as EntityManager;
const qb = em.aggregate(...);

Mikro-ORM expone detalles de bajo nivel sobre MongoDB que podrían ser encapsulados por el ORM.

Las razones anteriores fueron insparación  para escribir un nuevo tipo de ORM, que estoy llamando nukak.


Entonces, ¿por qué nukak es la opción más cercana para un ORM perfecto? en pocas palabras, porque fue diseñado con estos fundamentos en mente, vea cómo.

Consultas 100% serializables

Incluso las operaciones de inserción y actualización tienen una API totalmente serializable.

const lastUsers = await querier.findMany(User,
  {
    $sort: { createdAt: -1 },
    $limit: 20
  },
  ['id', 'name', 'email']
);

TypeScript nativo con consultas realmente seguras:

Cada operador y campo se valida según el contexto. Por ejemplo, los posibles valores del operador $project dependerán automáticamente del nivel.

const lastUsersWithProfiles = await querier.findMany(User,
  {
    $sort: { createdAt: -1 },
    $limit: 20
  },
  {
    id: true,
    name: true,
    profile: {
      $project: ['id', 'picture'],
      $required: true
    }
  }
);

Operarios multinivel

Los operadores funcionan en cualquier nivel. Por ejemplo, el operador $sort puede aplicarse a las relaciones y sus campos de forma segura para el tipo y consciente del contexto.

const items = await querier.findMany(Item,
  {
    $filter: {
      salePrice: { $gte: 1000 }, name: { $istartsWith: 'A' }
    },
    $sort: {
      tax: { name: 1 }, measureUnit: { name: 1 }, createdAt: -1 
    },
    $limit: 100,
  },
  {
    id: true,
    name: true,
    measureUnit: {
      $project: ['id', 'name'],
      $filter: { name: { $ne: 'unidad' } },
      $required: true
    },
    tax: ['id', 'name'],
  }
);

API coherente en todas las bases de datos

Su API está unificada entre las diferentes bases de datos, hace la magia bajo el capó para que las mismas entidades y consultas puedan funcionar de forma transparente en cualquiera de las bases de datos soportadas.

Por ejemplo, esto facilita el cambio de una base de datos documental a una relacional (o viceversa).

Sintaxis universal entre lenguajes

Su sintaxis es 100% JSON estándar, lo que abre la puerta a muchas posibilidades con otros lenguajes, como la interoperabilidad o incluso crear versiones de nukak en otros lenguajes como Python o Rust con facilidad.

Más información en nukak.org

Gracias por llegar hasta el final de este blog quiero recordarte que todo esto es gratis y posible gracias a que tu compartes. Un fuerte abrazo y recuerda que el conocimiento es poder.

Invertir en conocimientos produce siempre los mejores beneficios. (Benjamín Franklin)

Fuente

Plataforma de cursos gratis sobre programación