Skip to content

Commit b01b842

Browse files
committed
docs(repository): added getting started with repository docs
1 parent 8adf133 commit b01b842

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
layout: post
3+
title: Build a business layer with a Repository 📦
4+
author: [gallayl]
5+
tags: ['Getting Started', 'repository']
6+
image: img/005-getting-started-with-repository-cover.jpg
7+
date: '2021-06-23T10:58:20.257Z'
8+
draft: false
9+
excerpt: A Repository is the next layer above the data stores. When setting up a repository, you can create DataSets that can rely on a previously configured physical store. The difference is that while PhysicalStore focuses on the data, DataSet focuses on business logic. You can authorize, check permissions, subscribe to entity changes, etc...
10+
---
11+
12+
### Disclaimer
13+
14+
15+
> If you are using a repository, use the repository all the time. - Anonymous
16+
17+
As callbacks, authorization and data manipulation works through the Repository layer, you should always use Repository if you have dependant business logic through it.
18+
19+
### Simplifying a complex idea
20+
21+
Let's say you have an entity type. You have to be notified each and every time somebody creates a new instance.
22+
You also have to take care about that new entities should have some validation.
23+
24+
```ts
25+
class MyEntity {
26+
public key!: number
27+
public value!: string
28+
}
29+
30+
const myInjector = new Injector()
31+
.setupStores((sm) => sm.addStore(new InMemoryStore({ model: MyEntity, primaryKey: 'key' })))
32+
.setupRepository((repo) =>
33+
repo.createDataSet(MyEntity, 'key', {
34+
authorizeAdd: async ({ entity }) => {
35+
if (entity.value && entity.value.length > 2)
36+
return {
37+
isAllowed: true,
38+
}
39+
return {
40+
isAllowed: false,
41+
message: `Failed to create entity. The value length should be greater than 2 but was ${
42+
entity.value?.length
43+
}. Entity: ${JSON.stringify(entity)}`,
44+
}
45+
},
46+
}),
47+
)
48+
49+
const dataSet = myInjector.getDataSetFor(MyEntity, 'key')
50+
51+
dataSet.onEntityAdded.subscribe(({ entity }) => {
52+
console.log('Hey, a new entity has been added', entity)
53+
})
54+
55+
dataSet.add(myInjector, { key: 1, value: 'a' }) // Will fail
56+
dataSet.add(myInjector, { key: 1, value: 'asd' }) // Will pass and will be logged to the console
57+
58+
```
59+
60+
### Event subscriptions
61+
62+
You can subscribe to the following events in your Repository:
63+
- `onEntityAdded` will notify you when a new entity has been created
64+
- `onEntityUpdated` will fire on updates
65+
- `onEntityRemoved` will notify about the deletions
66+
67+
### Authorizing operations
68+
69+
You can define authorization / validation during you create the DataSet. These callbacks are the followings:
70+
- `authorizeAdd` will verify entities before adding / inserting them into the stores
71+
- `authorizeGet` / `authorizeGetEntity` will check that you can get that single entity (also `authorizeGetEntity` won't check collections)
72+
- `authorizeUpdate` / `authorizeUpdateEntity` will verify before update. `authorizeUpdate` won't load the entity from the Store (you won't have as a parameter) while `authorizeUpdateEntity` does
73+
- `authorizeRemove` / `authorizeRemoveEntity` will fire before remove. Again, `authorizeRemoveEntity` loads the whole entity from the store before deleting it.
74+
- with `addFilter`, you can append conditions to your filter expressions to narrow collection queries and optimize performance
75+
76+
### Manipulating Data
77+
78+
There are also two callbacks that allows you to modify data: with `modifyOnAdd` and `modifyOnUpdate`, you can update data in some fields like e.g. `createdByUser` or `lastModificationDate`
79+
80+
### Getting the Context
81+
82+
All methods above has an _injector_ instance on the call parameter - you can use that injector to get service instances from the right caller context. It means that you can e.g.: get the current user in the following way.
83+
84+
```ts
85+
authorizeAdd: async ({ injector }) => {
86+
const currentUser = await injector.getCurrentUser()
87+
if (currentUser.roles.find((role) => role === 'CanAddMyEntity'))
88+
return {
89+
isAllowed: true,
90+
}
91+
return {
92+
isAllowed: false,
93+
message: "The user doesn't have the role 'CanAddMyEntity'",
94+
}
95+
},
96+
```
458 KB
Loading

0 commit comments

Comments
 (0)