@d-mok/quasar-app-extension-quasar-axe 1.0.2 → 1.0.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d-mok/quasar-app-extension-quasar-axe",
3
- "version": "1.0.2",
3
+ "version": "1.0.6",
4
4
  "description": "A Quasar App Extension",
5
5
  "author": "d-mok <49301824+d-mok@users.noreply.github.com>",
6
6
  "license": "MIT",
@@ -20,3 +20,4 @@ export default boot(({ app }) => {
20
20
  app.component('QxSelectObject', QxSelectObject)
21
21
  app.component('QxSelectText', QxSelectText)
22
22
  })
23
+
@@ -3,6 +3,7 @@ import { qDialog } from '../dialog'
3
3
  import { qNotify } from '../notify'
4
4
  import { LoadingBar } from 'quasar'
5
5
  import { Ordering, Criteria, strKeyOf, Sheet } from 'sapphire-js'
6
+ import { reactive } from 'vue'
6
7
 
7
8
 
8
9
  export type Where<T> =
@@ -11,29 +12,20 @@ export type Where<T> =
11
12
  | T[K][]
12
13
  | { like: string }
13
14
  }
14
- | ((_: PostgrestFilterBuilder) => any)
15
15
 
16
- // export type OrderBy<T> =
17
- // strKeyOf<T>
18
- // | { [K in keyof T]?: true | false }
19
16
 
20
17
 
21
-
22
- type Action = 'select' | 'insert' | 'update' | 'delete' | 'patch'
23
-
18
+ type Action = 'select' | 'insert' | 'update' | 'delete'
24
19
 
25
20
 
26
21
  function loadingBar(on: boolean): void {
27
- on ? setTimeout(() => LoadingBar.setDefaults({ size: "5px" }), 3000)
22
+ on
23
+ ? setTimeout(() => LoadingBar.setDefaults({ size: "5px" }), 3000)
28
24
  : LoadingBar.setDefaults({ size: "0px" })
29
25
  }
30
26
 
31
27
 
32
28
 
33
-
34
-
35
-
36
-
37
29
  /**
38
30
  * A subclass of array designed as an ORM.
39
31
  * @template T - type of element class
@@ -41,28 +33,38 @@ function loadingBar(on: boolean): void {
41
33
  */
