Class

BaseRepository

BaseRepository()

Constructor

# new BaseRepository()

Base repository class providing data access patterns for all domain repositories.

Handles the translation between database rows (via Objection.js) and immutable Entity instances. All domain repositories (IconRepository, UserRepository, etc.) extend this class and inherit these CRUD operations.

Responsibilities:

  • Execute database queries via Objection.js models
  • Convert query results to Entity instances
  • Enforce immutability (freeze entities)
  • Support transactions
  • Provide consistent CRUD interface

Does NOT:

  • Contain business logic (use Services)
  • Handle caching (use Services with CacheableService mixin)
  • Emit events (use Services)
  • Enforce access control (use Services with AccessControl)

View Source src/common/BaseRepository.js, line 86

Examples
// Define domain repository
class IconRepository extends BaseRepository {
  constructor(opts = {}) {
    super({
      modelName: 'IconModel',
      entityClass: IconEntity,
      hooks: {
        afterFind: async (icon) => {
          // Post-process icon if needed
          return icon;
        }
      },
      ...opts
    });
  }

  // Custom query
  async findActiveBySetId(setId) {
    const rows = await this.model.query()
      .where({ set_id: setId, is_active: true })
      .orderBy('name');
    return this.wrapEntity(rows, this.entityClass);
  }
}
// Use in service
const repository = new IconRepository();
const icon = await repository.findById(123);
console.log(icon instanceof IconEntity); // true
console.log(Object.isFrozen(icon)); // true

Methods

# async applyHook(name, value) → {Promise.<(Object|Array)>}

Applies a hook to the given value

Parameters:
Name Type Description
name String

The name of the hook to apply

value Object | Array

The value to apply the hook to

View Source src/common/BaseRepository.js, line 212

  • The value after applying the hook
Promise.<(Object|Array)>

# async count()

Counts the number of records that match the given criteria

View Source src/common/BaseRepository.js, line 476

# async create()

Creates a new record

View Source src/common/BaseRepository.js, line 384

# async createMany()

Creates multiple records

View Source src/common/BaseRepository.js, line 393

# async cursorPage()

Cursor-based pagination (stub).

View Source src/common/BaseRepository.js, line 377

# async delete()

Deletes a record by its ID

View Source src/common/BaseRepository.js, line 454

# async deleteWhere()

Deletes records that match the given criteria

View Source src/common/BaseRepository.js, line 461

# async exists()

Checks if a record exists that matches the given criteria

View Source src/common/BaseRepository.js, line 468

# async findAll()

Finds all records that match the given criteria

View Source src/common/BaseRepository.js, line 313

# async findById()

Finds a record by its ID

View Source src/common/BaseRepository.js, line 295

# async findByIds()

Finds records by their IDs

View Source src/common/BaseRepository.js, line 326

# async findOne()

Finds a record matching a where clause

View Source src/common/BaseRepository.js, line 304

# async findOneWithRelations()

Finds a single record with related data (no afterFind hook to avoid relation mutations)

View Source src/common/BaseRepository.js, line 502

# async paginate(whereopt, pageopt, pageSizeopt, optionsopt) → {Promise.<Object>}

Paginate query results with offset-based pagination.

Returns paginated results with metadata (total count, page info). Uses Objection's .page() method which efficiently counts total rows and fetches the requested page.

Note: Offset pagination doesn't scale well beyond ~100K rows. For large datasets, consider cursor-based pagination (currently not implemented).

Parameters:
Name Type Attributes Default Description
where Object <optional>
{}

WHERE clause conditions

page number <optional>
1

Page number (1-indexed)

pageSize number <optional>
10

Items per page

options Object <optional>
{}

Query options

entityClass function <optional>

Entity class override

entityOptions Object <optional>

Entity constructor options

trx Object <optional>

Knex transaction object

View Source src/common/BaseRepository.js, line 365

Pagination result:

  • results: Array of Entity instances
  • total: Total row count
  • page: Current page (1-indexed)
  • pageSize: Items per page
  • totalPages: Total page count
