11/* eslint-disable @typescript-eslint/no-empty-function */
2+ import { BinaryToTextEncoding , createHash , Hash } from 'crypto' ;
3+ import { IdempotencyRecordStatus } from '../types/IdempotencyRecordStatus' ;
4+ import { EnvironmentVariablesService } from '../EnvironmentVariablesService' ;
25import { IdempotencyRecord } from './IdempotencyRecord' ;
36import { PersistenceLayerInterface } from './PersistenceLayerInterface' ;
47
58abstract class PersistenceLayer implements PersistenceLayerInterface {
6- public constructor ( ) { }
7- public configure ( _functionName : string = '' ) : void { }
8- public async deleteRecord ( ) : Promise < void > { }
9- public async getRecord ( ) : Promise < IdempotencyRecord > {
10- return Promise . resolve ( { } as IdempotencyRecord ) ;
9+
10+ // envVarsService is always initialized in the constructor
11+ private envVarsService ! : EnvironmentVariablesService ;
12+
13+ private expiresAfterSeconds : number ;
14+
15+ private functionName : string = '' ;
16+
17+ private hashDigest : BinaryToTextEncoding ;
18+
19+ private hashFunction : string ;
20+
21+ public constructor ( ) {
22+ this . setEnvVarsService ( ) ;
23+ this . expiresAfterSeconds = 60 * 60 ; //one hour is the default expiration
24+ this . hashFunction = 'md5' ;
25+ this . hashDigest = 'base64' ;
26+
27+ }
28+ public configure ( functionName : string = '' ) : void {
29+ this . functionName = this . getEnvVarsService ( ) . getLambdaFunctionName ( ) + '.' + functionName ;
30+ }
31+
32+ /**
33+ * Deletes a record from the persistence store for the persistence key generated from the data passed in.
34+ *
35+ * @param data - the data payload that will be hashed to create the hash portion of the idempotency key
36+ */
37+ public async deleteRecord ( data : unknown ) : Promise < void > {
38+ const idempotencyRecord : IdempotencyRecord =
39+ new IdempotencyRecord ( this . getHashedIdempotencyKey ( data ) ,
40+ IdempotencyRecordStatus . EXPIRED ,
41+ undefined ,
42+ undefined ,
43+ undefined ,
44+ undefined
45+ ) ;
46+
47+ this . _deleteRecord ( idempotencyRecord ) ;
48+ }
49+ /**
50+ * Retrieves idempotency key for the provided data and fetches data for that key from the persistence store
51+ *
52+ * @param data - the data payload that will be hashed to create the hash portion of the idempotency key
53+ */
54+ public async getRecord ( data : unknown ) : Promise < IdempotencyRecord > {
55+ const idempotencyKey : string = this . getHashedIdempotencyKey ( data ) ;
56+
57+ return this . _getRecord ( idempotencyKey ) ;
58+ }
59+
60+ /**
61+ * Saves a record indicating that the function's execution is currently in progress
62+ *
63+ * @param data - the data payload that will be hashed to create the hash portion of the idempotency key
64+ */
65+ public async saveInProgress ( data : unknown ) : Promise < void > {
66+ const idempotencyRecord : IdempotencyRecord =
67+ new IdempotencyRecord ( this . getHashedIdempotencyKey ( data ) ,
68+ IdempotencyRecordStatus . INPROGRESS ,
69+ this . getExpiryTimestamp ( ) ,
70+ undefined ,
71+ undefined ,
72+ undefined
73+ ) ;
74+
75+ return this . _putRecord ( idempotencyRecord ) ;
76+ }
77+
78+ /**
79+ * Saves a record of the function completing successfully. This will create a record with a COMPLETED status
80+ * and will save the result of the completed function in the idempotency record.
81+ *
82+ * @param data - the data payload that will be hashed to create the hash portion of the idempotency key
83+ * @param result - the result of the successfully completed function
84+ */
85+ public async saveSuccess ( data : unknown , result : Record < string , unknown > ) : Promise < void > {
86+ const idempotencyRecord : IdempotencyRecord =
87+ new IdempotencyRecord ( this . getHashedIdempotencyKey ( data ) ,
88+ IdempotencyRecordStatus . COMPLETED ,
89+ this . getExpiryTimestamp ( ) ,
90+ undefined ,
91+ result ,
92+ undefined
93+ ) ;
94+
95+ this . _updateRecord ( idempotencyRecord ) ;
1196 }
12- public async saveInProgress ( ) : Promise < void > { }
13- public async saveSuccess ( ) : Promise < void > { }
1497
1598 protected abstract _deleteRecord ( record : IdempotencyRecord ) : Promise < void > ;
1699 protected abstract _getRecord ( idempotencyKey : string ) : Promise < IdempotencyRecord > ;
17100 protected abstract _putRecord ( record : IdempotencyRecord ) : Promise < void > ;
18101 protected abstract _updateRecord ( record : IdempotencyRecord ) : Promise < void > ;
102+
103+ /**
104+ * Generates a hash of the data and returns the digest of that hash
105+ *
106+ * @param data the data payload that will generate the hash
107+ * @returns the digest of the generated hash
108+ */
109+ private generateHash ( data : string ) : string {
110+ const hash : Hash = createHash ( this . hashFunction ) ;
111+ hash . update ( data ) ;
112+
113+ return hash . digest ( this . hashDigest ) ;
114+ }
115+
116+ /**
117+ * Getter for `envVarsService`.
118+ * Used internally during initialization.
119+ */
120+ private getEnvVarsService ( ) : EnvironmentVariablesService {
121+ return this . envVarsService ;
122+ }
123+
124+ /**
125+ * Creates the expiry timestamp for the idempotency record
126+ *
127+ * @returns the expiry time for the record expressed as number of seconds past the UNIX epoch
128+ */
129+ private getExpiryTimestamp ( ) : number {
130+ const currentTime : number = Date . now ( ) / 1000 ;
131+
132+ return currentTime + this . expiresAfterSeconds ;
133+ }
134+
135+ /**
136+ * Generates the idempotency key used to identify records in the persistence store.
137+ *
138+ * @param data the data payload that will be hashed to create the hash portion of the idempotency key
139+ * @returns the idempotency key
140+ */
141+ private getHashedIdempotencyKey ( data : unknown ) : string {
142+ if ( ! data ) {
143+ console . warn ( 'No data found for idempotency key' ) ;
144+ }
145+
146+ return this . functionName + '#' + this . generateHash ( JSON . stringify ( data ) ) ;
147+ }
148+
149+ /**
150+ * Setter and initializer for `envVarsService`.
151+ * Used internally during initialization.
152+ */
153+ private setEnvVarsService ( ) : void {
154+ this . envVarsService = new EnvironmentVariablesService ( ) ;
155+ }
156+
19157}
20158
21159export {
22- IdempotencyRecord ,
23160 PersistenceLayer
24161} ;
0 commit comments