@@ -27,7 +27,6 @@ import {
27
27
bucketSort ,
28
28
populateForeignKeys ,
29
29
setPopulateOptions ,
30
- intersect ,
31
30
getFileSize ,
32
31
deepMerge ,
33
32
ExaId ,
@@ -42,7 +41,7 @@ export class GLOBAL_OBJECT {
42
41
static RCT : Record < string , Record < string , Msgs | undefined > | boolean > = {
43
42
none : false , //? none is default for use with identifiers that has no need to cache
44
43
} ;
45
- static _db : any ;
44
+ static db : any ;
46
45
static rct_level : number ;
47
46
}
48
47
@@ -114,10 +113,10 @@ export class ExaSchema<Model> {
114
113
} else {
115
114
throw new ExaError ( "No table name provided!" ) ;
116
115
}
117
- if ( ! GLOBAL_OBJECT . _db ) {
116
+ if ( ! GLOBAL_OBJECT . db ) {
118
117
throw new ExaError ( "database has not yet been created!" ) ;
119
118
}
120
- GLOBAL_OBJECT . _db . induce ( this ) ;
119
+ GLOBAL_OBJECT . db . induce ( this ) ;
121
120
}
122
121
}
123
122
@@ -158,7 +157,7 @@ export class Manager {
158
157
}
159
158
}
160
159
constructRelationships ( ) {
161
- const allSchemas : ExaSchema < { } > [ ] = GLOBAL_OBJECT . _db . schemas ;
160
+ const allSchemas : ExaSchema < { } > [ ] = GLOBAL_OBJECT . db . schemas ;
162
161
if ( this . schema . table ) {
163
162
//? keep a easy track of relationships
164
163
if ( this . schema . relationship ) {
@@ -195,7 +194,7 @@ export class Manager {
195
194
}
196
195
this . isRelatedConstructed = true ;
197
196
}
198
- async _synchronize ( ) {
197
+ async synchronize ( ) {
199
198
try {
200
199
const dir = await opendir ( this . tableDir ! ) ;
201
200
const logFiles : string [ ] = [ ] ;
@@ -229,8 +228,7 @@ export class Manager {
229
228
for ( const filename in this . LogFiles ) {
230
229
const logFile = this . LogFiles [ filename ] ;
231
230
//? size check is for inserts
232
- // //? 3142656
233
- if ( logFile . size < 124 /*3mb*/ ) {
231
+ if ( logFile . size < 3142656 /*3mb*/ ) {
234
232
return filename ;
235
233
}
236
234
}
@@ -280,7 +278,7 @@ export class Manager {
280
278
} else {
281
279
// ? update search index
282
280
if ( flag === "d" ) {
283
- await this . xIndex . removeIndex ( message , file ) ;
281
+ await this . xIndex . removeIndex ( message , file , true ) ;
284
282
} else {
285
283
await this . xIndex . createIndex ( message ) ;
286
284
}
@@ -318,44 +316,33 @@ export class Manager {
318
316
}
319
317
return RCTied ;
320
318
}
321
- const file = this . xIndex . log_search ( id as string ) || "LOG-1" ;
319
+ const file = this . xIndex . log_search ( id ) ;
322
320
let RCTied = this . RCT [ file ] ;
323
321
if ( ! RCTied ) {
324
322
RCTied = await loadLog ( this . tableDir + file ) ;
325
323
this . RCT [ file ] = RCTied ;
326
324
}
327
325
return RCTied ;
328
326
}
329
- async _find ( query : QueryType < Record < string , any > > ) {
327
+ async find ( query : QueryType < Record < string , any > > ) {
330
328
let RCTied = await this . getLog ( query . one ) ;
331
329
if ( query . many ) {
332
- // ? skip results
333
- if ( query . skip && query . skip < RCTied . length ) {
334
- RCTied = RCTied . slice ( query . skip ) ;
335
- }
330
+ const skip = query . skip || 0 ;
336
331
const take = query . take || 1000 ;
337
- if ( RCTied . length > take ) {
338
- RCTied = RCTied . slice ( 0 ) ;
339
- } else {
340
- const logsCount = Object . keys ( this . LogFiles ) . length ;
341
- let log = 2 ;
342
- for ( ; RCTied . length < take ; ) {
343
- // ? break an endless loop.
344
- if ( log > logsCount ) {
345
- break ;
346
- }
347
- const RCTied2 = await this . getLog ( undefined , log ) ;
348
- Array . prototype . push . apply ( RCTied , RCTied2 ) ;
349
- if ( query . skip && query . skip < RCTied . length ) {
350
- RCTied = RCTied . slice ( query . skip ) ;
332
+ let result : any [ ] = [ ] ;
333
+ for ( let log = 1 ; log <= Object . keys ( this . LogFiles ) . length ; log ++ ) {
334
+ const RCTied = await this . getLog (
335
+ log === 1 ? query . one : undefined ,
336
+ log
337
+ ) ;
338
+ for ( let i = 0 ; i < RCTied . length && result . length < take ; i ++ ) {
339
+ if ( i >= skip ) {
340
+ result . push ( RCTied [ i ] ) ;
351
341
}
352
- log += 1 ;
353
- }
354
- if ( RCTied . length > take ) {
355
- RCTied = RCTied . slice ( 0 ) ;
356
342
}
343
+ if ( result . length >= take ) break ;
357
344
}
358
- // ? cutdown results
345
+ RCTied = result ;
359
346
// ? sort results using bucketed merge.sort algorithm
360
347
if ( query . sort ) {
361
348
const key = Object . keys ( query . sort ) [ 0 ] as "_id" ;
@@ -388,14 +375,14 @@ export class Manager {
388
375
}
389
376
async runner ( query : QueryType < Msg > ) : Promise < Msg | Msgs | number | void > {
390
377
if ( query . many || query . one ) {
391
- return this . _find ( query ) ;
378
+ return this . find ( query ) ;
392
379
}
393
380
if ( query [ "search" ] ) {
394
381
const indexes = this . xIndex . search ( query . search as Msg , query . take ) ;
395
382
const searches = await Promise . all (
396
383
indexes . map (
397
384
( _id : string ) =>
398
- this . _find ( {
385
+ this . find ( {
399
386
one : _id ,
400
387
populate : query . populate ,
401
388
sort : query . sort ,
@@ -455,6 +442,12 @@ export class Manager {
455
442
const file = this . xIndex . log_search ( message . _id ) ;
456
443
if ( typeof file !== "string" )
457
444
throw new ExaError ( "item to update not found" ) ;
445
+ const oldMessage = ( await this . find ( { one : query . update . _id } ) ) as Msg ;
446
+ if ( ! oldMessage ) {
447
+ throw new ExaError ( "item to update not found" ) ;
448
+ } else {
449
+ await this . xIndex . removeIndex ( oldMessage , file , false ) ;
450
+ }
458
451
// ? conserve foreign relationships
459
452
await conserveForeignKeys ( message , this . schema . foreign_field ) ;
460
453
return this . queue ( file , message , "u" ) ;
@@ -473,8 +466,7 @@ export class Manager {
473
466
if ( typeof file !== "string" )
474
467
throw new ExaError ( "item to delete not found" ) ;
475
468
476
- const message = ( await this . _find ( { one : query . delete } ) ) as Msg ;
477
-
469
+ const message = ( await this . find ( { one : query . delete } ) ) as Msg ;
478
470
if ( ! message ) {
479
471
throw new ExaError ( "item to delete not found" ) ;
480
472
}
@@ -516,30 +508,28 @@ export class XTree {
516
508
this . indexTable = init . indexTable ;
517
509
}
518
510
search ( search : Msg , take : number = Infinity ) {
519
- let idx : string [ ] = [ ] ;
520
511
const Indexes : number [ ] [ ] = [ ] ;
521
- // ? get the search keys
522
512
for ( const key in search ) {
523
- if ( ! this . indexTable [ key ] ) continue ;
524
- if ( this . tree [ key ] ) {
525
- const index = this . tree [ key ] . map [ search [ key as "_id" ] ] ;
526
- if ( ! index || index ?. length === 0 ) continue ;
527
- Indexes . push ( index ) ;
528
- if ( idx . length >= take ) break ;
529
- }
513
+ const index = this . tree [ key ] ?. map [ search [ key as "_id" ] ] ;
514
+ if ( index ?. length ) Indexes . push ( index ) ;
530
515
}
531
- // ? get return the keys if the length is 1
532
- if ( Indexes . length === 1 ) {
533
- return Indexes [ 0 ] . map ( ( idx ) => this . keys [ idx ] ) ;
516
+ if ( Indexes . length === 0 ) return [ ] ;
517
+ const result = new Set < number > ( ) ;
518
+ const smallestIndex = Indexes . reduce ( ( a , b ) =>
519
+ a . length < b . length ? a : b
520
+ ) ;
521
+ for ( const id of smallestIndex ) {
522
+ if ( Indexes . every ( ( index ) => index . includes ( id ) ) ) {
523
+ result . add ( id ) ;
524
+ if ( result . size >= take ) break ;
525
+ }
534
526
}
535
- // ? get return the keys if the length is more than one
536
- return intersect ( Indexes ) . map ( ( idx ) => this . keys [ idx ] ) ;
527
+ return Array . from ( result ) . map ( ( idx ) => this . keys [ idx ] ) ;
537
528
}
538
- // ? for keep _id indexes and possibly unique indexes on the XTree algorithm
539
- log_search ( id : string ) {
540
- // ? remove log tree index
529
+ log_search ( id : string = "" ) {
541
530
const logKey = this . tree [ "_exa_log_index" ] . map ?. [ id ] ;
542
531
if ( logKey ) return this . logKeys [ logKey [ 0 ] ] ;
532
+ return " LOG-1" ;
543
533
}
544
534
count ( search : Msg ) {
545
535
let resultsCount : number = 0 ;
@@ -557,15 +547,10 @@ export class XTree {
557
547
let logKey = this . logKeys . indexOf ( logFile ) ;
558
548
if ( logKey === - 1 ) {
559
549
logKey = this . logKeys . push ( logFile ) - 1 ;
560
- if ( ! this . tree [ "_exa_log_index" ] ) {
561
- this . tree [ "_exa_log_index" ] = new XNode ( ) ;
562
- }
563
550
}
564
551
// ? index it log file
565
552
this . tree [ "_exa_log_index" ] . create ( data . _id , logKey ) ;
566
553
}
567
- //
568
- //
569
554
// ? retrieve msg key index
570
555
let idk = this . keys . indexOf ( data . _id ) ;
571
556
if ( idk === - 1 ) {
@@ -581,19 +566,20 @@ export class XTree {
581
566
}
582
567
return this . persist ( ) ;
583
568
}
584
- removeIndex ( data : Msg , logFile : string ) {
569
+ removeIndex ( data : Msg , logFile : string , drop : boolean ) {
585
570
// ? remove other attributes indexes
586
571
let idk = this . keys . indexOf ( data . _id ) ;
587
572
if ( idk === - 1 ) return ;
588
573
for ( const key in data ) {
589
574
if ( ! this . tree [ key ] ) continue ;
590
575
this . tree [ key ] . drop ( data [ key as "_id" ] , idk ) ;
591
576
}
592
-
593
- this . keys . splice ( idk , 1 ) ;
594
- // ? remove log tree index
595
- const logKey = this . logKeys . indexOf ( logFile ) ;
596
- this . tree [ "_exa_log_index" ] . drop ( data . _id , logKey ) ;
577
+ if ( drop ) {
578
+ this . keys . splice ( idk , 1 ) ;
579
+ // ? remove log tree index
580
+ const logKey = this . logKeys . indexOf ( logFile ) ;
581
+ this . tree [ "_exa_log_index" ] . drop ( data . _id , logKey ) ;
582
+ }
597
583
598
584
return this . persist ( ) ;
599
585
}
@@ -631,5 +617,8 @@ export class XTree {
631
617
this . tree [ key ] = new XNode ( tree [ key ] ) ;
632
618
}
633
619
}
620
+ if ( ! this . tree [ "_exa_log_index" ] ) {
621
+ this . tree [ "_exa_log_index" ] = new XNode ( ) ;
622
+ }
634
623
}
635
624
}
0 commit comments