mobx-lark 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,283 +1,294 @@
1
- import {
2
- DataObject,
3
- Filter,
4
- ListModel,
5
- PageData,
6
- RESTClient,
7
- Stream,
8
- toggle
9
- } from 'mobx-restful';
10
- import { buildURLData, Constructor, isEmpty } from 'web-utility';
11
-
12
- import { UserIdType } from '../../type';
13
- import { createPageStream } from '../base';
14
- import {
15
- BITable,
16
- LarkFormData,
17
- TableFormView,
18
- TableRecord,
19
- TableRecordData,
20
- TableRecordFields,
21
- TableView
22
- } from './type';
23
- import { makeSimpleFilter } from './utility';
24
-
25
- export * from './type';
26
- export * from './utility';
27
-
28
- export type BiBaseData = Omit<
29
- TableRecord<{}>,
30
- `record_${'id' | 'url'}` | 'fields'
31
- >;
32
-
33
- export interface BiDataQueryOptions {
34
- text_field_as_array?: boolean;
35
- automatic_fields?: boolean;
36
- display_formula_ref?: boolean;
37
- with_shared_url?: boolean;
38
- user_id_type?: UserIdType;
39
- }
40
-
41
- /**
42
- * @see {@link https://open.feishu.cn/document/ukTMukTMukTM/uUDN04SN0QjL1QDN/bitable-overview}
43
- */
44
- export function BiDataTable<
45
- T extends DataObject,
46
- F extends Filter<T> = Filter<T>
47
- >(Base = ListModel) {
48
- abstract class BiDataTableModel extends Stream<T, F>(Base) {
49
- requiredKeys: readonly (keyof T)[] = [];
50
-
51
- sort: Partial<Record<keyof T, 'ASC' | 'DESC'>> = {};
52
-
53
- queryOptions: BiDataQueryOptions = {
54
- text_field_as_array: true,
55
- automatic_fields: true
56
- };
57
- currentViewId?: string;
58
-
59
- constructor(appId: string, tableId: string) {
60
- super();
61
- this.baseURI = `bitable/v1/apps/${appId}/tables/${tableId}/records`;
62
- }
63
-
64
- normalize({ fields, ...meta }: TableRecord<T>): T {
65
- return { ...meta, ...fields };
66
- }
67
-
68
- /**
69
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/get}
70
- */
71
- @toggle('downloading')
72
- async getOne(id: string) {
73
- const { body } = await this.client.get<TableRecordData<T>>(
74
- `${this.baseURI}/${id}?${buildURLData(this.queryOptions)}`
75
- );
76
- return (this.currentOne = this.normalize(body!.data!.record));
77
- }
78
-
79
- /**
80
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/create}
81
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/update}
82
- */
83
- @toggle('uploading')
84
- async updateOne(fields: F, id?: string) {
85
- const { body } = await (id
86
- ? this.client.put<TableRecordData<T>>(`${this.baseURI}/${id}`, {
87
- fields
88
- })
89
- : this.client.post<TableRecordData<T>>(this.baseURI, {
90
- fields
91
- }));
92
- return (this.currentOne = this.normalize(body!.data!.record));
93
- }
94
-
95
- makeFilter(filter: F) {
96
- return [
97
- this.requiredKeys[0] &&
98
- makeSimpleFilter(
99
- Object.fromEntries(
100
- this.requiredKeys.map(key => [key, ''])
101
- ),
102
- '!='
103
- ),
104
- !isEmpty(filter) && makeSimpleFilter(filter)
105
- ]
106
- .filter(Boolean)
107
- .join('&&');
108
- }
109
-
110
- /**
111
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/list}
112
- */
113
- async *openStream(filter: F) {
114
- const view_id = this.currentViewId;
115
- const searchParams = view_id
116
- ? { view_id }
117
- : {
118
- filter: this.makeFilter(filter),
119
- sort: JSON.stringify(
120
- Object.entries(this.sort).map(
121
- ([key, order]) => `${key} ${order}`
122
- )
123
- )
124
- };
125
- const stream = createPageStream<TableRecord<T>>(
126
- this.client,
127
- this.baseURI,
128
- total => (this.totalCount = total),
129
- { ...searchParams, ...this.queryOptions }
130
- );
131
- for await (const item of stream) yield this.normalize(item);
132
- }
133
-
134
- async getViewList(
135
- viewId: string,
136
- pageIndex = this.pageIndex + 1,
137
- pageSize = this.pageSize
138
- ) {
139
- try {
140
- this.currentViewId = viewId;
141
-
142
- return await this.getList({} as F, pageIndex, pageSize);
143
- } finally {
144
- this.currentViewId = undefined;
145
- }
146
- }
147
-
148
- async getViewAll(viewId: string, pageSize = this.pageSize) {
149
- this.clearList();
150
-
151
- while (!this.noMore)
152
- await this.getViewList(viewId, undefined, pageSize);
153
-
154
- return this.allItems;
155
- }
156
- }
157
- return BiDataTableModel;
158
- }
159
-
160
- export function BiSearch<D extends DataObject, F extends Filter<D> = Filter<D>>(
161
- Model: Constructor<ListModel<D, F>>
162
- ) {
163
- abstract class BiSearchModel extends Model {
164
- declare baseURI: string;
165
- declare client: RESTClient;
166
- declare loadPage: (
167
- pageIndex: number,
168
- pageSize: number,
169
- filter: F
170
- ) => Promise<PageData<D>>;
171
-
172
- abstract searchKeys: readonly (keyof TableRecordFields)[];
173
-
174
- makeFilter(filter: F) {
175
- return isEmpty(filter)
176
- ? ''
177
- : makeSimpleFilter(filter, 'contains', 'OR');
178
- }
179
-
180
- async getSearchList(
181
- keywords: string,
182
- pageIndex = this.pageIndex + 1,
183
- pageSize = this.pageSize
184
- ) {
185
- const wordList = keywords.split(/[\s,]+/);
186
- const filterList = this.searchKeys.map(key => [key, wordList]);
187
-
188
- return this.getList(
189
- Object.fromEntries(filterList),
190
- pageIndex,
191
- pageSize
192
- );
193
- }
194
- }
195
- return BiSearchModel;
196
- }
197
-
198
- interface BiSearchModel
199
- extends InstanceType<ReturnType<typeof BiSearch<TableRecordFields, any>>> {}
200
-
201
- export type BiSearchModelClass = Constructor<BiSearchModel>;
202
-
203
- export function BiTableView<
204
- T extends TableView['view_type'],
205
- D extends T extends 'form' ? TableFormView : TableView
206
- >(type = 'grid' as T) {
207
- abstract class BiTableViewModel extends Stream<D>(ListModel) {
208
- constructor(appId: string, tableId: string) {
209
- super();
210
- this.baseURI = `bitable/v1/apps/${appId}/tables/${tableId}/views`;
211
- }
212
-
213
- /**
214
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-view/list}
215
- * @see {@link https://open.feishu.cn/document/server-docs/docs/bitable-v1/form/get}
216
- */
217
- async *openStream() {
218
- for await (const item of createPageStream<TableView>(
219
- this.client,
220
- this.baseURI,
221
- total => (this.totalCount = total)
222
- ))
223
- if (type !== 'form') {
224
- if (item.view_type === type) yield item as D;
225
- } else if (item.view_type === 'form') {
226
- const { body } = await this.client.get<LarkFormData>(
227
- this.baseURI.replace(/views$/, `forms/${item.view_id}`)
228
- );
229
- yield body!.data!.form as D;
230
- }
231
- }
232
- }
233
- return BiTableViewModel;
234
- }
235
-
236
- export type BiDataTableClass<
237
- T extends DataObject,
238
- F extends Filter<T> = Filter<T>
239
- > = ReturnType<typeof BiDataTable<T, F>>;
240
-
241
- export function BiTable() {
242
- abstract class BiTableModel extends Stream<BITable>(ListModel) {
243
- constructor(public id: string) {
244
- super();
245
- this.baseURI = `bitable/v1/apps/${id}/tables`;
246
- }
247
-
248
- currentDataTable?: ListModel<any>;
249
-
250
- async getOne<T extends DataObject, F extends Filter<T>>(
251
- tableName: string,
252
- DataTableClass?: BiDataTableClass<T, F>
253
- ) {
254
- const { allItems } = this;
255
-
256
- const list = allItems[0] ? allItems : await this.getAll();
257
-
258
- const table = list.find(({ name }) => name === tableName);
259
-
260
- if (!table) throw new URIError(`Table "${tableName}" is not found`);
261
-
262
- if (DataTableClass instanceof Function)
263
- this.currentDataTable = Reflect.construct(DataTableClass, [
264
- this.id,
265
- table.table_id
266
- ]);
267
- return (this.currentOne = table);
268
- }
269
-
270
- /**
271
- * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table/list}
272
- */
273
- async *openStream() {
274
- for await (const item of createPageStream<BITable>(
275
- this.client,
276
- this.baseURI,
277
- total => (this.totalCount = total)
278
- ))
279
- yield item;
280
- }
281
- }
282
- return BiTableModel;
283
- }
1
+ import {
2
+ DataObject,
3
+ Filter,
4
+ ListModel,
5
+ PageData,
6
+ RESTClient,
7
+ Stream,
8
+ toggle
9
+ } from 'mobx-restful';
10
+ import { buildURLData, Constructor, isEmpty } from 'web-utility';
11
+
12
+ import { UserIdType } from '../../type';
13
+ import { createPageStream } from '../base';
14
+ import {
15
+ BITable,
16
+ LarkFormData,
17
+ TableFormView,
18
+ TableRecord,
19
+ TableRecordData,
20
+ TableRecordFields,
21
+ TableView
22
+ } from './type';
23
+ import { makeSimpleFilter } from './utility';
24
+
25
+ export * from './type';
26
+ export * from './utility';
27
+
28
+ export type BiBaseData = Omit<
29
+ TableRecord<{}>,
30
+ `record_${'id' | 'url'}` | 'fields'
31
+ >;
32
+
33
+ export interface BiDataQueryOptions {
34
+ text_field_as_array?: boolean;
35
+ automatic_fields?: boolean;
36
+ display_formula_ref?: boolean;
37
+ with_shared_url?: boolean;
38
+ user_id_type?: UserIdType;
39
+ }
40
+
41
+ /**
42
+ * @see {@link https://open.feishu.cn/document/ukTMukTMukTM/uUDN04SN0QjL1QDN/bitable-overview}
43
+ */
44
+ export function BiDataTable<
45
+ T extends DataObject,
46
+ F extends Filter<T> = Filter<T>
47
+ >(Base = ListModel) {
48
+ abstract class BiDataTableModel extends Stream<T, F>(Base) {
49
+ requiredKeys: readonly (keyof T)[] = [];
50
+
51
+ sort: Partial<Record<keyof T, 'ASC' | 'DESC'>> = {};
52
+
53
+ queryOptions: BiDataQueryOptions = {
54
+ text_field_as_array: true,
55
+ automatic_fields: true
56
+ };
57
+ currentViewId?: string;
58
+
59
+ constructor(appId: string, tableId: string) {
60
+ super();
61
+ this.baseURI = `bitable/v1/apps/${appId}/tables/${tableId}/records`;
62
+ }
63
+
64
+ extractFields({ fields, ...meta }: TableRecord<T>): T {
65
+ return { ...meta, ...fields };
66
+ }
67
+
68
+ /**
69
+ * @deprecated
70
+ */
71
+ normalize = this.extractFields;
72
+
73
+ wrapFields(fields: F) {
74
+ return fields as unknown as T;
75
+ }
76
+
77
+ /**
78
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/get}
79
+ */
80
+ @toggle('downloading')
81
+ async getOne(id: string) {
82
+ const { body } = await this.client.get<TableRecordData<T>>(
83
+ `${this.baseURI}/${id}?${buildURLData(this.queryOptions)}`
84
+ );
85
+ return (this.currentOne = this.normalize(body!.data!.record));
86
+ }
87
+
88
+ /**
89
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/create}
90
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/update}
91
+ */
92
+ @toggle('uploading')
93
+ async updateOne(data: F, id?: string) {
94
+ const fields = this.wrapFields(data);
95
+
96
+ const { body } = await (id
97
+ ? this.client.put<TableRecordData<T>>(`${this.baseURI}/${id}`, {
98
+ fields
99
+ })
100
+ : this.client.post<TableRecordData<T>>(this.baseURI, {
101
+ fields
102
+ }));
103
+ return (this.currentOne = this.normalize(body!.data!.record));
104
+ }
105
+
106
+ makeFilter(filter: F) {
107
+ return [
108
+ this.requiredKeys[0] &&
109
+ makeSimpleFilter(
110
+ Object.fromEntries(
111
+ this.requiredKeys.map(key => [key, ''])
112
+ ),
113
+ '!='
114
+ ),
115
+ !isEmpty(filter) && makeSimpleFilter(filter)
116
+ ]
117
+ .filter(Boolean)
118
+ .join('&&');
119
+ }
120
+
121
+ /**
122
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/list}
123
+ */
124
+ async *openStream(filter: F) {
125
+ const view_id = this.currentViewId;
126
+ const searchParams = view_id
127
+ ? { view_id }
128
+ : {
129
+ filter: this.makeFilter(filter),
130
+ sort: JSON.stringify(
131
+ Object.entries(this.sort).map(
132
+ ([key, order]) => `${key} ${order}`
133
+ )
134
+ )
135
+ };
136
+ const stream = createPageStream<TableRecord<T>>(
137
+ this.client,
138
+ this.baseURI,
139
+ total => (this.totalCount = total),
140
+ { ...searchParams, ...this.queryOptions }
141
+ );
142
+ for await (const item of stream) yield this.normalize(item);
143
+ }
144
+
145
+ async getViewList(
146
+ viewId: string,
147
+ pageIndex = this.pageIndex + 1,
148
+ pageSize = this.pageSize
149
+ ) {
150
+ try {
151
+ this.currentViewId = viewId;
152
+
153
+ return await this.getList({} as F, pageIndex, pageSize);
154
+ } finally {
155
+ this.currentViewId = undefined;
156
+ }
157
+ }
158
+
159
+ async getViewAll(viewId: string, pageSize = this.pageSize) {
160
+ this.clearList();
161
+
162
+ while (!this.noMore)
163
+ await this.getViewList(viewId, undefined, pageSize);
164
+
165
+ return this.allItems;
166
+ }
167
+ }
168
+ return BiDataTableModel;
169
+ }
170
+
171
+ export function BiSearch<D extends DataObject, F extends Filter<D> = Filter<D>>(
172
+ Model: Constructor<ListModel<D, F>>
173
+ ) {
174
+ abstract class BiSearchModel extends Model {
175
+ declare baseURI: string;
176
+ declare client: RESTClient;
177
+ declare loadPage: (
178
+ pageIndex: number,
179
+ pageSize: number,
180
+ filter: F
181
+ ) => Promise<PageData<D>>;
182
+
183
+ abstract searchKeys: readonly (keyof TableRecordFields)[];
184
+
185
+ makeFilter(filter: F) {
186
+ return isEmpty(filter)
187
+ ? ''
188
+ : makeSimpleFilter(filter, 'contains', 'OR');
189
+ }
190
+
191
+ async getSearchList(
192
+ keywords: string,
193
+ pageIndex = this.pageIndex + 1,
194
+ pageSize = this.pageSize
195
+ ) {
196
+ const wordList = keywords.split(/[\s,]+/);
197
+ const filterList = this.searchKeys.map(key => [key, wordList]);
198
+
199
+ return this.getList(
200
+ Object.fromEntries(filterList),
201
+ pageIndex,
202
+ pageSize
203
+ );
204
+ }
205
+ }
206
+ return BiSearchModel;
207
+ }
208
+
209
+ interface BiSearchModel
210
+ extends InstanceType<ReturnType<typeof BiSearch<TableRecordFields, any>>> {}
211
+
212
+ export type BiSearchModelClass = Constructor<BiSearchModel>;
213
+
214
+ export function BiTableView<
215
+ T extends TableView['view_type'],
216
+ D extends T extends 'form' ? TableFormView : TableView
217
+ >(type = 'grid' as T) {
218
+ abstract class BiTableViewModel extends Stream<D>(ListModel) {
219
+ constructor(appId: string, tableId: string) {
220
+ super();
221
+ this.baseURI = `bitable/v1/apps/${appId}/tables/${tableId}/views`;
222
+ }
223
+
224
+ /**
225
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-view/list}
226
+ * @see {@link https://open.feishu.cn/document/server-docs/docs/bitable-v1/form/get}
227
+ */
228
+ async *openStream() {
229
+ for await (const item of createPageStream<TableView>(
230
+ this.client,
231
+ this.baseURI,
232
+ total => (this.totalCount = total)
233
+ ))
234
+ if (type !== 'form') {
235
+ if (item.view_type === type) yield item as D;
236
+ } else if (item.view_type === 'form') {
237
+ const { body } = await this.client.get<LarkFormData>(
238
+ this.baseURI.replace(/views$/, `forms/${item.view_id}`)
239
+ );
240
+ yield body!.data!.form as D;
241
+ }
242
+ }
243
+ }
244
+ return BiTableViewModel;
245
+ }
246
+
247
+ export type BiDataTableClass<
248
+ T extends DataObject,
249
+ F extends Filter<T> = Filter<T>
250
+ > = ReturnType<typeof BiDataTable<T, F>>;
251
+
252
+ export function BiTable() {
253
+ abstract class BiTableModel extends Stream<BITable>(ListModel) {
254
+ constructor(public id: string) {
255
+ super();
256
+ this.baseURI = `bitable/v1/apps/${id}/tables`;
257
+ }
258
+
259
+ currentDataTable?: ListModel<any>;
260
+
261
+ async getOne<T extends DataObject, F extends Filter<T>>(
262
+ tableName: string,
263
+ DataTableClass?: BiDataTableClass<T, F>
264
+ ) {
265
+ const { allItems } = this;
266
+
267
+ const list = allItems[0] ? allItems : await this.getAll();
268
+
269
+ const table = list.find(({ name }) => name === tableName);
270
+
271
+ if (!table) throw new URIError(`Table "${tableName}" is not found`);
272
+
273
+ if (DataTableClass instanceof Function)
274
+ this.currentDataTable = Reflect.construct(DataTableClass, [
275
+ this.id,
276
+ table.table_id
277
+ ]);
278
+ return (this.currentOne = table);
279
+ }
280
+
281
+ /**
282
+ * @see {@link https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table/list}
283
+ */
284
+ async *openStream() {
285
+ for await (const item of createPageStream<BITable>(
286
+ this.client,
287
+ this.baseURI,
288
+ total => (this.totalCount = total)
289
+ ))
290
+ yield item;
291
+ }
292
+ }
293
+ return BiTableModel;
294
+ }