Presentamos Camo: un ODM ES6 basado en clases para bases de datos similares a Mongo

Editar: Código Camo actualizado a v0.12.1 Camo es un ODM ES6 con modelos basados ​​en clases. Algunas de sus características principales son: declaración de esquema simple, esquema intuitivo...

Editar: Código Camo actualizado a v0.12.1

¿Qué es el camuflaje? {#lo que escamo}

camuflaje es un ODM ES6 con modelos basados ​​en clases. Algunas de sus características principales son: declaración de esquema muy simple, herencia de esquema intuitiva y soporte para múltiples bases de datos.

Un modelo Camo simple podría verse así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var Document = require('camo').Document;

class Car extends Document {
    constructor() {
        super();

        this.make = String;
        this.miles = Number;
        this.numWheels = {
            type: Number;
            default: 4
        };
    }
}

Para instalar, solo use:

1
2
3
4
5
6
7
npm install camo --save

AND

npm install nedb --save
OR
npm install mongodb --save

¿Por qué otro ODM?

Por mucho que quisiera que me gustara Mongoose, como parecía gustarles a todos los demás, simplemente no podía aceptarlo. Puede haber sido porque todavía era nuevo en JavaScript, y no había abrazado el aspecto de la programación funcional tanto como debería, pero me decepcionó la forma en que se declararon los modelos y la falta de herencia de esquema (o al menos al menos es torpeza).

Viniendo de un fondo de Java, soy muy aficionado a las clases. Así que diseñar modelos sin poder usar fácilmente clases o herencia fue difícil para mí. Al ver que ES6 tiene soporte tradicional de clases y herencia, me sorprendió ver que ningún ODM de Node.js estaba basado en clases.

Por último, me gustó cómo en SQL se podía cambiar fácilmente entre bases de datos pequeñas y portátiles como SQLite para desarrollo y bases de datos más grandes y escalables como PostgreSQL para producción. Al ver que NeDB llena muy bien ese vacío para MongoDB, quería un ODM que me permitiera cambiar fácilmente entre estas bases de datos.

Características

Clases

Como se mencionó anteriormente, Camo gira en torno a las clases de ES6 para crear modelos. Cada modelo debe extender la clase Document, la clase EmbeddedDocument u otro modelo. Los esquemas se declaran en los constructores, donde puede especificar el tipo de datos, los valores predeterminados, las opciones y otros validadores.

Los virtuales, los métodos y los estáticos se pueden usar para manipular y recuperar los datos del modelo, al igual que una clase normal no persistente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var Document = require('camo').Document;

class Manufacturer extends Document {
    constructor() {
        super();

        this.name = String;
    }
}

class Car extends Document {
    constructor() {
        super();

        this.make = Manufacturer;
        this.model = String;
        this.year = {
            type: Number,
            min: 1900,
            max: 2015
        };
        this.miles = {
            type: Number,
            min: 0
        };
        this.numWheels = {
            type: Number;
            default: 4
        };
    }

    get isUnderWarranty() {
        return this.miles < 50000;
    }

    milesPerYear() {
        return this.miles / (new Date().getFullYear() - this.year)
    };
}

Documentos integrados {#documentos integrados}

Una de las principales ventajas de usar MongoDB es su estructura de datos anidados, y debería poder aprovecharla fácilmente en su ODM. Camo tiene soporte de documentos incorporado incorporado, por lo que puede tratar los datos de documentos anidados como lo haría con un documento normal.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var Document = require('camo').Document;
var EmbeddedDocument = require('camo').EmbeddedDocument;

class Warranty extends EmbeddedDocument {
    constructor() {
        super();

        this.miles = Number;
        this.years = Number;
        this.isUnlimitedMiles = Boolean;
    }

    isCovered(car) {
        var thisYear = new Date().getFullYear();
        return ((car.miles <= this.miles) || this.isUnlimitedMiles) &&
            ((thisYear - car.year) <= this.years)
    };
}

class Manufacturer extends Document {
    constructor() {
        super();

        this.name = String;

        this.basicWarranty = Warranty;
        this.powertrainWarranty = Warranty;
        this.corrosionWarranty = Warranty;
    }
}

Compatibilidad con múltiples bases de datos

No todos los proyectos requieren una base de datos enorme con replicación, balanceo de carga y soporte para millones de lecturas/escrituras por segundo, razón por la cual era importante que Camo admitiera múltiples bases de datos, como NeDB.

La mayoría de los proyectos comienzan siendo pequeños y eventualmente se convierten en productos más grandes y populares que requieren bases de datos más rápidas y sólidas. Con NeDB, obtiene un subconjunto de los comandos API más utilizados de MongoDB sin necesidad de configurar la base de datos completa. Es como tener el equivalente de SQLite, pero para Mongo. Para cambiar entre las bases de datos, simplemente proporcione una cadena de conexión diferente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var connect = require('camo').connect;

var uri;
var neUri = 'nedb://memory';
var mongoUri = 'mongodb://localhost/car-app';

uri = neUri;
if (process.env.NODE_ENV === 'production') {
    uri = mongoUri;
}

connect(uri).then(function(db) {
    // Ready to use Camo!
});

A partir de la v0.5.5, Camo es compatible con MongoDB y NeDB. Estamos planeando agregar soporte para más bases de datos similares a Mongo, incluidas [LokiJS] (http://lokijs.org/#/) y [taffydb] (http://www.taffydb.com/). Con NeDB y las adiciones de LokiJS y TaffyDB, también puede usar Camo en el navegador.

Herencia

Podría decirse que una de las mejores características de Camo es la herencia de esquema. Simplemente use la herencia de clase ES6 para extender un esquema.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var Document = require('camo').Document;

class Vehicle extends Document {
    constructor() {
        super();

        this.make = String;
        this.model = String;
        this.year = Number;
        this.miles = Number;
    }
}

class Car extends Vehicle {
    constructor() {
        super();

        this.numberOfDoors = String;
    }
}

Las subclases pueden anular o ampliar cualquier esquema, virtual, método o estático, lo que da como resultado un código más legible y más simple.

¿Camo está listo para la producción?

Si bien Camo ya tiene bastantes características y solo algunos errores conocidos, todavía es un trabajo en progreso. Aquí hay una breve lista de las características principales que aún queremos agregar al proyecto antes de declarar v1.0:

  • Devuelve un objeto Query desde findOne/find/delete/etc
  • Agregar compatibilidad con omitir/limitar las consultas
  • Agregue una opción para completar solo las referencias especificadas
  • Agregar soporte para LokiJS y TaffyDB

Dicho esto, Camo ya se está utilizando en el código de producción en polimetria (un SaaS que proporciona métricas para Stripe). El código base de Polymetrics se creó originalmente en Mongoose, pero luego se reemplazó con Camo sin ningún problema. Las pruebas y el desarrollo son mucho más fáciles ahora que podemos cambiar fácilmente entre bases de datos.

Camo también facilitó mucho el diseño de los modelos para Polymetrics. Gran parte de los datos que necesitamos para descargar y guardar de Stripe tienen los mismos campos (como fechas, metadatos, etc.), por lo que extender un esquema común nos permitió escribir menos código y solo nos permitió cambiar la base. esquema en lugar de tener que hacer el mismo cambio en muchos archivos.

Conclusión

Dirígete a las páginas npm o Github y consulta el proyecto. El archivo README es actualmente la mejor fuente de documentación, así que si falta algo, házmelo saber.

Como siempre, cualquier sugerencia, pregunta, comentario o solicitud de extracción es bienvenida. No dude en ponerse en contacto conmigo a través de [Gorjeo] (https://twitter.com/ScottWRobinson), [Github] (https://github.com/scottwrobinson) o correo electrónico.