@@ -7,7 +7,19 @@ import Version from '../version'
7
7
import { Traversable } from '../shared'
8
8
import { Mutation , Selector , QueryToken , PredicateProvider } from './modules'
9
9
import { dispose , contextTableName , fieldIdentifier , hiddenColName } from './symbols'
10
- import { forEach , clone , contains , tryCatch , hasOwn , getType , assert , assertValue , warn , isNonNullable } from '../utils'
10
+ import {
11
+ forEach ,
12
+ clone ,
13
+ contains ,
14
+ tryCatch ,
15
+ isException ,
16
+ hasOwn ,
17
+ getType ,
18
+ assert ,
19
+ assertValue ,
20
+ warn ,
21
+ isNonNullable ,
22
+ } from '../utils'
11
23
import { createPredicate , createPkClause , mergeTransactionResult , predicatableQuery , lfFactory } from './helper'
12
24
import { Relationship , RDBType , DataStoreType , LeafType , StatementType , JoinMode } from '../interface/enum'
13
25
import { SchemaDef , ColumnDef , ParsedSchema , Association , ScopedHandler } from '../interface'
@@ -28,6 +40,8 @@ const transactionErrorHandler = {
28
40
error : ( ) => warn ( `Execute failed, transaction is already marked for rollback.` ) ,
29
41
}
30
42
43
+ const tryCatchCreatePredicate = tryCatch ( createPredicate )
44
+
31
45
export class Database {
32
46
public static version = Version
33
47
@@ -46,14 +60,14 @@ export class Database {
46
60
private storedIds = new Set < string > ( )
47
61
private subscription : Subscription | null = null
48
62
49
- private findPrimaryKey = ( name : string ) => {
50
- return this . findSchema ( name ) ! . pk
51
- }
52
-
53
63
private findSchema = ( name : string ) : ParsedSchema => {
54
64
const schema = this . schemas . get ( name )
55
65
return assertValue ( schema , Exception . NonExistentTable , name )
56
66
}
67
+ private tryCatchFindPrimaryKey = tryCatch ( ( name : string ) => {
68
+ return this . findSchema ( name ) . pk
69
+ } )
70
+ private tryCatchFindSchema = tryCatch ( this . findSchema )
57
71
58
72
/**
59
73
* @method defineSchema
@@ -64,7 +78,7 @@ export class Database {
64
78
assert ( advanced , Exception . UnmodifiableTable )
65
79
66
80
const hasPK = Object . keys ( schema ) . some ( ( key : string ) => schema [ key ] . primaryKey === true )
67
- assert ( hasPK , Exception . PrimaryKeyNotProvided )
81
+ assert ( hasPK , Exception . PrimaryKeyNotProvided , { tableName } )
68
82
69
83
this . schemaDefs . set ( tableName , schema )
70
84
return this
@@ -104,14 +118,15 @@ export class Database {
104
118
assert ( ! this . connected , Exception . DatabaseIsNotEmpty )
105
119
106
120
const load = ( db : lf . Database ) => {
121
+ const findPrimaryKey = this . tryCatchFindPrimaryKey ( { call : 'load' , doThrow : true } )
107
122
forEach ( data . tables , ( entities : any [ ] , name : string ) => {
108
- const schema = this . findSchema ( name )
109
- entities . forEach ( ( entity : any ) => this . storedIds . add ( fieldIdentifier ( name , entity [ schema . pk ] ) ) )
123
+ const { unwrapped : pk } = findPrimaryKey ( name )
124
+ entities . forEach ( ( entity : any ) => this . storedIds . add ( fieldIdentifier ( name , entity [ pk ] ) ) )
110
125
} )
111
126
return db . import ( data ) . catch ( ( ) => {
112
127
forEach ( data . tables , ( entities : any [ ] , name : string ) => {
113
- const schema = this . findSchema ( name )
114
- entities . forEach ( ( entity : any ) => this . storedIds . delete ( fieldIdentifier ( name , entity [ schema . pk ] ) ) )
128
+ const { unwrapped : pk } = findPrimaryKey ( name )
129
+ entities . forEach ( ( entity : any ) => this . storedIds . delete ( fieldIdentifier ( name , entity [ pk ] ) ) )
115
130
} )
116
131
} )
117
132
}
@@ -126,7 +141,11 @@ export class Database {
126
141
127
142
insert < T > ( tableName : string , raw : T | T [ ] ) : Observable < ExecutorResult > {
128
143
const insert = ( db : lf . Database ) => {
129
- const schema = this . findSchema ( tableName )
144
+ const maybeSchema = this . tryCatchFindSchema ( { op : 'insert' } ) ( tableName )
145
+ if ( isException ( maybeSchema ) ) {
146
+ return throwError ( maybeSchema . unwrapped )
147
+ }
148
+ const schema = maybeSchema . unwrapped
130
149
const pk = schema . pk
131
150
const columnMapper = schema . mapper
132
151
const [ table ] = Database . getTables ( db , tableName )
@@ -180,20 +199,21 @@ export class Database {
180
199
return throwError ( Exception . InvalidType ( [ 'Object' , type ] ) )
181
200
}
182
201
183
- const [ schema , err ] = tryCatch < ParsedSchema > ( this . findSchema ) ( tableName )
184
- if ( err ) {
185
- return throwError ( err )
202
+ const maybeSchema = this . tryCatchFindSchema ( { op : 'update' } ) ( tableName )
203
+ if ( isException ( maybeSchema ) ) {
204
+ return throwError ( maybeSchema . unwrapped )
186
205
}
206
+ const schema = maybeSchema . unwrapped
187
207
188
208
const update = ( db : lf . Database ) => {
189
209
const entity = clone ( raw )
190
210
const [ table ] = Database . getTables ( db , tableName )
191
- const columnMapper = schema ! . mapper
211
+ const columnMapper = schema . mapper
192
212
const hiddenPayload = Object . create ( null )
193
213
194
214
columnMapper . forEach ( ( mapper , key ) => {
195
215
// cannot create a hidden column for primary key
196
- if ( ! hasOwn ( entity , key ) || key === schema ! . pk ) {
216
+ if ( ! hasOwn ( entity , key ) || key === schema . pk ) {
197
217
return
198
218
}
199
219
@@ -208,7 +228,7 @@ export class Database {
208
228
209
229
forEach ( mut , ( val , key ) => {
210
230
const column = table [ key ]
211
- if ( key === schema ! . pk ) {
231
+ if ( key === schema . pk ) {
212
232
warn ( `Primary key is not modifiable.` )
213
233
} else if ( ! column ) {
214
234
warn ( `Column: ${ key } is not existent on table:${ tableName } ` )
@@ -223,24 +243,25 @@ export class Database {
223
243
}
224
244
225
245
delete < T > ( tableName : string , clause : Predicate < T > = { } ) : Observable < ExecutorResult > {
226
- const [ pk , err ] = tryCatch < string > ( this . findPrimaryKey ) ( tableName )
227
- if ( err ) {
228
- return throwError ( err )
246
+ const maybePK = this . tryCatchFindPrimaryKey ( { op : 'delete' } ) ( tableName )
247
+ if ( isException ( maybePK ) ) {
248
+ return throwError ( maybePK . unwrapped )
229
249
}
250
+ const pk = maybePK . unwrapped
230
251
231
252
const deletion = ( db : lf . Database ) : Observable < ExecutorResult > => {
232
253
const [ table ] = Database . getTables ( db , tableName )
233
- const column = table [ pk ! ]
254
+ const column = table [ pk ]
234
255
const provider = new PredicateProvider ( table , clause )
235
256
const prefetch = predicatableQuery ( db , table , provider . getPredicate ( ) , StatementType . Select , column )
236
257
const deleteByScopedIds = ( scopedIds : Object [ ] ) => {
237
258
const query = predicatableQuery ( db , table , provider . getPredicate ( ) , StatementType . Delete )
238
259
239
- scopedIds . forEach ( ( entity ) => this . storedIds . delete ( fieldIdentifier ( tableName , entity [ pk ! ] ) ) )
260
+ scopedIds . forEach ( ( entity ) => this . storedIds . delete ( fieldIdentifier ( tableName , entity [ pk ] ) ) )
240
261
241
262
const onError = {
242
263
error : ( ) => {
243
- scopedIds . forEach ( ( entity : object ) => this . storedIds . add ( fieldIdentifier ( tableName , entity [ pk ! ] ) ) )
264
+ scopedIds . forEach ( ( entity : object ) => this . storedIds . add ( fieldIdentifier ( tableName , entity [ pk ] ) ) )
244
265
} ,
245
266
}
246
267
@@ -290,11 +311,12 @@ export class Database {
290
311
}
291
312
292
313
remove < T > ( tableName : string , clause : Clause < T > = { } ) : Observable < ExecutorResult > {
293
- const [ schema , err ] = tryCatch < ParsedSchema > ( this . findSchema ) ( tableName )
294
- if ( err ) {
295
- return throwError ( err )
314
+ const maybeSchema = this . tryCatchFindSchema ( { op : 'remove' } ) ( tableName )
315
+ if ( isException ( maybeSchema ) ) {
316
+ return throwError ( maybeSchema . unwrapped )
296
317
}
297
- const disposeHandler = schema ! . dispose
318
+ const schema = maybeSchema . unwrapped
319
+ const disposeHandler = schema . dispose
298
320
299
321
const remove = ( db : lf . Database ) => {
300
322
const [ table ] = Database . getTables ( db , tableName )
@@ -306,7 +328,7 @@ export class Database {
306
328
307
329
const removeByRootEntities = ( rootEntities : Object [ ] ) => {
308
330
rootEntities . forEach ( ( entity ) => {
309
- removedIds . push ( fieldIdentifier ( tableName , entity [ schema ! . pk ] ) )
331
+ removedIds . push ( fieldIdentifier ( tableName , entity [ schema . pk ] ) )
310
332
} )
311
333
312
334
const onError = {
@@ -470,6 +492,8 @@ export class Database {
470
492
// src: schemaDef; dest: uniques, indexes, primaryKey, nullable, associations, mapper
471
493
// no short-curcuiting
472
494
forEach ( schemaDef , ( def , key ) => {
495
+ const currentPK : string | undefined = primaryKey [ 0 ]
496
+
473
497
if ( typeof def === 'function' ) {
474
498
return
475
499
}
@@ -479,7 +503,7 @@ export class Database {
479
503
columns . set ( key , def . type as RDBType )
480
504
481
505
if ( def . primaryKey ) {
482
- assert ( ! primaryKey [ 0 ] , Exception . PrimaryKeyConflict )
506
+ assert ( ! currentPK , Exception . PrimaryKeyConflict , { tableName , currentPK , incomingPK : key } )
483
507
primaryKey . push ( key )
484
508
}
485
509
@@ -528,7 +552,10 @@ export class Database {
528
552
}
529
553
530
554
private buildSelector < T > ( db : lf . Database , tableName : string , clause : Query < T > , mode : JoinMode ) {
531
- const schema = this . findSchema ( tableName )
555
+ const { unwrapped : schema } = this . tryCatchFindSchema ( {
556
+ call : 'buildSelector' ,
557
+ doThrow : true ,
558
+ } ) ( tableName )
532
559
const pk = schema . pk
533
560
const containFields = ! ! clause . fields
534
561
@@ -616,7 +643,10 @@ export class Database {
616
643
context : Record = { } ,
617
644
mode : JoinMode ,
618
645
) {
619
- const schema = this . findSchema ( tableName )
646
+ const { unwrapped : schema } = this . tryCatchFindSchema ( {
647
+ call : 'traverseQueryFields' ,
648
+ doThrow : true ,
649
+ } ) ( tableName )
620
650
const rootDefinition = Object . create ( null )
621
651
const navigators : string [ ] = [ ]
622
652
@@ -664,10 +694,13 @@ export class Database {
664
694
} else {
665
695
const { where, type } = defs as Association
666
696
rootDefinition [ key ] = typeDefinition . revise ( type ! , ret . definition )
667
- const [ predicate , err ] = tryCatch ( createPredicate ) ( currentTable , where ( ret . table ) )
668
- if ( err ) {
669
- warn ( `Failed to build predicate, since ${ err . message } ` + `, on table: ${ ret . table . getName ( ) } ` )
697
+ const maybePredicate = tryCatchCreatePredicate ( {
698
+ tableName : ret . table . getName ( ) ,
699
+ } ) ( currentTable , where ( ret . table ) )
700
+ if ( isException ( maybePredicate ) ) {
701
+ warn ( `Failed to build predicate, since ${ maybePredicate . unwrapped . message } ` )
670
702
}
703
+ const predicate = maybePredicate . unwrapped
671
704
const joinLink = predicate ? [ { table : ret . table , predicate } , ...ret . joinInfo ] : ret . joinInfo
672
705
673
706
joinInfo . push ( ...joinLink )
@@ -750,10 +783,13 @@ export class Database {
750
783
return
751
784
}
752
785
753
- const schema = this . findSchema ( tableName )
786
+ const { unwrapped : schema } = this . tryCatchFindSchema ( {
787
+ call : 'traverseCompound' ,
788
+ doThrow : true ,
789
+ } ) ( tableName )
754
790
const pk = schema . pk
755
791
const pkVal = compoundEntites [ pk ]
756
- assert ( pkVal !== undefined , Exception . PrimaryKeyNotProvided )
792
+ assert ( pkVal !== undefined , Exception . PrimaryKeyNotProvided , { tableName , pk , entry : compoundEntites } )
757
793
758
794
const [ table ] = Database . getTables ( db , tableName )
759
795
const identifier = fieldIdentifier ( tableName , pkVal )
@@ -827,7 +863,10 @@ export class Database {
827
863
}
828
864
829
865
private navigatorLeaf ( assocaiation : Association , _ : string , val : any ) {
830
- const schema = this . findSchema ( assocaiation . name )
866
+ const { unwrapped : schema } = this . tryCatchFindSchema ( {
867
+ call : 'navigatorLeaf' ,
868
+ doThrow : true ,
869
+ } ) ( assocaiation . name )
831
870
const fields = typeof val === 'string' ? new Set ( schema . columns . keys ( ) ) : val
832
871
833
872
return {
@@ -839,7 +878,10 @@ export class Database {
839
878
840
879
private createScopedHandler < T > ( db : lf . Database , queryCollection : any [ ] , keys : any [ ] ) {
841
880
return ( tableName : string ) : ScopedHandler => {
842
- const pk = this . findPrimaryKey ( tableName )
881
+ const { unwrapped : pk } = this . tryCatchFindPrimaryKey ( {
882
+ call : 'createScopedHandler' ,
883
+ doThrow : true ,
884
+ } ) ( tableName )
843
885
844
886
const remove = ( entities : T [ ] ) => {
845
887
const [ table ] = Database . getTables ( db , tableName )
@@ -856,11 +898,14 @@ export class Database {
856
898
857
899
const get = ( where : Predicate < any > | null = null ) => {
858
900
const [ table ] = Database . getTables ( db , tableName )
859
- const [ predicate , err ] = tryCatch ( createPredicate ) ( table , where )
860
- if ( err ) {
861
- return throwError ( err )
901
+ const maybePredicate = tryCatchCreatePredicate ( {
902
+ call : 'createScopedHandler' ,
903
+ } ) ( table , where )
904
+ if ( isException ( maybePredicate ) ) {
905
+ return throwError ( maybePredicate . unwrapped )
862
906
}
863
- const query = predicatableQuery ( db , table , predicate ! , StatementType . Select )
907
+ const predicate = maybePredicate . unwrapped
908
+ const query = predicatableQuery ( db , table , predicate , StatementType . Select )
864
909
865
910
return from < T [ ] > ( query . exec ( ) as any )
866
911
}
0 commit comments