Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
An easy to use ORM for node.js. Supports eager loading, complex queries, joins, transactions, complex database clusters & connection pooling.
An easy to use ORM for node.js. Supports advanced eager loading, complex queries, joins, transactions, complex database clusters & connection pooling. The ORM automatically generates models from the tables & relations stored in your database.
-- alpha software --, expect a stable release in june 2014.
install via npm, you may only install the packages required for you rdbms. currently supported are postgres & mysql.
npm install ee-orm ee-postgres-connection ee-mysql-connection
If the api changes the minor version number will change. So if you use the version «0.2.x» you will have always the same stable api.
var ORM = require('ee-orm');
// load models from the «eventdata» db
var orm = new ORM({
eventdata: {
type: 'postgres'
, hosts: [ // you may add as many hosts as you want
{
host : 'mydbcuster.mycompyny.mytld'
, username : 'eventsUsers'
, password : 'securebeyondanything'
, port : 5432
, mode : 'readwrite' // readonly or writeonly would be other options
}
]
}
});
// you may not interact with the orm before it was laoded
orm.on('load', function(err){
if (err) console.log('failed to load ORM!', err);
else {
// the orm creates dynamically models from your normalized relational database structure
// lets say the db has an events table. an event can have many venues (mapping, m:n).
log(orm); // { events: { events: {}, venues: {}}}
// you may create complex queries using the generated model structure. the orm
// has scanned all relations and knows whic entity belongs to which, there is also
// support for many to many reltions using mapping tables.
// load events with the ids 1-6, get also the venues for the events but select only the
// id and the name attribute
orm.eventdata.events({id: ORM.in(1,2,3,4,5,6)}, ['*']).fetchVenues(['id', 'name']).limit(10).find(function(err, events){
if (err) log(err);
else {
// get first event
events.first().dir() // {id:1, title: "prodigy", startdate: "2012-07-08 22:00:00", venues: [{id: 45, name: "via felsenau"}]};
// add new venue to the second event. the events list is an array with advanced functions
// the relation to the venues table was automatically on the events model.
events[2].venues.push(new orm.eventdata.venues({name: 'dachstock'}));
events[2].save(function(err){
// the venue was inserted to the venue table, the mapping to the event was created
});
}
});
// lets say you want to get all events for a specific venue. you have two possiblitie to do this.
orm.eventdata.events(['id']).fetchVenues({id: 56}).find(function(err, events){
events.dir(); // [{id:1}, {id:2}]
});
orm.eventdata.venues({id: 56}).events(['id']).find(function(err, venues){
venues.dir(); // [{id:56, events: [{id:1}, {id:2}]}]
});
}
});
The consturctor expects the complete configuration used for accessing a database or cluster. The ORM makes always use of a conenction pool which may be configured in the config described below.
var ORM = require('ee-orm');
var ormInstance = new ORM(config);
For every Database used by the ORM you have to provide a complete configuration stored on the the key which must be the name of the database.
// database names «eventdata» and «shopping». the «eventdata» database
// is a single mysql server, the «shopping» database consists of a
// postgres master and a read replica. the orm tries to use the read replica
// for readonly queries
{
eventdata: {
type: 'mysql' // postgres or mysql
, hosts: [
{
host : 'mydbcuster.mycompyny.mytld'
, username : 'eventsUsers'
, password : 'securebeyondanything'
, port : 3306
, mode : 'readwrite' // readonly or writeonly would be other options
, maxConenctions : 50 // optional, defaults to 50
}
]
}
, shopping: {
type: 'postgres'
, hosts: [
{
host : 'mydbcuster.mycompyny.mytld'
, username : 'eventsUsers'
, password : 'securebeyondanything'
, port : 5432
, mode : 'readwrite'
, maxConenctions : 20
, database : 'myDatabase' // optional, the name of the database (not the schema) to
// connect to (defaults to the database name, «shopping» in this case)
}
, {
host : 'mydbcuster.mycompyny.mytld'
, username : 'eventsUsers'
, password : 'securebeyondanything'
, port : 5432
, mode : 'readonly'
, maxConenctions : 200
, database : 'myDatabase' // optional, the name of the database (not the schema) to
// connect to (defaults to the database name, «shopping» in this case)
}
]
}
}
The orm gets the complete structure of every datbase specified in the config. For each database it creates a representation which it stores on itself. The configuration above will result in the object described below. The ORM cannot be used before the «load» event was fired.
ormInstance.on('load', function(err){
if (err) log(err);
else {
log(ormInstance); // {eventdata: {...}, shopping: {...}}
}
});
if you wish we can add support for dynamic adding & removing of database servers.
The querybuilder has support for complex queries. Currently some queries are not supported (please report an issue if there is missing something you like to use). You have to use the «queryRaw» method if you need to execute such queries.
Lets take the configuration defined above an see what tables the «eventdata» database has. The ORM scans every database for all tables and all relations between them. There are on naming conventions or requirements exept from some reserved keywords (see «reserved keywords»).
log(ormInstance.eventdata);
// {
// event: {} // table containing events
// , event_image: {} // mapping to the image table
// , event_language: {} // mapping to the language table (locales)
// , event_venue: {} // mapping tot he venue table, an event can have many venues
// , image: {} // the images table
// , language: {} // the languages
// , venue: {} // th e venues table
// , venue_image: {} // the mapping between venues and images
// , venue_locale: {} // venue locales
// }
Every entity represented in the object above is a querybuilder and has the same set of methods on it:
Every querybuilder has methods linking to all referenced tables. These methods are built using the referenced tables name and the keyword «get» and «fetch». The «get» and «fetch» method do the exact same thing, they differ only in the scope returned. The «event» querybuilder for example has the the following methods added because of its relations to other tables:
if you don't know which methods are available on an entity you can use the «describeMethods» method for listing them.
ormInstance.eventdata.event().describeMethods();
// { getImage: 'Mapping accessor for the «image» Model', .... }
So, what exactly are those generated methods useful for? They let you build complex queries with ease. They make it also possible to fetch unlimited nested data from the database (it will get slower with each additional level you're fetching).
Each of the method accepts the following arguments (of whic all are optional) in any order.
Lets fetch some events:
// select all events in the table, returns only their id (the primary key is selected automatically)
ormInstance.eventdata.event().find(function(err, events){
});
// select all events, return all columns
ormInstance.eventdata.event([*]).find(function(err, events){
});
// select all events, return the id and the title columns
ormInstance.eventdata.event(['id', 'title']).find(function(err, events){
});
Lets select & filter some events:
// fecth the event with the id 9, select the id only
ormInstance.eventdata.event({id: 9}).find(function(err, events){
});
// fecth the event with the id 7,8,9, select the id and title
ormInstance.eventdata.event({id: ORM.in([7, 8, 9])}, ['id', 'title']).find(function(err, events){
});
Lets select all events of the venue with the id 56, select the events title and id
ormInstance.eventdata.event(['id', 'title']).fetchVenue({id:56}).find(function(err, events){
});
// the exact same query as above (get vs fetch)
ormInstance.eventdata.event(['id', 'title']).getVenue({id:56}).find(function(err, events){
});
Lets select all events of the venue with the id 56, select the events title and id and all columns of the venue
ormInstance.eventdata.event(['id', 'title']).getVenue(['*'], {id:56}).find(function(err, events){
});
Now lets also get the images of the venue (get vs fetch)
// loads all events of the venue with the id 56 and all images attched to the venue
//the getVenue did change the scope to the venue entity, so the fetchImage points to
// the images of the ***venue***
ormInstance.eventdata.event(['id', 'title']).getVenue(['*'], {id:56}).fetchImage(['*']).find(function(err, events){
});
// fetchVenue vs getVenue: because we used fetchVenue instead of getVenue the scope
// stays on the previuos item which is in this case the the «event» entity. this query
// fetches all events of the venue with the id 56 and all images attched to the ***event***
ormInstance.eventdata.event(['id', 'title']).fetchVenue(['*'], {id:56}).fetchImage(['*']).find(function(err, events){
});
Now lets do a complex query:
// get all columns of the event table, dont filter yet
var myQuery = ormInstance.eventdata.event(['*']);
// filter events by the venue with the id 56, select all columns of the venue
// table, get the description locale from the locale table where the language
// is english.
// the filter method is called on the language entity because we want all the
// events and not only those with english locales (join vs. left join) but we
// want only the english locales. filter events by locale vs. filter locales
myQuery.getVenue({id:56}, ['*']).fetchImage(['*']).getVenue_language(['description']).getLanguage().filter({code: 'en'});
// get all event images, get the english event locale
myQuery.fetchImage(['*']).getEvent_language(['description']).fetchLanguage({code: 'en'});
// execute the query
myQuery.find(function(err, events){
log(events);
// [
// {
// id: 34
// , title: 'bookashade'
// , event_language: [
// {
// id_event: 32
// , id_language: 1
// , description: 'lorem ipsum ...'
// }
// ]
// , image: [
// {
// id: 34
// , url: 'http://eventemitter.com/...'
// }
// , {
// id: 35
// , url: 'http://eventemitter.com/...'
// }
// ]
// , venue: [
// {
// id: 56
// , name: 'Lavo'
// , venue_language: [
// {
// id_venue: 56
// , id_language: 1
// , description: 'lorem ipsum ...'
// }
// ]
// , image: [
// {
// id: 456
// , url: 'http://eventemitter.com/...'
// }
// , {
// id: 978
// , url: 'http://eventemitter.com/...'
// }
// ]
// }
// ]
// }
// ]
});
The filter object which can be used by the queryuilder and the filter mehotd can contain the following structure
All events receive the following parameters (except those which contain the word «commit»)
Eventlist
beforeSave: emitted before saving the model and all its references & mappings
afterSave: emitted when the model and all its references & mappings were saved, but the transaction was not yet commited
afterSaveCommit: emitted when the model and all its references & mappings were saved and the changes were commited
beforeUpdate: emitted before an upate
afterUpdate: emitted after the update without the transaction commited
afterUpdateCommit: emitted after the update with the changes were commited
beforeInsert: emitted before an insert
afterInsert: emitted after the insert without the transaction commited
afterInsertCommit: emitted after the insert with the changes were commited
the delete event gets as last parameter a flag which indicates if the record was / is goint to be deleted using a softdelete
beforeDelete: emitted before a delete
afterDeleteCommit: emitted after the delete was commited
beforeSaveReference: emitted before the referrences of the current model are saved
aftereSaveReferences: emitted after the references of the current model were saved, before the changes are commited
beforeSaveMappings: emitted before the mappings of the current model are saved
aftereSaveMappings: emitted after the mappings of the current model were saved, before the changes are commited
beforeSaveBelongsTo: emitted before the belonging models of the current model are saved
aftereSaveBelongsTo: emitted after the belonging models of the current model were saved, before the changes are commited
FAQs
ORM for postgres and mysql. Loads and saves referenced entites, executes complex queries, supports joins, transactions, complex database clusters, connection pooling and much more. No conventions. MIT Licence
The npm package ee-orm receives a total of 6 weekly downloads. As such, ee-orm popularity was classified as not popular.
We found that ee-orm demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.