@@ -2,14 +2,31 @@ import Dataloader from 'dataloader';
2
2
3
3
import { knex } from '../../../../db/knex-database-connection.js' ;
4
4
import { LearningContentCache } from '../caches/learning-content-cache.js' ;
5
+ import { child } from '../utils/logger.js' ;
5
6
7
+ const logger = child ( 'learningcontent:repository' , { event : 'learningcontent' } ) ;
8
+
9
+ /**
10
+ * @typedef {(knex: import('knex').QueryBuilder) => Promise<string[]|number[]> } QueryBuilderCallback
11
+ */
12
+
13
+ /**
14
+ * Datasource for learning content repositories.
15
+ * This datasource uses a {@link Dataloader} to load and cache entities.
16
+ */
6
17
export class LearningContentRepository {
7
18
#tableName;
8
19
#idType;
9
20
#dataloader;
10
21
#findCache;
11
22
#findCacheMiss;
12
23
24
+ /**
25
+ * @param {{
26
+ * tableName: string
27
+ * idType?: 'text' | 'integer'
28
+ * }} config
29
+ */
13
30
constructor ( { tableName, idType = 'text' } ) {
14
31
this . #tableName = tableName ;
15
32
this . #idType = idType ;
@@ -23,21 +40,15 @@ export class LearningContentRepository {
23
40
this . #findCacheMiss = new Map ( ) ;
24
41
}
25
42
43
+ /**
44
+ * Finds several entities using a request and caches results.
45
+ * The request is built using a knex query builder given to {@link callback}.
46
+ * {@link cacheKey} must vary according to params given to the query builder.
47
+ * @param {string } cacheKey
48
+ * @param {QueryBuilderCallback } callback
49
+ * @returns {Promise<object[]> }
50
+ */
26
51
async find ( cacheKey , callback ) {
27
- return this . #findDtos( callback , cacheKey ) ;
28
- }
29
-
30
- async load ( id ) {
31
- if ( ! id ) return null ;
32
- return this . #dataloader. load ( id ) ;
33
- }
34
-
35
- async loadMany ( ids ) {
36
- const notNullIds = ids . filter ( ( id ) => id ) ;
37
- return this . #dataloader. loadMany ( notNullIds ) ;
38
- }
39
-
40
- #findDtos( callback , cacheKey ) {
41
52
let dtos = this . #findCache. get ( cacheKey ) ;
42
53
if ( dtos ) return dtos ;
43
54
@@ -52,14 +63,51 @@ export class LearningContentRepository {
52
63
return dtos ;
53
64
}
54
65
66
+ /**
67
+ * Loads one entity by ID.
68
+ * @param {string|number } id
69
+ * @returns {Promise<object> }
70
+ */
71
+ async load ( id ) {
72
+ if ( ! id ) return null ;
73
+ return this . #dataloader. load ( id ) ;
74
+ }
75
+
76
+ /**
77
+ * Loads several entities by ID.
78
+ * @param {string[]|number[] } ids
79
+ * @returns {Promise<object[]> }
80
+ */
81
+ async loadMany ( ids ) {
82
+ const notNullIds = ids . filter ( ( id ) => id ) ;
83
+ return this . #dataloader. loadMany ( notNullIds ) ;
84
+ }
85
+
86
+ /**
87
+ * Loads entities from database using a request and writes result to cache.
88
+ * @param {string } cacheKey
89
+ * @param {QueryBuilderCallback } callback
90
+ * @returns {Promise<object[]> }
91
+ */
55
92
async #loadDtos( callback , cacheKey ) {
56
93
const ids = await callback ( knex . pluck ( `${ this . #tableName} .id` ) . from ( this . #tableName) ) ;
57
94
const dtos = await this . #dataloader. loadMany ( ids ) ;
95
+
96
+ logger . debug ( { tableName : this . #tableName, cacheKey } , 'caching find result' ) ;
58
97
this . #findCache. set ( cacheKey , dtos ) ;
98
+
59
99
return dtos ;
60
100
}
61
101
102
+ /**
103
+ * Loads a batch of entities from database by ID.
104
+ * Entities are returned in the same order as {@link ids}.
105
+ * If an ID is not found, it is null in results.
106
+ * @param {string[]|number[] } ids
107
+ * @returns {Promise<(object|null)[]> }
108
+ */
62
109
async #batchLoad( ids ) {
110
+ logger . debug ( { tableName : this . #tableName, count : ids . length } , 'loading from PG' ) ;
63
111
const dtos = await knex
64
112
. select ( `${ this . #tableName} .*` )
65
113
. from ( knex . raw ( `unnest(?::${ this . #idType} []) with ordinality as ids(id, idx)` , [ ids ] ) ) // eslint-disable-line knex/avoid-injections
@@ -68,7 +116,15 @@ export class LearningContentRepository {
68
116
return dtos . map ( ( dto ) => ( dto . id ? dto : null ) ) ;
69
117
}
70
118
119
+ /**
120
+ * Clears repository’s cache.
121
+ * If {@link id} is undefined, all cache is cleared.
122
+ * If {@link id} is given, cache is partially cleared.
123
+ * @param {string|number|undefined } id
124
+ */
71
125
clearCache ( id ) {
126
+ logger . debug ( { tableName : this . #tableName, id } , 'trigerring cache clear' ) ;
127
+
72
128
if ( id ) {
73
129
this . #dataloader. clear ( id ) ;
74
130
} else {
0 commit comments