@@ -12,14 +12,19 @@ type SerializeContent<I> = (content: I) => string;
1212type DeserializeContent = ( content : string ) => unknown ;
1313type GetFileName = ( id : string ) => string ;
1414
15- export type UserDataOptions < Input > = {
15+ export type FileUserDataOptions < Input > = {
1616 subdir : string ;
1717 basePath ?: string ;
1818 serialize ?: SerializeContent < Input > ;
1919 deserialize ?: DeserializeContent ;
2020 getFileName ?: GetFileName ;
2121} ;
2222
23+ export type AtlasUserDataOptions < Input > = {
24+ serialize ?: SerializeContent < Input > ;
25+ deserialize ?: DeserializeContent ;
26+ } ;
27+
2328type ReadOptions = {
2429 ignoreErrors : boolean ;
2530} ;
@@ -63,28 +68,54 @@ export interface ReadAllWithStatsResult<T extends z.Schema> {
6368 errors : Error [ ] ;
6469}
6570
66- export class UserData < T extends z . Schema > {
71+ export abstract class IUserData < T extends z . Schema > {
72+ protected readonly validator : T ;
73+ protected readonly serialize : SerializeContent < z . input < T > > ;
74+ protected readonly deserialize : DeserializeContent ;
75+ protected static readonly semaphore = new Semaphore ( 100 ) ;
76+
77+ constructor (
78+ validator : T ,
79+ {
80+ serialize = ( content : z . input < T > ) => JSON . stringify ( content , null , 2 ) ,
81+ deserialize = JSON . parse ,
82+ } : {
83+ serialize ?: SerializeContent < z . input < T > > ;
84+ deserialize ?: DeserializeContent ;
85+ } = { }
86+ ) {
87+ this . validator = validator ;
88+ this . serialize = serialize ;
89+ this . deserialize = deserialize ;
90+ }
91+
92+ abstract write ( id : string , content : z . input < T > ) : Promise < boolean > ;
93+ abstract delete ( id : string ) : Promise < boolean > ;
94+ abstract readAll ( options ?: ReadOptions ) : Promise < ReadAllResult < T > > ;
95+ abstract updateAttributes (
96+ id : string ,
97+ data : Partial < z . input < T > >
98+ ) : Promise < z . output < T > > ;
99+ }
100+
101+ export class FileUserData < T extends z . Schema > extends IUserData < T > {
67102 private readonly subdir : string ;
68103 private readonly basePath ?: string ;
69- private readonly serialize : SerializeContent < z . input < T > > ;
70- private readonly deserialize : DeserializeContent ;
71104 private readonly getFileName : GetFileName ;
72- private readonly semaphore = new Semaphore ( 100 ) ;
73105
74106 constructor (
75- private readonly validator : T ,
107+ validator : T ,
76108 {
77109 subdir,
78110 basePath,
79111 serialize = ( content : z . input < T > ) => JSON . stringify ( content , null , 2 ) ,
80112 deserialize = JSON . parse ,
81113 getFileName = ( id ) => `${ id } .json` ,
82- } : UserDataOptions < z . input < T > >
114+ } : FileUserDataOptions < z . input < T > >
83115 ) {
116+ super ( validator , { serialize, deserialize } ) ;
84117 this . subdir = subdir ;
85118 this . basePath = basePath ;
86- this . deserialize = deserialize ;
87- this . serialize = serialize ;
88119 this . getFileName = getFileName ;
89120 }
90121
@@ -126,7 +157,7 @@ export class UserData<T extends z.Schema> {
126157 let handle : fs . FileHandle | undefined = undefined ;
127158 let release : ( ( ) => void ) | undefined = undefined ;
128159 try {
129- release = await this . semaphore . waitForRelease ( ) ;
160+ release = await IUserData . semaphore . waitForRelease ( ) ;
130161 handle = await fs . open ( absolutePath , 'r' ) ;
131162 [ stats , data ] = await Promise . all ( [
132163 handle . stat ( ) ,
@@ -290,4 +321,15 @@ export class UserData<T extends z.Schema> {
290321 ) {
291322 return ( await this . readOneWithStats ( id , options ) ) ?. [ 0 ] ;
292323 }
324+
325+ async updateAttributes (
326+ id : string ,
327+ data : Partial < z . input < T > >
328+ ) : Promise < z . output < T > > {
329+ await this . write ( id , {
330+ ...( ( await this . readOne ( id ) ) ?? { } ) ,
331+ ...data ,
332+ } ) ;
333+ return await this . readOne ( id ) ;
334+ }
293335}
0 commit comments