Promise.<Object>
Example
const result = await iconRepo.paginate(
  { is_active: true },
  1,  // page
  20  // pageSize
);
console.log(result.results.length); // 20
console.log(result.total); // 150000
console.log(result.totalPages); // 7500

# query()

Returns a query builder for the model

View Source src/common/BaseRepository.js, line 519

# raw()

Executes a raw SQL query

View Source src/common/BaseRepository.js, line 526

# async update()

Updates a record by its ID NOTE: mirrors your existing behavior (returns patch result wrapped).

View Source src/common/BaseRepository.js, line 438

# async updateWhere()

Updates records that match the given criteria

View Source src/common/BaseRepository.js, line 447

# async upsert()

Upserts a record (insert or update)

View Source src/common/BaseRepository.js, line 400

# async withRelations()

Finds records with related data (no afterList hook to avoid relation mutations)

View Source src/common/BaseRepository.js, line 484

# wrapEntity(result, entityClass, entityOptionsopt) → {Object|Array.<Object>}

Convert database rows to Entity instances.

This is the core method that transforms plain database objects (from Objection.js) into immutable, frozen Entity instances. Handles both single objects and arrays.

Entity Wrapping Process:

  1. Convert Objection model instance to plain object (via toJSON if available)
  2. Pass to Entity constructor
  3. Entity filters hidden fields, materializes relations
  4. Returns frozen, immutable Entity instance
Parameters:
Name Type Attributes Default Description
result Object | Array.<Object>

Database row(s) from Objection query

entityClass function

Entity class to instantiate (e.g., IconEntity)

entityOptions Object <optional>
{}

Options passed to Entity constructor

includeHiddenFields boolean <optional>

Include hidden fields

View Source src/common/BaseRepository.js, line 274

Entity instance(s)

Object | Array.<Object>
Examples
// Single entity
const row = await IconModel.query().findById(1);
const icon = this.wrapEntity(row, IconEntity);
console.log(icon instanceof IconEntity); // true
// Array of entities
const rows = await IconModel.query().where({ is_active: true });
const icons = this.wrapEntity(rows, IconEntity);
console.log(icons[0] instanceof IconEntity); // true

BaseRepository(options)

Constructor

# new BaseRepository(options)

Construct repository with model and entity bindings.

Parameters:
Name Type Attributes Default Description
options Object

Repository configuration

DB Object <optional>

Database instance (default: require('@vectoricons.net/db'))

modelName string

Name of Objection model in DB instance (e.g., 'IconModel')

entityClass function

Entity class to wrap results (e.g., IconEntity)

hooks Object <optional>
{}

Lifecycle hooks (afterFind, afterList)

hooks.afterFind function <optional>

Called after findById/findOne

hooks.afterList function <optional>

Called after findAll/paginate

freezeEntities boolean <optional>
true

Whether to freeze returned entities

deepFreezeEntities boolean <optional>
true

Whether to deep-freeze (recursive)

View Source src/common/BaseRepository.js, line 172

If DB instance is missing

Error

If modelName is missing

Error

If model doesn't exist in DB instance

Error

If entityClass is missing

Error
Example
const repo = new IconRepository({
  modelName: 'IconModel',
  entityClass: IconEntity,
  hooks: {
    afterList: async (icons) => {
      console.log(`Loaded ${icons.length} icons`);
      return icons;
    }
  }
});

Methods

# async applyHook(name, value) → {Promise.<(Object|Array)>}

Applies a hook to the given value

Parameters:
Name Type Description
name String

The name of the hook to apply

value Object | Array

The value to apply the hook to

View Source src/common/BaseRepository.js, line 212

  • The value after applying the hook
Promise.<(Object|Array)>

# async count()

Counts the number of records that match the given criteria

View Source src/common/BaseRepository.js, line 476

# async create()

Creates a new record

View Source src/common/BaseRepository.js, line 384

# async createMany()

Creates multiple records

View Source src/common/BaseRepository.js, line 393

# async cursorPage()

Cursor-based pagination (stub).

