Skip to content

defineRepository()

The defineRepository() method is used to create a composable that serves as a repository for given model.

Create repository

Creating a model repository is similar to creating a Pinia store.

typescript
const useModelRepository = defineRepository(Model);

For example:

typescript
import { Model, defineRepository } from '@kovalson/prevue';

class User extends Model {
  // ...
}

const useUserRepository = defineRepository(User);

export {
  User,
  useUserRepository,
};

Setup

You may pass a setup object as a second parameter to configure the composable.

typescript
import { Model, defineRepository } from '@kovalson/prevue';

class User extends Model {
  public active: boolean = false;
  // ...
}

const useUserRepository = defineRepository(User, {
  local: true,
  methods: {
    active() {
      return this
        .all()
        .filter((user: User) => user.active);
    },
  },
});

export {
  User,
  useUserRepository,
};

Setup Object

typescript
interface ISetupObject {
  /**
   * Whether the repository is local or global.
   * 
   * Local repository uses a ref to store data. The data is therefore cleared whenever the component using it is
   * destroyed.
   * Global repository uses a Pinia store, so the data persists when navigating through the app, even when the component
   * using it is destroyed. There can only be one global repository for a model.
   * 
   * @default false
   *  By default, all repositories are global.
   */
  local?: boolean;

  /**
   * Custom methods that enhance the repository functionality.
   * 
   * @default undefined
   */
  methods?: Record<string, TCustomMethod>;
}

Custom Methods

Custom methods are functions that are automatically bound a special context. This context provides them with all other methods (including other custom created methods).

You may, or may not make use of custom method context. Your method can return anything you like, but bear in mind that the repository should serve as a single source of truth in terms of the local model BREAD management and ideally should reflect the server's state of given model.

For example:

typescript
const useUserRepository = defineRepository(User, {
  local: true,
  methods: {
    active(): User[] {
      return this
        .all()
        .filter((user: User) => user.active);
    },
    activate(id: string, active: boolean): void {
      this.update(id, {
        active: active,
      });
    }
  },
});

Items Map

The custom method context also provides the items property. This property stores a map of all items in that repository. The keys are models' ids, and the values are models' objects:

typescript
const useUserRepository = defineRepository(User, {
  local: true,
  methods: {
    active(): User[] {
      return this.items
        .values()
        .filter((user: User) => user.active);
    },
  },
});

Default Methods

The created repository composable has several BREAD methods out-of-the-box.

typescript
interface IBaseMethods<M extends Model> {
  isEmpty(): boolean;
  isNotEmpty(): boolean;
  count(): number;
  clear(): void;
  set(items: M[]): void;
  add(items: M[] | M): void;
  all(): M[];
  find(id: string): M | null;
  first(): M | null;
  last(): M | null;
  update(item: M, data?: Partial<M>): void;
  update(item: string, data: Partial<M>): void;
  remove(items: (M | string)[] | M | string): void;
  toArray(): M[];
  getWatchable(): Readonly<Ref<ReadonlyMap<string, DeepReadonly<M>>>>;
}

Released under the MIT License.