42
34
  export abstract class BasicTable<T extends R, R extends object> extends Sheet<T>{
43
35
 
36
+ constructor(...args: any) {
37
+ super(args)
38
+ if (this.caching) {
39
+ this.restoreCache()
40
+ setInterval(() => this.screenCache(), 6000 + Math.random() * 3000)
41
+ }
42
+ }
43
+
44
44
  /**
45
45
  * The name of the database table.
46
46
  */
47
47
  public abstract readonly tableName: string
48
+
48
49
  /**
49
50
  * The name of the ID field.
50
51
  */
51
52
  public abstract readonly idField: strKeyOf<R>
53
+
52
54
  /**
53
55
  * The class of the elements.
54
56
  */
55
57
  public abstract readonly entityClass: new (_: Partial<R>) => T
58
+
56
59
  /**
57
60
  * The default ordering instruction object.
58
61
  */
59
62
  public readonly ordering: Readonly<Ordering<T>> = []
60
- // /**
61
- // * The default fields to select
62
- // */
63
- // public readonly selectFields: strKeyOf<R>[] = []
64
-
65
63
 
64
+ /**
65
+ * Auto Cache
66
+ */
67
+ public readonly caching: boolean = false
66
68
 
67
69
  private convert(data: R[]): T[] {
68
70
  return data.map($ => new this.entityClass($))
@@ -74,41 +76,21 @@ export abstract class BasicTable<T extends R, R extends object> extends Sheet<T>
74
76
  }
75
77
 
76
78
 
77
-
78
- // private defaultOrder(): void {
79
- // if (this.ordering !== undefined)
80
- // this.order(...this.ordering)
81
- // }
82
-
83
-
84
- // private selectedFields() {
85
- // return this.selectFields === undefined ? "*" : this.selectFields.join(",")
86
- // }
87
-
88
-
89
79
  protected idWhere(id: R[this['idField']]): any {
90
80
  return { [this.idField]: id }
91
81
  }
92
82
 
93
83
 
94
- protected idsWhere(ids: R[this['idField']][]): any {
95
- return { [this.idField]: ids }
96
- }
97
84
 
98
85
 
99
- protected orderById(ids: R[this['idField']][]): void {
100
- let ord = { [this.idField]: ids } as any
101
- this.order(ord)
102
- }
103
86
 
104
87
 
105
- private APIAction(type: Action, content: Partial<R>[] = []) {
88
+
89
+ private APIAction(type: Action, content: Partial<R>[]) {
106
90
  let q = supabase.from<R>(this.tableName)
107
91
  switch (type) {
108
92
  case 'select':
109
93
  return q.select('*')
110
- case 'patch':
111
- return q.select('*')
112
94
  case 'delete':
113
95
  return q.delete()
114
96
  case 'insert':
@@ -120,21 +102,19 @@ export abstract class BasicTable<T extends R, R extends object> extends Sheet<T>
120
102
 
121
103
  protected async API({
122
104
  type,
123
- content,
124
- where,
125
- // orderBy,
126
- // limit,
127
- action = (_: any) => { },
128
- confirm,
129
- notify,
130
- slience
105
+ content = [],
106
+ where = {},
107
+ custom = $ => $,
108
+ action = ($: any) => { },
109
+ confirm = undefined,
110
+ notify = undefined,
111
+ slience = false
131
112
  }: {
132
113
  type: Action
133
114
  content?: Partial<R>[]
134
115
  where?: Where<R>
135
- // orderBy?: OrderBy<R>
136
- // limit?: number,
137
- action: (entities: T[]) => void
116
+ custom?: (_: PostgrestFilterBuilder) => PostgrestFilterBuilder
117
+ action?: (entities: T[]) => void
138
118
  confirm?: [string, string?]
139
119
  notify?: string
140
120
  slience?: boolean
@@ -144,12 +124,12 @@ export abstract class BasicTable<T extends R, R extends object> extends Sheet<T>
144
124
 
145
125
  let q = this.APIAction(type, content)
146
126
  q = applyWhere(q, where)
147
- // q = applyOrderBy(q, orderBy)
148
- // q = applyLimit(q, limit)
127
+ q = custom(q)
149
128
 
150
129
  let { data, error } = await q
151
130
  handleError(data, error)
152
131
 
132
+ if (this.caching) this.pushCache(data)
153
133
  let entities = this.convert(data)
154
134
  action(entities)
155
135
  this.order(...this.ordering)
@@ -161,68 +141,77 @@ export abstract class BasicTable<T extends R, R extends object> extends Sheet<T>
161
141
 
162
142
 
163
143
 
164
-
165
-
166
144
  /**
167
145
  * Get an item by `criteria`. If not found, return a new object.
168
146
  */
169
147
  got(criteria: Criteria<T>): T {
170
148
  return this.get(criteria) ?? new this.entityClass({})
171
149
  }
172
- }
173
150
 
174
151
 
152
+ /**
153
+ * Get a reactive copy of this.
154
+ */
155
+ reactive(): this {
156
+ return reactive(this) as this
157
+ }
175
158
 
176
159
 
177
160
 
161
+ private get cache(): R[] {
162
+ return JSON.parse(localStorage.getItem(this.tableName) ?? '[]')
163
+ }
178
164
 
179
- function applyWhere(q: PostgrestFilterBuilder, where?: Where<any>): PostgrestFilterBuilder {
180
- if (where === undefined)
181
- return q
165
+ private set cache(data: R[]) {
166
+ let json = JSON.stringify(data)
167
+ localStorage.setItem(this.tableName, json)
168
+ }
182
169
 
183
- if (typeof where === 'function')
184
- return where(q)
170
+ private restoreCache() {
171
+ let entities = this.convert(this.cache)
172
+ this.set(entities)
173
+ }
185
174
 
186
- for (let key in where) {
187
- let val = where[key]
188
- if (Array.isArray(val)) {
189
- // treat as in
190
- q = q.in(key, val)
191
- } else if (typeof val === 'object') {
192
- if ('like' in val) {
193
- // treat as like
194
- let { like } = val as { like: string }
195
- q = q.like(key, like)
196
- }
197
- } else {
198
- // treat as eq
199
- q = q.eq(key, val)
200
- }
175
+ private pushCache(data: R[]) {
176
+ this.cache = [...this.cache, ...data]
201
177
  }
202
- return q
178
+
179
+ private screenCache() {
180
+ let ids: any[] = this.scan(this.idField)
181
+ this.cache = this.cache.filter($ => ids.includes($[this.idField]))
182
+ }
183
+
184
+
185
+
186
+
187
+
203
188
  }
204
189
 
205
- // function applyOrderBy(q: PostgrestFilterBuilder, orderBy?: OrderBy<any>): PostgrestFilterBuilder {
206
- // if (orderBy === undefined)
207
- // return q
208
190
 
209
- // if (typeof orderBy === "string") {
210
- // q = q.order(orderBy)
211
- // } else {
212
- // let field = Object.keys(orderBy)[0]
213
- // let ascending = orderBy[field]
214
- // q = q.order(field, { ascending })
215
- // }
216
- // return q
217
- // }
191
+ function whereType(val: any): string {
192
+ if (Array.isArray(val))
193
+ return 'in'
218
194
 
195
+ if (typeof val === 'object' && 'like' in val)
196
+ return 'like'
219
197
 
198
+ return 'eq'
199
+ }
220
200
 
221
- // function applyLimit(q: PostgrestFilterBuilder, limit?: number): PostgrestFilterBuilder {
222
- // if (limit === undefined)
223
- // return q
224
201
 
225
- // return q.limit(limit)
226
- // }
227
202
 
203
+ function applyWhere(q: PostgrestFilterBuilder, where: Where<any>): PostgrestFilterBuilder {
204
+ for (let key in where) {
205
+ let val = where[key]
206
+ let type = whereType(val)
207
+
208
+ if (type === 'in')
209
+ q = q.in(key, val)
210
+ if (type === 'like')
211
+ q = q.like(key, val.like)
212
+ if (type === 'eq')
213
+ q = q.eq(key, val)
214
+ }
215
+ return q
216
+ }
228
217
 
@@ -4,7 +4,7 @@ import { TableView } from './view'
4
4
 
5
5
 
6
6
  type muteOptions = {
7
- confirm?: [string, string?]
7
+ confirm?: [string, string?]
8
8
  notify?: string
9
9
  slience?: boolean
10
10
  }
@@ -28,7 +28,7 @@ export abstract class Table<T extends R, R extends object> extends TableView<T,
28
28
  await this.API({
29
29
  type: 'insert',
30
30
  content: Array.isArray(rows) ? rows : [rows],
31
- action: entities => this.push(...entities),
31
+ action: $ => this.push(...$),
32
32
  confirm,
33
33
  notify,
34
34
  slience
@@ -45,7 +45,7 @@ export abstract class Table<T extends R, R extends object> extends TableView<T,
45
45
  type: 'update',
46
46
  content: [row],
47
47
  where: this.idWhere(id),
48
- action: entities => this.merge(entities, this.idField),
48
+ action: $ => this.merge($, this.idField),
49
49
  confirm,
50
50
  notify,
51
51
  slience
@@ -88,7 +88,7 @@ export abstract class Table<T extends R, R extends object> extends TableView<T,
88
88
  await this.API({
89
89
  type: 'delete',
90
90
  where: this.idWhere(id),
91
- action: entities => this.discard(this.idWhere(id) as Criteria<T>),
91
+ action: $ => this.discard(this.idWhere(id) as Criteria<T>),
92
92
  confirm,
93
93
  notify,
94
94
  slience
@@ -153,3 +153,61 @@ export function Empower<RCls extends Constructor, R = InstanceType<RCls>>(BaseCl
153
153
 
154
154
 
155
155
 
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+ // class FolderRow {
167
+ // id: number = 0
168
+ // subject: string = ""
169
+ // category: string = ""
170
+ // teacher: string = ""
171
+ // bank: string = ""
172
+ // name: string = ""
173
+ // pub_q: boolean = false
174
+ // pub_s: boolean = false
175
+ // codes: string[] = []
176
+ // modified: number = 0
177
+
178
+ // constructor(row = {}) {
179
+ // Object.assign(this, row)
180
+ // }
181
+ // }
182
+
183
+
184
+
185
+
186
+ // export class Folder extends FolderRow {
187
+
188
+
189
+
190
+
191
+ // }
192
+
193
+
194
+
195
+ // export class FolderTable extends Table<Folder, FolderRow>{
196
+ // readonly tableName = 'folder'
197
+ // readonly idField = 'id' as const
198
+ // readonly entityClass = Folder
199
+ // readonly ordering = [
200
+ // 'subject',
201
+ // { category: ['topic', 'paper', 'exercise'] },
202
+ // 'bank',
203
+ // 'name'
204
+ // ] as const
205
+
206
+
207
+
208
+ // }
209
+
210
+
211
+ // export const Folders = (new FolderTable).reactive()
212
+
213
+ // Folders.selectIn('teacher', [1,2,3])
@@ -1,13 +1,15 @@
1
1
  import { BasicTable, Where } from './basic'
2
+ import { PostgrestFilterBuilder } from '../supabase'
3
+ import { strKeyOf } from 'sapphire-js'
2
4
 
3
5
 
4
6
  type selectOptions<R> = {
5
7
  where?: Where<R>
6
- // orderBy?: OrderBy<R>
7
- // limit?: number
8
+ custom?: (_: PostgrestFilterBuilder) => PostgrestFilterBuilder
8
9
  confirm?: [string, string?]
9
10
  notify?: string
10
11
  slience?: boolean
12
+ patch?: boolean
11
13
  }
12
14
 
13
15
 
@@ -30,65 +32,42 @@ function chunk<T>(arr: T[], size: number): T[][] {
30
32
  */
31
33
  export abstract class TableView<T extends R, R extends object> extends BasicTable<T, R>{
32
34
 
33
- async select({ where, confirm, notify, slience }: selectOptions<R> = {}) {
35
+ async select({ where, custom, confirm, notify, slience, patch }: selectOptions<R> = {}) {
36
+ if (!patch) this.clear()
34
37
  await this.API({
35
38
  type: 'select',
36
39
  where,
37
- // orderBy,
38
- // limit,
39
- action: entities => this.set(entities),
40
- // order: true,
40
+ custom,
41
+ action: $ => patch ? this.absorb($, this.idField) : this.set($),
41
42
  confirm,
42
43
  notify,
43
44
  slience
44
45
  })
45
46
  }
46
47
 
47
- async patch({ where, confirm, notify, slience }: selectOptions<R> = {}) {
48
- await this.API({
49
- type: 'patch',
50
- where,
51
- // orderBy,
52
- // limit,
53
- action: entities => this.absorb(entities, this.idField),
54
- confirm,
55
- notify,
56
- slience
57
- })
58
- }
59
48
 
60
49
 
61
- async patchIDs(
62
- ids: R[this['idField']][],
63
- { where, confirm, notify, slience }: selectOptions<R> = {},
50
+ async selectIn<F extends strKeyOf<R>>(
51
+ field: F,
52
+ values: R[F][],
53
+ { where, custom, confirm, notify, slience, patch }: selectOptions<R> = {},
64
54
  chunkSize = 100,
65
55
  ) {
66
- for (let ck of chunk(ids, chunkSize)) {
67
- await this.patch({
68
- where: { ...this.idsWhere(ck), ...where },
69
- confirm,
70
- notify,
71
- slience
72
- })
73
- }
56
+ if (!patch) this.clear()
57
+ let getSelect = (ck: R[F][]): Promise<void> => this.select({
58
+ where: { [field]: ck, ...where },
59
+ custom,
60
+ confirm,
61
+ notify,
62
+ slience,
63
+ patch: true
64
+ })
65
+ await Promise.all(chunk(values, chunkSize).map(getSelect))
74
66
  if (this.ordering.length === 0)
75
- this.orderById(ids)
67
+ this.order({ [field]: values } as any)
76
68
  }
77
69
 
78
70
 
79
- async selectIDs(
80
- ids: R[this['idField']][],
81
- { where, confirm, notify, slience }: selectOptions<R> = {},
82
- chunkSize = 100,
83
- ) {
84
- this.clear()
85
- this.patchIDs(
86
- ids,
87
- { where, confirm, notify, slience },
88
- chunkSize
89
- )
90
- }
91
-
92
71
 
93
72
  }
94
73
 
@@ -137,7 +137,7 @@ export function handleError<T>(data: T[] | null, error: PostgrestError | null):
137
137
 
138
138
 
139
139
 
140
- const _filterBuilder = supabase.from('DEMO').select()
140
+ const _filterBuilder = supabase.from('DEMO').select().eq('','').order('f').limit(3)
141
141
  export type PostgrestFilterBuilder = typeof _filterBuilder
142
142
 
143
143