@@ -11,7 +11,21 @@ import client from './client';
11
11
12
12
const APP_METADATA_KEY_PREFIX = 'webUI_' ;
13
13
14
- const getMetadataKey = ( key : string ) => `${ APP_METADATA_KEY_PREFIX } ${ key } ` ;
14
+ const migrations : IMetadataMigration [ ] = [
15
+ {
16
+ keys : [
17
+ { oldKey : 'loadNextonEnding' , newKey : 'loadNextOnEnding' } ,
18
+ ] ,
19
+ } ,
20
+ ] ;
21
+
22
+ const getMetadataKey = ( key : string , appPrefix : string = APP_METADATA_KEY_PREFIX ) => `${ appPrefix } ${ key } ` ;
23
+
24
+ const doesMetadataKeyExistIn = (
25
+ meta : IMetadata | undefined ,
26
+ key : string ,
27
+ appPrefix ?: string ,
28
+ ) : boolean => Object . prototype . hasOwnProperty . call ( meta ?? { } , getMetadataKey ( key , appPrefix ) ) ;
15
29
16
30
const convertValueFromMetadata = <
17
31
T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes ,
@@ -33,31 +47,121 @@ const convertValueFromMetadata = <
33
47
return value as T ;
34
48
} ;
35
49
50
+ const getAppMetadataFrom = (
51
+ meta : IMetadata ,
52
+ appPrefix : string = APP_METADATA_KEY_PREFIX ,
53
+ ) : IMetadata => {
54
+ const appMetadata : IMetadata = { } ;
55
+
56
+ Object . entries ( meta ) . forEach ( ( [ key , value ] ) => {
57
+ if ( key . startsWith ( appPrefix ) ) {
58
+ appMetadata [ key ] = value ;
59
+ }
60
+ } ) ;
61
+
62
+ return appMetadata ;
63
+ } ;
64
+
65
+ const applyAppKeyPrefixMigration = ( meta : IMetadata , migration : IMetadataMigration ) : IMetadata => {
66
+ const migratedMetadata : IMetadata = { ...meta } ;
67
+
68
+ if ( ! migration . appKeyPrefix ) {
69
+ return migratedMetadata ;
70
+ }
71
+
72
+ const { oldPrefix, newPrefix } = migration . appKeyPrefix ;
73
+
74
+ const oldAppMetadata = getAppMetadataFrom ( meta , oldPrefix ) ;
75
+ const newAppMetadata = getAppMetadataFrom ( meta , newPrefix ) ;
76
+
77
+ const missingMetadataKeys = Object . keys ( oldAppMetadata )
78
+ . filter ( ( key ) => ! Object . keys ( newAppMetadata ) . includes ( key ) ) ;
79
+
80
+ const isMissingOldMetadata = missingMetadataKeys . length ;
81
+ if ( isMissingOldMetadata ) {
82
+ missingMetadataKeys . forEach ( ( oldKey ) => {
83
+ const keyWithNewPrefix = oldKey . replace ( oldPrefix , newPrefix ) ;
84
+ migratedMetadata [ keyWithNewPrefix ] = oldAppMetadata [ oldKey ] ;
85
+ } ) ;
86
+ }
87
+
88
+ return migratedMetadata ;
89
+ } ;
90
+
91
+ const applyMetadataKeyMigration = ( meta : IMetadata , migration : IMetadataMigration ) : IMetadata => {
92
+ const migratedMetadata : IMetadata = { ...meta } ;
93
+
94
+ if ( ! migration . keys ) {
95
+ return migratedMetadata ;
96
+ }
97
+
98
+ const metadataKeyChanges = migration . keys ;
99
+
100
+ metadataKeyChanges . forEach ( ( { oldKey, newKey } ) => {
101
+ if ( ! doesMetadataKeyExistIn ( meta , oldKey ) ) {
102
+ return ;
103
+ }
104
+
105
+ if ( doesMetadataKeyExistIn ( meta , newKey ) ) {
106
+ return ;
107
+ }
108
+
109
+ migratedMetadata [ getMetadataKey ( newKey ) ] = meta [ getMetadataKey ( oldKey ) ] ;
110
+ } ) ;
111
+
112
+ return migratedMetadata ;
113
+ } ;
114
+
115
+ const applyMetadataMigrations = ( meta ?: IMetadata ) : IMetadata | undefined => {
116
+ if ( ! meta ) {
117
+ return undefined ;
118
+ }
119
+
120
+ const migrationToMetadata : [ number , IMetadata ] [ ] = [ [ 0 , meta ] ] ;
121
+
122
+ migrations . forEach ( ( migration , index ) => {
123
+ const migrationId = index + 1 ;
124
+ const metadataToMigrate = migrationToMetadata [ migrationId - 1 ] [ 1 ] ;
125
+ const appKeyPrefixMigrated = applyAppKeyPrefixMigration ( metadataToMigrate , migration ) ;
126
+ const metadataKeysMigrated = applyMetadataKeyMigration ( appKeyPrefixMigrated , migration ) ;
127
+
128
+ migrationToMetadata . push ( [ migrationId , metadataKeysMigrated ] ) ;
129
+ } ) ;
130
+
131
+ const appliedMigration = migrationToMetadata . length > 1 ;
132
+ if ( ! appliedMigration ) {
133
+ return { ...meta } ;
134
+ }
135
+
136
+ return migrationToMetadata . pop ( ) ! [ 1 ] ;
137
+ } ;
138
+
36
139
export const getMetadataValueFrom = <
37
140
T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes ,
38
141
> (
39
142
{ meta } : IMetadataHolder ,
40
143
key : AppMetadataKeys ,
41
144
defaultValue ?: T ,
145
+ applyMigrations : boolean = true ,
42
146
) : T | undefined => {
43
- const metadataKey = getMetadataKey ( key ) ;
147
+ const metadata = applyMigrations ? applyMetadataMigrations ( meta ) : meta ;
44
148
45
- const isMissingKey = ! Object . prototype . hasOwnProperty . call ( meta ?? { } , metadataKey ) ;
46
- if ( meta === undefined || isMissingKey ) {
149
+ if ( metadata === undefined || ! doesMetadataKeyExistIn ( metadata , key ) ) {
47
150
return defaultValue ;
48
151
}
49
152
50
- return convertValueFromMetadata ( meta [ metadataKey ] ) ;
153
+ return convertValueFromMetadata ( metadata [ getMetadataKey ( key ) ] ) ;
51
154
} ;
52
155
53
156
export const getMetadataFrom = (
54
157
{ meta } : IMetadataHolder ,
55
158
keysToDefaultValues : MetadataKeyValuePair [ ] ,
159
+ applyMigrations ?: boolean ,
56
160
) : IMetadata < AllowedMetadataValueTypes > => {
57
161
const appMetadata : IMetadata < AllowedMetadataValueTypes > = { } ;
58
162
59
163
keysToDefaultValues . forEach ( ( [ key , defaultValue ] ) => {
60
- appMetadata [ key ] = getMetadataValueFrom ( { meta } , key , defaultValue ) ;
164
+ appMetadata [ key ] = getMetadataValueFrom ( { meta } , key , defaultValue , applyMigrations ) ;
61
165
} ) ;
62
166
63
167
return appMetadata ;
0 commit comments