View Source src/common/BaseRepository.js, line 377

# async delete()

Deletes a record by its ID

View Source src/common/BaseRepository.js, line 454

# async deleteWhere()

Deletes records that match the given criteria

View Source src/common/BaseRepository.js, line 461

# async exists()

Checks if a record exists that matches the given criteria

View Source src/common/BaseRepository.js, line 468

# async findAll()

Finds all records that match the given criteria

View Source src/common/BaseRepository.js, line 313

# async findById()

Finds a record by its ID

View Source src/common/BaseRepository.js, line 295

# async findByIds()

Finds records by their IDs

View Source src/common/BaseRepository.js, line 326

# async findOne()

Finds a record matching a where clause

View Source src/common/BaseRepository.js, line 304

# async findOneWithRelations()

Finds a single record with related data (no afterFind hook to avoid relation mutations)

View Source src/common/BaseRepository.js, line 502

# async paginate(whereopt, pageopt, pageSizeopt, optionsopt) → {Promise.<Object>}

Paginate query results with offset-based pagination.

Returns paginated results with metadata (total count, page info). Uses Objection's .page() method which efficiently counts total rows and fetches the requested page.

Note: Offset pagination doesn't scale well beyond ~100K rows. For large datasets, consider cursor-based pagination (currently not implemented).

Parameters:
Name Type Attributes Default Description
where Object <optional>
{}

WHERE clause conditions

page number <optional>
1

Page number (1-indexed)

pageSize number <optional>
10

Items per page

options Object <optional>
{}

Query options

entityClass function <optional>

Entity class override

entityOptions Object <optional>

Entity constructor options

trx Object <optional>

Knex transaction object

View Source src/common/BaseRepository.js, line 365

Pagination result:

  • results: Array of Entity instances
  • total: Total row count
  • page: Current page (1-indexed)
  • pageSize: Items per page
  • totalPages: Total page count
Promise.<Object>
Example
const result = await iconRepo.paginate(
  { is_active: true },
  1,  // page
  20  // pageSize
);
console.log(result.results.length); // 20
console.log(result.total); // 150000
console.log(result.totalPages); // 7500

# query()

Returns a query builder for the model

View Source src/common/BaseRepository.js, line 519

# raw()

Executes a raw SQL query

View Source src/common/BaseRepository.js, line 526

# async update()

Updates a record by its ID NOTE: mirrors your existing behavior (returns patch result wrapped).

View Source src/common/BaseRepository.js, line 438

# async updateWhere()

Updates records that match the given criteria

View Source src/common/BaseRepository.js, line 447

# async upsert()

Upserts a record (insert or update)

View Source src/common/BaseRepository.js, line 400

# async withRelations()

Finds records with related data (no afterList hook to avoid relation mutations)

View Source src/common/BaseRepository.js, line 484

# wrapEntity(result, entityClass, entityOptionsopt) → {Object|Array.<Object>}

Convert database rows to Entity instances.

This is the core method that transforms plain database objects (from Objection.js) into immutable, frozen Entity instances. Handles both single objects and arrays.

Entity Wrapping Process:

  1. Convert Objection model instance to plain object (via toJSON if available)
  2. Pass to Entity constructor
  3. Entity filters hidden fields, materializes relations
  4. Returns frozen, immutable Entity instance
Parameters:
Name Type Attributes Default Description
result Object | Array.<Object>

Database row(s) from Objection query

entityClass function

Entity class to instantiate (e.g., IconEntity)

entityOptions Object <optional>
{}

Options passed to Entity constructor

includeHiddenFields boolean <optional>

Include hidden fields

View Source src/common/BaseRepository.js, line 274

Entity instance(s)

Object | Array.<Object>
Examples
// Single entity
const row = await IconModel.query().findById(1);
const icon = this.wrapEntity(row, IconEntity);
console.log(icon instanceof IconEntity); // true
// Array of entities
const rows = await IconModel.query().where({ is_active: true });
const icons = this.wrapEntity(rows, IconEntity);
console.log(icons[0] instanceof IconEntity); // true