Mòdul de comunitat impressionant

Cartografia relacional d'objectes per a fibjs

Estat de la compilació

Instal·la

1
npm install fib-orm

Prova

1
npm run ci

Suport SGBD

  • MySQL i MariaDB
  • SQLite

Característiques

fib-orm afegeix un conjunt de mètodes de versió síncrona a l'objecte node-orm.

Introducció

Es tracta d’un mòdul de mapatge relacional d’objectes fibjs.

Un exemple:

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
var orm = require("fib-orm"); var db = orm.connectSync("mysql://username:password@host/database"); var Person = db.define("person", { name : String, surname : String, age : Number, // FLOAT male : Boolean, continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type photo : Buffer, // BLOB/BINARY data : Object // JSON encoded }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } }, validations: { age: orm.enforce.ranges.number(18, undefined, "under-age") } }); // add the table to the database db.syncSync(); // add a row to the person table Person.createSync({ id: 1, name: "John", surname: "Doe", age: 27 }); // query the person table by surname var people = Person.findSync({ surname: "Doe" }); // SQL: "SELECT * FROM person WHERE surname = 'Doe'" console.log("People found: %d", people.length); console.log("First person: %s, age %d", people[0].fullName(), people[0].age); people[0].age = 16; people[0].saveSync();

La versió node.js és la següent:

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 40 41 42 43 44 45 46 47 48 49
var orm = require("orm"); orm.connect("mysql://username:password@host/database", function (err, db) { if (err) throw err; var Person = db.define("person", { name : String, surname : String, age : Number, // FLOAT male : Boolean, continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type photo : Buffer, // BLOB/BINARY data : Object // JSON encoded }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } }, validations: { age: orm.enforce.ranges.number(18, undefined, "under-age") } }); // add the table to the database db.sync(function(err) { if (err) throw err; // add a row to the person table Person.create({ id: 1, name: "John", surname: "Doe", age: 27 }, function(err) { if (err) throw err; // query the person table by surname Person.find({ surname: "Doe" }, function (err, people) { // SQL: "SELECT * FROM person WHERE surname = 'Doe'" if (err) throw err; console.log("People found: %d", people.length); console.log("First person: %s, age %d", people[0].fullName(), people[0].age); people[0].age = 16; people[0].save(function (err) { // err.msg = "under-age"; }); }); }); }); });

Documentació

Fibjs no afegir noves funcions, l'elaboració de documents es pot referir a el node-ORM, només cal canviar la crida asincrònica a la versió sincrònica. Wiki .

Configuració

Veure informació a la wiki .

Connectant

Veure informació a la wiki .

Models

Un model és una abstracció sobre una o més taules de bases de dades. Els models admeten associacions (més a sota). Se suposa que el nom del model coincideix amb el nom de la taula.

Els models admeten comportaments per accedir i manipular dades de taula.

Definició de models

Veure informació a la wiki .

Properties

Veure informació a la wiki .

Instance Methods

Es transmeten durant la definició del model.

1 2 3 4 5 6 7 8 9 10 11 12 13
var Person = db.define('person', { name : String, surname : String }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } } }); var person = Person.getSync(4); console.log( person.fullName() );

Model Methods

Es defineixen directament sobre el model.

1 2 3 4 5 6 7 8 9
var Person = db.define('person', { name : String, height : { type: 'integer' } }); Person.tallerThan = function(height) { return this.findSync({ height: orm.gt(height) }); }; var tallPeople = Person.tallerThan( 192);

S'estan carregant els models [NO SUPORT]

Els models es poden incloure en mòduls separats. Simplement assegureu-vos que el mòdul que conté els models utilitzi module.exports per publicar una funció que accepti la connexió a la base de dades i, a continuació, carregueu els models com vulgueu.

Si utilitzeu aquesta tècnica, podeu tenir càrregues en cascada.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// your main file (after connecting) db.loadSync("./models"); // loaded! var Person = db.models.person; var Pet = db.models.pet; // models.js module.exports = function (db) { db.loadSync("./models-extra"); db.define('person', { name : String }); }; // models-extra.js module.exports = function (db) { db.define('pet', { name : String }); };

Sincronització de models

Veure informació a la wiki .

Eliminació de models

Veure informació a la wiki .

Opcions avançades

ORM2 us permet fer algunes modificacions avançades a les definicions del vostre model. Podeu configurar-les mitjançant la configuració o la trucada definequan configureu el model.

Per exemple, cada instància de model té un identificador únic a la base de dades. Aquesta columna de taula s'afegeix automàticament i s'anomena per defecte "id".
Si definiu la vostra pròpia key: truecolumna, no s'afegirà "id":

1 2 3 4 5 6 7 8 9 10 11 12
var Person = db.define("person", { personId : { type: 'serial', key: true }, name : String }); // You can also change the default "id" property name globally: db.settings.set("properties.primary_key", "UID"); // ..and then define your Models var Pet = db.define("pet", { name : String });

El model de mascota tindrà 2 columnes, una UIDi una name.

També és possible tenir tecles compostes:

1 2 3 4
var Person = db.define("person", { firstname : { type: 'text', key: true }, lastname : { type: 'text', key: true } });

Altres opcions:

  • identityCache : (per defecte :) falseEstabliu-lo per truehabilitar la memòria cau d'identitat ( Singletons ) o definiu un valor d'espera (en segons);
  • autoSave : (per defecte :) falseEstabliu-lo en trueper desar una instància just després de canviar qualsevol propietat;
  • autoFetch : (per defecte :) falseEstabliu-lo en trueper obtenir associacions quan es busca una instància de la base de dades;
  • autoFetchLimit: (per defecte :) 1Si autoFetchestà activat, es defineix quants cèrcols (associacions d'associacions) voleu que obtingui automàticament.

Ganxos

Veure informació a la wiki .

Cercar articles

Model.getSync(id, [ options ])

Per obtenir un element específic de l'ús de la base de dades Model.get.

1 2
var person = Person.getSync(123); // finds person with id = 123

Model.findSync([ conditions ] [, options ] [, limit ] [, order ])

Trobar un o més elements té més opcions, cadascun es pot donar en cap ordre de paràmetre específic. Només optionsha de ser després conditions(encara que sigui un objecte buit).

1 2
var people = Person.findSync({ name: "John", surname: "Doe" }, 3); // finds people with name='John' AND surname='Doe' and returns the first 3

Si necessiteu ordenar els resultats perquè esteu limitant o simplement perquè voleu que s’ordenin, feu el següent:

1 2 3 4 5 6
var people = Person.findSync({ surname: "Doe" }, "name"); // finds people with surname='Doe' and returns sorted by name ascending people = Person.findSync({ surname: "Doe" }, [ "name", "Z" ]); // finds people with surname='Doe' and returns sorted by name descending // ('Z' means DESC; 'A' means ASC - default)

Hi ha més opcions que podeu passar per trobar alguna cosa. Aquestes opcions es passen en un segon objecte:

1 2
var people = Person.findSync({ surname: "Doe" }, { offset: 2 }); // finds people with surname='Doe', skips the first 2 and returns the others

També podeu fer servir SQL en brut en fer cerques. Es documenta a la secció Encadenament següent.

Model.countSync([ conditions])

Si només voleu comptar el nombre d'elements que coincideixen amb una condició, podeu utilitzar-los .count()en lloc de trobar-los tots i comptabilitzar-los. Això indicarà al servidor de base de dades que faci un recompte (no es farà en el propi procés del node) ).

1 2
var count = Person.countSync({ surname: "Doe" }); console.log("We have %d Does in our db", count);

Model.existsSync([ conditions])

De manera similar .count(), aquest mètode només comprova si el recompte és superior a zero o no.

1 2
var exists = Person.existsSync({ surname: "Doe" }); console.log("We %s Does in our db", exists ? "have" : "don't have");

Aggregating Functions

Una Arrayde les propietats es pot passar per seleccionar només algunes propietats. ObjectTambé s'accepta una per definir les condicions.

Aquí teniu un exemple per il·lustrar com s'utilitza .groupBy():

1 2 3
//The same as "select avg(weight), age from person where country='someCountry' group by age;" var stats = Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age").getSync(); // stats is an Array, each item should have 'age' and 'avg_weight'

.aggregate()Mètodes bàsics

  • .limit(): podeu passar un número com a límit o dos números com a desplaçament i límit respectivament
  • .order(): el mateix que Model.find().order()

.aggregate()Mètodes addicionals

  • min
  • max
  • avg
  • sum
  • count(hi ha una drecera a això Model.count)

Hi ha més funcions agregades en funció del controlador (per exemple, funcions matemàtiques).

Chaining

Si preferiu una sintaxi menys complicada, podeu encadenar .find()sense donar cap paràmetre de devolució de trucada.

1 2 3
var people = Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "surname").runSync(); // finds people with surname='Doe', skips first 2 and limits to 3 elements, // returning only 'name' and 'surname' properties

Si voleu ometre només una o dues propietats, podeu trucar .omit()en lloc de .only.

La cadena permet fer consultes més complicades. Per exemple, podem fer cerques especificant SQL personalitzat:

1
Person.find({ age: 18 }).where("LOWER(surname) LIKE ?", ['dea%']).allSync( ... );

És una mala pràctica escapar manualment dels paràmetres SQL, ja que és propens a errors i exposa la vostra aplicació a injecció SQL. La ?sintaxi s’encarrega d’escapar-vos substituint el signe d’interrogació de la consulta amb els paràmetres proporcionats. També podeu encadenar diverses whereclàusules com necessari.

.find, .where& .allfer el mateix; tots són intercanviables i encadenables.

També podeu ordero orderRaw:

1 2 3
Person.find({ age: 18 }).order('-name').allSync( ... ); // see the 'Raw queries' section below for more details Person.find({ age: 18 }).orderRaw("?? DESC", ['age']).allSync( ... );

També podeu encadenar i obtenir el recompte al final. En aquest cas, la compensació, el límit i l'ordre s'ignoren.

1 2
var people = Person.find({ surname: "Doe" }).countSync(); // people = number of people with surname="Doe"

També està disponible l'opció per eliminar els elements seleccionats. Tingueu en compte que una eliminació encadenada no executarà cap ganxo.

1 2
Person.find({ surname: "Doe" }).removeSync(); // Does gone..

També podeu fer modificacions a les vostres instàncies mitjançant mètodes de recorregut de matriu comuns i desar-ho tot al final. [NO SUPORT]

1 2 3 4 5 6 7 8 9 10 11 12 13
Person.find({ surname: "Doe" }).each(function (person) { person.surname = "Dean"; }).save(function (err) { // done! }); Person.find({ surname: "Doe" }).each().filter(function (person) { return person.age >= 18; }).sort(function (person1, person2) { return person1.age < person2.age; }).get(function (people) { // get all people with at least 18 years, sorted by age });

Per descomptat, podeu fer-ho directament .find(), però per a tasques més complicades això pot ser molt útil.

Model.find()no retorna una matriu de manera que no només pot encadenar directament. Per a iniciar l'encadenament vostè ha de trucar .each()(amb una devolució de trucada opcional si vol recórrer la llista). A continuació, pot utilitzar les funcions comuns .filter(), .sort()i .forEach()més d'una vegada.

Al final (o durant el procés ..) podeu trucar a:

  • .countSync() si només voleu saber quants articles hi ha;
  • .getSync() per recuperar la llista;
  • .saveSync() per desar tots els canvis d’element.

Condicions

Les condicions es defineixen com un objecte en què cada clau és una propietat (columna de taula). Se suposa que totes les claus són concatenades per la lògica AND. Es considera que els valors coincideixen exactament, tret que estigueu passant una Array. En aquest cas, es considera una llista per comparar la propietat.

1 2
{ col1: 123, col2: "foo" } // `col1` = 123 AND `col2` = 'foo' { col1: [ 1, 3, 5 ] } // `col1` IN (1, 3, 5)

Si necessiteu altres comparacions, heu d’utilitzar un objecte especial creat per algunes funcions d’ajuda. A continuació, en detallem alguns exemples:

1 2 3 4 5 6 7 8 9 10 11
{ col1: orm.eq(123) } // `col1` = 123 (default) { col1: orm.ne(123) } // `col1` <> 123 { col1: orm.gt(123) } // `col1` > 123 { col1: orm.gte(123) } // `col1` >= 123 { col1: orm.lt(123) } // `col1` < 123 { col1: orm.lte(123) } // `col1` <= 123 { col1: orm.between(123, 456) } // `col1` BETWEEN 123 AND 456 { col1: orm.not_between(123, 456) } // `col1` NOT BETWEEN 123 AND 456 { col1: orm.like(12 + "%") } // `col1` LIKE '12%' { col1: orm.not_like(12 + "%") } // `col1` NOT LIKE '12%' { col1: orm.not_in([1, 4, 8]) } // `col1` NOT IN (1, 4, 8)

Consultes en brut

1 2 3 4 5 6 7 8 9 10 11 12 13
var data = db.driver.execQuerySync("SELECT id, email FROM user") // You can escape identifiers and values. // For identifier substitution use: ?? // For value substitution use: ? var data = db.driver.execQuerySync( "SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? > ?", ['id', 'name', 'name', 'john', 'id', 55]) // Identifiers don't need to be scaped most of the time var data = db.driver.execQuerySync( "SELECT user.id, user.name FROM user WHERE user.name LIKE ? AND user.id > ?", ['john', 55])

Identity pattern

Podeu utilitzar el patró d'identitat (desactivat per defecte). Si està activat, diverses consultes diferents donaran lloc al mateix resultat: obtindreu el mateix objecte. Si teniu altres sistemes que poden canviar la vostra base de dades o heu de trucar a algun manual Consultes SQL, no heu d'utilitzar aquesta funció. També se sap que pot causar problemes amb relacions complexes d'autofetch. Utilitzeu-ho al vostre propi risc.

Es pot habilitar / desactivar per model:

1 2 3 4 5
var Person = db.define('person', { name : String }, { identityCache : true });

i també a nivell mundial:

1 2
var db = orm.connectSync('...'); db.settings.set('instance.identityCache', true);

La memòria cau d'identitat es pot configurar perquè caduqui després d'un període de temps passant un número en lloc d'un booleà. El número es considerarà el temps d'espera de la memòria cau en segons (podeu utilitzar el punt flotant).

Nota : Una excepció sobre la memòria cau és que no s'utilitzarà si no es desa una instància. Per exemple, si obteniu una persona i la canvieu, mentre no es desa, no es passarà de la memòria cau.

Creació d’elements

Model.createSync(items)

Per inserir nous elements a l'ús de la base de dades Model.create.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var items = Person.createSync([ { name: "John", surname: "Doe", age: 25, male: true }, { name: "Liza", surname: "Kollan", age: 19, male: false } ]); // items - array of inserted items

S'estan actualitzant els elements

Tots els articles retornats tenen les propietats definides al model i també un parell de mètodes que podeu utilitzar per canviar cada element.

1 2 3 4 5
var John = Person.getSync(1); John.name = "Joe"; John.surname = "Doe"; John.saveSync(); console.log("saved!");

L'actualització i després desar una instància es pot fer en una sola trucada:

1 2 3
var John = Person.getSync(1); John.saveSync({ name: "Joe", surname: "Doe" }); console.log("saved!");

Si voleu eliminar una instància, feu el següent:

1 2 3 4
// you could do this without even fetching it, look at Chaining section above var John = Person.getSync(1); John.removeSync(); console.log("removed!");

Validacions

Veure informació a la wiki .

Associacions

Una associació és una relació entre una o més taules.

hasOne

A ÉS MOLT per a un . És la mateixa relació, com pertany a.
Per exemple: Animal.hasOne('owner', Person).. L’
ANIMAL POT tenir només un propietari, en té MOLTES. Però la persona que els animals
de Will tindran a la owner_idpropietat s’afegirà automàticament.

Les següents funcions estaran disponibles:

1 2 3 4
animal.getOwnerSync() // Gets owner animal.setOwnerSync(person) // Sets owner_id animal.hasOwnerSync() // Checks if owner exists animal.removeOwnerSync() // Sets owner_id to 0

Cerca de cadenes

L'associació hasOne també és compatible amb la cerca en cadena. Amb l'exemple anterior, podem fer-ho per accedir a una nova instància d'un objecte ChainFind:

1
Animal.findByOwner({ /* options */ })

Accés invers

1
Animal.hasOne('owner', Person, {reverse: 'pets'})

afegirà el següent:

1 2 3 4 5 6
// Instance methods person.getPetsSync(function..) person.setPetsSync(cat, function..) // Model methods Person.findByPets({ /* options */ }) // returns ChainFind object

hasMany

A és de molts a molts relació (inclou la taula d'unió).
Per exemple, de: Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients', key: true }).
. El pacient cada llauna metge metges tenen molts poden tenir diferents Diferents pacients tenen tenen molts.

Això crearà una taula d'unió patient_doctorsquan truqueu Patient.sync():

nom de la columna tipus
identificador_pacient Enter (tecla composta)
identificador_doctor Enter (tecla composta)
Per què varchar (255)

Estaran disponibles les funcions següents:

1 2 3 4 5 6 7 8 9 10 11 12
patient.getDoctorsSync() // List of doctors patient.addDoctorsSync(docs) // Adds entries to join table patient.setDoctorsSync(docs) // Removes existing entries in join table, adds new ones patient.hasDoctorsSync(docs) // Checks if patient is associated to specified doctors patient.removeDoctorsSync(docs) // Removes specified doctors from join table doctor.getPatientsSync() etc... // You can also do: patient.doctors = [doc1, doc2]; patient.saveSync()

Per associar un metge a un pacient:

1
patient.addDoctorSync(surgeon, {why: "remove appendix"})

que s'afegirà {patient_id: 4, doctor_id: 6, why: "remove appendix"}a la taula d'unió.

getAccessor

Aquest usuari d'aquest tipus d'associació retorna ChainFinduna trucada si no passa, de manera que podeu fer coses com:

1 2
var doctors = patient.getDoctors().order("name").offset(1).runSync()); // ... all doctors, ordered by name, excluding first one

extendsTo

Si voleu dividir les propietats opcionals en taules o col·leccions diferents. Totes les extensions seran en una taula nova, on l'identificador únic de cada fila és l'identificador principal de la instància del model. Per exemple:

1 2 3 4 5 6 7
var Person = db.define("person", { name : String }); var PersonAddress = Person.extendsTo("address", { street : String, number : Number });

Un Crear taula de l'est personamb les columnes idi name. Extensió de la voluntat de crear una taula person_addressamb les columnes person_id, streeti number. Disponible en els mètodes de la Personmodel són similars a altres hasOne associació. Vols que el En el present Exemple ser capaç de cridar .getAddress(cb), .setAddress(Address, cb)..

Nota: no cal que deseu el resultat Person.extendsTo. Retorna un model ampliat. Podeu utilitzar-lo per consultar directament aquesta taula ampliada (i fins i tot trobar el model relacionat), però depèn de vosaltres. Si només hi voleu accedir utilitzant el model original, només podeu descartar la devolució.

Examples & options

Si teniu una relació d'1 a n, hauríeu d'utilitzar hasOne(pertany a) associació.

1 2 3 4 5 6 7 8 9 10 11 12 13
var Person = db.define('person', { name : String }); var Animal = db.define('animal', { name : String }); Animal.hasOne("owner", Person); // creates column 'owner_id' in 'animal' table // get animal with id = 123 var animal = Animal.getSync(123); // animal is the animal model instance, if found var person = animal.getOwnerSync(); // if animal has really an owner, person points to it

Podeu marcar el owner_idcamp segons es requereixi a la base de dades especificant l' requiredopció:

1
Animal.hasOne("owner", Person, { required: true });

Si no cal un camp, però s'ha de validar encara que no estigui present, especifiqueu l' alwaysValidateopció (això pot passar, per exemple, quan la validació d'un camp nul depèn d'altres camps del registre)

1
Animal.hasOne("owner", Person, { required: false, alwaysValidate: true });

Si preferiu utilitzar un altre nom per al camp (propietari_id), podeu canviar aquest paràmetre a la configuració.

1
db.settings.set("properties.association_key", "{field}_{name}"); // {name} will be replaced by 'owner' and {field} will be replaced by 'id' in this case

Nota: Això s'ha de fer abans que s'especifiqui l'associació.

Les hasManyassociacions poden tenir propietats addicionals a la taula d'associació.

1 2 3 4 5 6 7 8 9 10 11
var Person = db.define('person', { name : String }); Person.hasMany("friends", { rate : Number }, {}, { key: true }); var John = Person.getSync(123); var friends = John.getFriendsSync(); // assumes rate is another column on table person_friends // you can access it by going to friends[N].extra.rate

Si ho preferiu, podeu activar-la autoFetch. D'aquesta manera, les associacions es recuperen automàticament quan obteniu o trobeu instàncies d'un model.

1 2 3 4 5 6 7 8 9 10 11 12
var Person = db.define('person', { name : String }); Person.hasMany("friends", { rate : Number }, { key : true, // Turns the foreign keys in the join table into a composite key autoFetch : true }); var John = Person.getSync(123); // no need to do John.getFriends() , John already has John.friends Array

També podeu definir aquesta opció de forma global en lloc d'una base per associació.

1 2 3 4 5 6 7 8 9 10
var Person = db.define('person', { name : String }, { autoFetch : true }); Person.hasMany("friends", { rate : Number }, { key: true });

Les associacions poden fer trucades al model associat mitjançant l' reverseopció. Per exemple, si teniu una associació del ModelA al ModelB, podeu crear un accessor al ModelB per obtenir instàncies del ModelA. Confusió? Vegeu el següent exemple.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var Pet = db.define('pet', { name : String }); var Person = db.define('person', { name : String }); Pet.hasOne("owner", Person, { reverse : "pets" }); var pets = Person(4).getPetsSync(); // although the association was made on Pet, // Person will have an accessor (getPets) // // In this example, ORM will fetch all pets // whose owner_id = 4

Això té encara més sentit quan es tenen hasManyassociacions, ja que es poden gestionar de moltes a moltes associacions d'ambdues parts.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var Pet = db.define('pet', { name : String }); var Person = db.define('person', { name : String }); Person.hasMany("pets", Pet, { bought : Date }, { key : true, reverse : "owners" }); Person(1).getPetsSync(...); Pet(2).getOwnersSync(...);

Suport a les transaccions

Podeu utilitzar la funció de transacció de baix nivell per processar la transcripció de db.

1 2 3 4 5 6
db.begin(); ... if(err) db.rollback(); else db.commit();

O podeu utilitzar trans per processar-lo de manera senzilla.

1 2 3 4
var result = db.trans(() => { ... return result; });

Addició d’adaptadors de bases de dades externes

Per afegir un adaptador de base de dades extern orm, truqueu al addAdaptermètode, passant l'àlies que s'utilitzarà per connectar-se amb aquest adaptador, juntament amb el constructor de l'adaptador:

1
require('orm').addAdapter('cassandra', CassandraAdapter);

Veure the documentation for creating adapters per a més detalls.