Skip to content

Commit 3b7c90a

Browse files
authored
fix: rtk helpers (#40)
* fix: rtk helpers * fix: type
1 parent dc3f8ce commit 3b7c90a

File tree

1 file changed

+172
-91
lines changed

1 file changed

+172
-91
lines changed

src/helpers/rtkQuery.ts

+172-91
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,37 @@
1+
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
2+
13
// -----------------------------------------------------------------------------
24
// Model Types
35
// -----------------------------------------------------------------------------
46

57
// The fields of a model.
68
export type Fields = Record<string, unknown>;
79

10+
export type TagId = string | number;
11+
12+
export type Tag<Type extends string> = {
13+
type: Type;
14+
id: TagId;
15+
};
16+
817
/**
918
* A data model.
10-
* ID: The type of ID.
11-
* ReadAndWrite: The fields that can both be read from and written to.
12-
* ReadOnly: The fields that can only be read from. 'id' is a mandatory
13-
* read-only field.
14-
* WriteOnly: The fields that can only be written to.
19+
* Id: The type of Id.
20+
* Data: The data fields.
1521
*/
16-
export type Model<
17-
ID,
18-
ReadAndWrite extends Fields = Fields,
19-
ReadOnly extends Fields = Fields,
20-
WriteOnly extends Fields = Fields
21-
> = ReadAndWrite & {
22-
_readOnly: ReadOnly & { id: ID; };
23-
_writeOnly: WriteOnly;
24-
};
22+
export type Model<Id extends TagId, MFields extends Fields = Fields> = {
23+
id: Id;
24+
} & Omit<MFields, "id">;
2525

26-
// Gets the type of a model's ID.
27-
export type ID<M extends Model<any>> = M['_readOnly']['id'];
26+
export type Result<M extends Model<any>, MFields extends keyof M = "id"> = Pick<
27+
M,
28+
"id" | MFields
29+
>;
2830

29-
// Gets the types of a model's readable fields.
30-
export type ReadFields<M extends Model<any>> =
31-
Omit<M, '_readOnly' | '_writeOnly'> & M['_readOnly'];
32-
33-
// Gets the types of a model's writeable fields.
34-
export type WriteFields<M extends Model<any>> =
35-
Omit<M, '_readOnly' | '_writeOnly'> & M['_writeOnly'];
36-
37-
// Gets the types of a model's readable and writeable fields.
38-
export type ReadAndWriteFields<M extends Model<any>> =
39-
Omit<M, '_readOnly' | '_writeOnly'> & M['_readOnly'] & M['_writeOnly'];
40-
41-
// An array of tags with ID's.
42-
export type TagArray<
43-
Type extends string,
44-
M extends Model<any>,
45-
LookupField extends keyof ReadFields<M> = 'id'
46-
> = Array<{
47-
type: Type;
48-
id: ReadFields<M>[LookupField];
49-
}>;
31+
export type Arg<M extends Model<any>, MFields extends keyof M> = Pick<
32+
M,
33+
MFields
34+
>;
5035

5136
// -----------------------------------------------------------------------------
5237
// CRUD Types
@@ -55,103 +40,199 @@ export type TagArray<
5540

5641
// Create
5742

58-
export type CreateResult<M extends Model<any>> = ReadFields<M>;
43+
export type CreateResult<
44+
M extends Model<any>,
45+
MFields extends keyof M = "id",
46+
> = Result<M, MFields>;
5947

60-
export type CreateArg<M extends Model<any>> = WriteFields<M>;
48+
export type CreateArg<
49+
M extends Model<any>,
50+
MFields extends keyof Omit<M, "id">,
51+
> = Arg<M, MFields>;
6152

62-
export type BulkCreateResult<M extends Model<any>> = Array<CreateResult<M>>;
53+
export type BulkCreateResult<
54+
M extends Model<any>,
55+
MFields extends keyof M = "id",
56+
ExtraFields extends Fields = Fields,
57+
> = Array<Result<M, MFields> & ExtraFields>;
6358

64-
export interface BulkCreateArg<M extends Model<any>> {
65-
data: Array<CreateArg<M>>;
66-
}
59+
export type BulkCreateArg<
60+
M extends Model<any>,
61+
MFields extends keyof Omit<M, "id">,
62+
ExtraFields extends Fields = Fields,
63+
> = Array<Arg<M, MFields> & ExtraFields>;
6764

6865
// Read
6966

70-
export type RetrieveResult<M extends Model<any>> = ReadFields<M>;
71-
72-
export type RetrieveArg<
67+
export type RetrieveResult<
7368
M extends Model<any>,
74-
LookupField extends keyof ReadAndWriteFields<M> = 'id'
75-
> = Pick<ReadAndWriteFields<M>, LookupField>;
69+
MFields extends keyof M = "id",
70+
> = Result<M, MFields>;
71+
72+
export type RetrieveArg<M extends Model<any>> = M["id"];
7673

77-
export interface ListResult<M extends Model<any>> {
74+
export interface ListResult<
75+
M extends Model<any>,
76+
MFields extends keyof M = "id",
77+
ExtraFields extends Fields = Fields,
78+
> {
7879
count: number;
7980
offset: number;
8081
limit: number;
8182
maxLimit: number;
82-
data: Array<RetrieveResult<M>>;
83+
data: Array<Result<M, MFields> & ExtraFields>;
8384
}
8485

85-
export type ListArg<Filters extends Fields = Fields> =
86-
null | Partial<Filters>;
86+
export type ListArg<Filters extends Fields = Fields> = {
87+
limit: number;
88+
offset: number;
89+
} & Partial<Omit<Filters, "limit" | "offset">>;
8790

8891
// Update
8992

90-
export type UpdateResult<M extends Model<any>> = ReadFields<M>;
93+
export type UpdateResult<
94+
M extends Model<any>,
95+
MFields extends keyof M = "id",
96+
> = Result<M, MFields>;
9197

9298
export type UpdateArg<
9399
M extends Model<any>,
94-
LookupField extends keyof ReadAndWriteFields<M> = 'id'
95-
> = Pick<ReadAndWriteFields<M>, LookupField> & Partial<WriteFields<M>>;
100+
MFields extends keyof Omit<M, "id">,
101+
ExtraFields extends Fields = Fields,
102+
> = [M["id"], Arg<M, MFields> & ExtraFields];
96103

97-
export type BulkUpdateResult<M extends Model<any>> = Array<UpdateResult<M>>;
104+
export type BulkUpdateResult<
105+
M extends Model<any>,
106+
MFields extends keyof M = "id",
107+
ExtraFields extends Fields = Fields,
108+
> = Array<Result<M, MFields> & ExtraFields>;
98109

99-
export interface BulkUpdateArg<
110+
export type BulkUpdateArg<
100111
M extends Model<any>,
101-
LookupField extends keyof ReadAndWriteFields<M> = 'id'
102-
> {
103-
data: Array<UpdateArg<M, LookupField>>;
104-
}
112+
MFields extends keyof Omit<M, "id">,
113+
ExtraFields extends Fields = Fields,
114+
> = Record<M["id"], Arg<M, MFields> & ExtraFields>;
115+
116+
export type PartialUpdateResult<
117+
M extends Model<any>,
118+
MFields extends keyof M = "id",
119+
> = Result<M, MFields>;
120+
121+
export type PartialUpdateArg<
122+
M extends Model<any>,
123+
MFields extends keyof Omit<M, "id">,
124+
ExtraFields extends Fields = Fields,
125+
> = [M["id"], Partial<Arg<M, MFields> & ExtraFields>];
126+
127+
export type BulkPartialUpdateResult<
128+
M extends Model<any>,
129+
MFields extends keyof M = "id",
130+
ExtraFields extends Fields = Fields,
131+
> = Array<Result<M, MFields> & ExtraFields>;
132+
133+
export type BulkPartialUpdateArg<
134+
M extends Model<any>,
135+
MFields extends keyof Omit<M, "id">,
136+
ExtraFields extends Fields = Fields,
137+
> = Record<M["id"], Partial<Arg<M, MFields> & ExtraFields>>;
105138

106139
// Delete
107140

108141
export type DestroyResult = null;
109142

110-
export type DestroyArg<
111-
M extends Model<any>,
112-
LookupField extends keyof ReadAndWriteFields<M> = 'id'
113-
> = Pick<ReadAndWriteFields<M>, LookupField>;
143+
export type DestroyArg<M extends Model<any>> = M["id"];
114144

115145
export type BulkDestroyResult = null;
116146

117-
export interface BulkDestroyArg<
118-
M extends Model<any>,
119-
LookupField extends keyof ReadAndWriteFields<M> = 'id'
120-
> {
121-
LookupField: Array<DestroyArg<M, LookupField>[LookupField]>;
122-
}
147+
export type BulkDestroyArg<M extends Model<any>> = Array<M["id"]>;
123148

124149
// -----------------------------------------------------------------------------
125150
// Functions
126151
// -----------------------------------------------------------------------------
127152

128-
export function searchParamsToString(arg: ListArg): string {
129-
if (arg !== null) {
130-
const searchParams = Object.entries(arg)
153+
export function buildUrl(
154+
url: string,
155+
params: {
156+
search?: Fields;
157+
url?: Fields;
158+
}
159+
): string {
160+
if (params.url) {
161+
Object.entries(params.url).forEach(([key, value]) => {
162+
url = url.replace(`<${key}>`, String(value));
163+
});
164+
}
165+
166+
if (params.search) {
167+
const searchParams = Object.entries(params.search)
131168
.filter(([_, value]) => value !== undefined)
132169
.map(([key, value]) => [key, String(value)]);
133170

134171
if (searchParams.length !== 0) {
135-
return `?${new URLSearchParams(searchParams).toString()}`;
172+
url += `?${new URLSearchParams(searchParams).toString()}`;
136173
}
137174
}
138175

139-
return '';
176+
return url;
140177
}
141178

142-
export function tagData<
143-
Type extends string,
144-
M extends Model<any>,
145-
LookupField extends keyof ReadFields<M> = 'id'
146-
>(
147-
result: ListResult<M> | BulkCreateResult<M>,
148-
type: Type,
149-
lookupField: LookupField = 'id' as LookupField
150-
): TagArray<Type, M, LookupField> {
151-
const data = 'data' in result ? result.data : result;
152-
153-
return data.map((result) => ({
154-
type,
155-
id: result[lookupField]
156-
})) as TagArray<Type, M, LookupField>;
179+
export function isTagId(value: unknown): boolean {
180+
return typeof value === "number" || typeof value === "string";
181+
}
182+
183+
export function tagData<Type extends string, M extends Model<any>>(
184+
type: Type
185+
): (
186+
result:
187+
| Result<M, any>
188+
| Array<Result<M, any>>
189+
| ListResult<M, any>
190+
| null
191+
| undefined,
192+
error: FetchBaseQueryError | undefined,
193+
arg:
194+
| Arg<M, any>
195+
| Array<Arg<M, any>>
196+
| [M["id"], Arg<M, any>]
197+
| Record<M["id"], Arg<M, any>>
198+
| ListArg<any>
199+
| Array<M["id"]>
200+
| string
201+
| number
202+
| undefined
203+
) => Array<Tag<Type>> {
204+
return (result, error, arg) => {
205+
if (!error) {
206+
if (arg) {
207+
if (isTagId(arg)) return [{ type, id: arg as TagId }];
208+
209+
if (Array.isArray(arg) && arg.length > 0) {
210+
if (isTagId(arg[0])) {
211+
if (arg.length === 2 && !isTagId(arg[1])) {
212+
return [{ type, id: (arg as [M["id"], Arg<M, any>])[0] }];
213+
}
214+
215+
return (arg as Array<M["id"]>).map((id) => ({ type, id }));
216+
}
217+
}
218+
}
219+
220+
if (result) {
221+
if ("id" in result) {
222+
return [{ type, id: result["id"] as TagId }];
223+
}
224+
225+
if (Array.isArray(result)) {
226+
return result.map((result) => ({ type, id: result["id"] as TagId }));
227+
}
228+
229+
return (result as ListResult<M, any>).data.map((result) => ({
230+
type,
231+
id: result["id"] as TagId,
232+
}));
233+
}
234+
}
235+
236+
return [];
237+
};
157238
}

0 commit comments

Comments
 (0)