0

I have some troubles to chose my repository pattern for my API. The database is composed of several tables that can be grouped in two "parts".

Have I to do one repository for each table (first example) or only one for each "parts" (second example) ? Another thing to notice is that later (in some month, when the version 1 of the API will works), the API will has to manage an additional (NoSQL) database Both at the same time, not instead of the first one (Examples use pg-promise)

First example

first.js : manage only the table 'first'

'use strict';
class FirstRepository {
  constructor(/*parameters*/) { /* hidden for brevity */ }

  makeInsertQuery(params) {
    return this.pgp.helpers.insert(params, this.Collections.insert);
    // return query like `INSERT INTO first...`
  }

  // t.* = *Repository (FirstRepository, secondRepository, ...)
  insertOne(params) {
    return this.Database.tx('MyTag', async t => {
      let result = {};

      const query = t.first.makeInsertQuery(params) + " RETURNING *";
      result.first = await t.one(query);
      result.second = await t.second.insertOne(params);
      result.third = await t.third.insert(params);
      // some other call like that

      /**
       * LATER = INSERT IN THE OTHER DATABASE
       */

      return result;
    })
    .catch(ex => {
      throw ex;
    });
  }

  /* some other function, hidden for brevity */
}

module.exports = FirstRepository

second.js : manage only the table 'second'

'use strict';
class SecondsRepository {
  constructor(/*parameters*/) { /* hidden for brevity */ }

  makeInsertQuery(params) {
    return this.pgp.helpers.insert(params, this.Collections.insert);
    // return query like `INSERT INTO second...`
  }

  insertOne(params) {
    let second = /* some stuf, hidden for brevity */;
    
    var query = this.makeInsertQuery(second);
    return this.Database.one(query)
            .then(data => { return data; })
            .catch(ex => { throw ex; });
  }

  /* some other function, hidden for brevity */
}

module.exports = SecondsRepository

Second example

// repo1.js
'use strict';
/* FirstPartRepository manage several tables : 'first', 'second' and 'third' */
class FirstPartRepository {
  constructor(/*parameters*/) { /* hidden for brevity */ }

  makeInsertQuery(params, entity) {
    let obj = /* extract it from params */
    return this.pgp.helpers.insert(params, this.Collections[entity].insert);
    // return query like `INSERT INTO ${entity}...`
  }

  // In this example, FirstPartRepository manage some table : 'first', 'second' and 'third'
  insertOne(params) {
    return this.Database.tx('MyTag', async t => {
      let result = {};

      const insertFirst  = t.firstpart.makeInsertQuery(params, 'first')  + " RETURNING *",
            insertSecond = t.firstpart.makeInsertQuery(params, 'second') + " RETURNING *",
            insertThird  = t.firstpart.makeInsertQuery(params, 'third')  + " RETURNING *";

      result.first  = await t.one(insertFirst);
      result.second = await t.one(insertSecond);
      result.third  = await t.one(insertThird);
      // some other like that

      /**
       * LATER = INSERT IN THE OTHER DATABASE
       */

      return result;
    })
    .catch(ex => {
      throw ex;
    });
  }

  /* some other function, hidden for brevity */
}

module.exports = FirstPartRepository
Community
  • 1
  • 1
Firlfire
  • 413
  • 1
  • 6
  • 14

1 Answers1

3

Pattern Repository = set of operations on a single entity.

In your case, each repository is a class that represents all operations on a single table.

When implementing a complex, multi-entity business logic, you can implement it in one of three ways:

  • You can have the key repository implement high-level business methods
  • You can create an extra high-level repository to keep high-level logic separate
  • You can implement it outside of the repository pattern, like in an external function.

Which one to choose - depends on the app requirements and its business logic.

vitaly-t
  • 24,279
  • 15
  • 116
  • 138