As you may know, I’ve been working on my first NPM package which is simply a SQL Builder and converts the method calls into a SQL string (specifically MySQL at present, but that should include others in the future). The reason I’ve been working on this, is partly to improve my NodeJs skills, and partly because of an idea I’ve been having for a ORM that is hopefully as easy to use as Active Record but has more of a Data Mapper design.

Active Record Vs Data Mapper ORMs

I’m not going to get into it too much, but my understanding is that active record quite simply allows:

  1. A 1 to 1 relationship between a models attributes and database columns.
  2. A save() method that persists the object to the storage layer.
  3. The model is aware of the data layer.

And Data Mapper allows:

  1. Objects to just handle business logic. No knowledge of the data layer.
  2. And uses an entity manager to persist the objects to the storage layer.
  3. Model attributes can be anything, as they can be mapped differently to the data layer columns.

The biggest difference most people will recognise is this:

A New Approach

As I have already talked about, the fact we can share code on the server and browser with NodeJs simply adds one more benefit to the DataMapper pattern, and I’m surprised I haven’t seen more mapper packages out there, this I believe is down to Active Records simplicity. But the DataMapper pattern doesn’t have to be that complicated:

The above example isn’t your “traditional” Data Mapper with its verbose method calls like, persist(), flush(), etc. And it has one simple method that I haven’t seen used before which would help so many people believe it’s not that complicated: create(). By simply adding this method we don’t have to scare people off with the idea “oh you have to manage multiple classes, etc”. We can let the mapper give you back an empty instance of the model, or just create a new one with the model directly. By adding the create method we can optionally not require the model class anywhere we need and just import the mapper.

The “Mapper” in a traditional sense doesn’t need to know what the entity is its being given, it can work out what it is and where it has to go based on configuration. But what if we turned an all-seeing “Mapper” into a per Entity Type Mapper, then rename it “Repository”. Strangely most people using Active Record also abstract them behind Repositories as well, which is a little ironic as you then pretty much lose the Active Record advantage of simplicity anyway.

Each “Repository” (Mapper) gets given its model at bootstrap, it can hand out new ones, ones from the db, and save any passed back to it. Whats more we can have the Data Mapper advantages of being able to map model attributes to different attributes in the persistence layer, but assume a 1 to 1 map. This idea could look like this:

The only difference here from Active Record is:

  1. We create a Model and a Repository.
  2. When we want a new Model, or fetch a Model, we call UserRepository.{method}(); instead of User.{method}();
  3. Saving a Model changes from; to;

With this example the core thinking of Active Record barely changes, but we do still have Data Mapper based functionality and flexibility.

It’s just an idea for now, but I think simply changing the idea of an “Entity Manager” into a per Model “Repository” should help many get over the idea Data Mappers are complex.

Its quite funny thinking about it. Data Mappers are touted as complex due to how they work, yet they are designed to follow SOLID principles (which should make them easier), but in my opinion having 1 object responsible for saving every type of object to the database goes against SOLID principles and is the reason people shy away from the pattern. If we take the idea further and make a Mapper for every model, each mapper really does have 1 responsibility, saving its intended model.

My next NPM package should expand on this idea and utilize the SQL Mason query builder we having been working on (by the way its in alpha now and useable) to create a simple yet powerful ORM with models available to both the server and the browser.