@@ -27,7 +27,6 @@ import {
2727 bucketSort ,
2828 populateForeignKeys ,
2929 setPopulateOptions ,
30- intersect ,
3130 getFileSize ,
3231 deepMerge ,
3332 ExaId ,
@@ -42,7 +41,7 @@ export class GLOBAL_OBJECT {
4241 static RCT : Record < string , Record < string , Msgs | undefined > | boolean > = {
4342 none : false , //? none is default for use with identifiers that has no need to cache
4443 } ;
45- static _db : any ;
44+ static db : any ;
4645 static rct_level : number ;
4746}
4847
@@ -114,10 +113,10 @@ export class ExaSchema<Model> {
114113 } else {
115114 throw new ExaError ( "No table name provided!" ) ;
116115 }
117- if ( ! GLOBAL_OBJECT . _db ) {
116+ if ( ! GLOBAL_OBJECT . db ) {
118117 throw new ExaError ( "database has not yet been created!" ) ;
119118 }
120- GLOBAL_OBJECT . _db . induce ( this ) ;
119+ GLOBAL_OBJECT . db . induce ( this ) ;
121120 }
122121}
123122
@@ -158,7 +157,7 @@ export class Manager {
158157 }
159158 }
160159 constructRelationships ( ) {
161- const allSchemas : ExaSchema < { } > [ ] = GLOBAL_OBJECT . _db . schemas ;
160+ const allSchemas : ExaSchema < { } > [ ] = GLOBAL_OBJECT . db . schemas ;
162161 if ( this . schema . table ) {
163162 //? keep a easy track of relationships
164163 if ( this . schema . relationship ) {
@@ -195,7 +194,7 @@ export class Manager {
195194 }
196195 this . isRelatedConstructed = true ;
197196 }
198- async _synchronize ( ) {
197+ async synchronize ( ) {
199198 try {
200199 const dir = await opendir ( this . tableDir ! ) ;
201200 const logFiles : string [ ] = [ ] ;
@@ -229,8 +228,7 @@ export class Manager {
229228 for ( const filename in this . LogFiles ) {
230229 const logFile = this . LogFiles [ filename ] ;
231230 //? size check is for inserts
232- // //? 3142656
233- if ( logFile . size < 124 /*3mb*/ ) {
231+ if ( logFile . size < 3142656 /*3mb*/ ) {
234232 return filename ;
235233 }
236234 }
@@ -280,7 +278,7 @@ export class Manager {
280278 } else {
281279 // ? update search index
282280 if ( flag === "d" ) {
283- await this . xIndex . removeIndex ( message , file ) ;
281+ await this . xIndex . removeIndex ( message , file , true ) ;
284282 } else {
285283 await this . xIndex . createIndex ( message ) ;
286284 }
@@ -318,44 +316,33 @@ export class Manager {
318316 }
319317 return RCTied ;
320318 }
321- const file = this . xIndex . log_search ( id as string ) || "LOG-1" ;
319+ const file = this . xIndex . log_search ( id ) ;
322320 let RCTied = this . RCT [ file ] ;
323321 if ( ! RCTied ) {
324322 RCTied = await loadLog ( this . tableDir + file ) ;
325323 this . RCT [ file ] = RCTied ;
326324 }
327325 return RCTied ;
328326 }
329- async _find ( query : QueryType < Record < string , any > > ) {
327+ async find ( query : QueryType < Record < string , any > > ) {
330328 let RCTied = await this . getLog ( query . one ) ;
331329 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 ;
336331 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 ] ) ;
351341 }
352- log += 1 ;
353- }
354- if ( RCTied . length > take ) {
355- RCTied = RCTied . slice ( 0 ) ;
356342 }
343+ if ( result . length >= take ) break ;
357344 }
358- // ? cutdown results
345+ RCTied = result ;
359346 // ? sort results using bucketed merge.sort algorithm
360347 if ( query . sort ) {
361348 const key = Object . keys ( query . sort ) [ 0 ] as "_id" ;
@@ -388,14 +375,14 @@ export class Manager {
388375 }
389376 async runner ( query : QueryType < Msg > ) : Promise < Msg | Msgs | number | void > {
390377 if ( query . many || query . one ) {
391- return this . _find ( query ) ;
378+ return this . find ( query ) ;
392379 }
393380 if ( query [ "search" ] ) {
394381 const indexes = this . xIndex . search ( query . search as Msg , query . take ) ;
395382 const searches = await Promise . all (
396383 indexes . map (
397384 ( _id : string ) =>
398- this . _find ( {
385+ this . find ( {
399386 one : _id ,
400387 populate : query . populate ,
401388 sort : query . sort ,
@@ -455,6 +442,12 @@ export class Manager {
455442 const file = this . xIndex . log_search ( message . _id ) ;
456443 if ( typeof file !== "string" )
457444 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+ }
458451 // ? conserve foreign relationships
459452 await conserveForeignKeys ( message , this . schema . foreign_field ) ;
460453 return this . queue ( file , message , "u" ) ;
@@ -473,8 +466,7 @@ export class Manager {
473466 if ( typeof file !== "string" )
474467 throw new ExaError ( "item to delete not found" ) ;
475468
476- const message = ( await this . _find ( { one : query . delete } ) ) as Msg ;
477-
469+ const message = ( await this . find ( { one : query . delete } ) ) as Msg ;
478470 if ( ! message ) {
479471 throw new ExaError ( "item to delete not found" ) ;
480472 }
@@ -516,30 +508,28 @@ export class XTree {
516508 this . indexTable = init . indexTable ;
517509 }
518510 search ( search : Msg , take : number = Infinity ) {
519- let idx : string [ ] = [ ] ;
520511 const Indexes : number [ ] [ ] = [ ] ;
521- // ? get the search keys
522512 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 ) ;
530515 }
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+ }
534526 }
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 ] ) ;
537528 }
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 = "" ) {
541530 const logKey = this . tree [ "_exa_log_index" ] . map ?. [ id ] ;
542531 if ( logKey ) return this . logKeys [ logKey [ 0 ] ] ;
532+ return " LOG-1" ;
543533 }
544534 count ( search : Msg ) {
545535 let resultsCount : number = 0 ;
@@ -557,15 +547,10 @@ export class XTree {
557547 let logKey = this . logKeys . indexOf ( logFile ) ;
558548 if ( logKey === - 1 ) {
559549 logKey = this . logKeys . push ( logFile ) - 1 ;
560- if ( ! this . tree [ "_exa_log_index" ] ) {
561- this . tree [ "_exa_log_index" ] = new XNode ( ) ;
562- }
563550 }
564551 // ? index it log file
565552 this . tree [ "_exa_log_index" ] . create ( data . _id , logKey ) ;
566553 }
567- //
568- //
569554 // ? retrieve msg key index
570555 let idk = this . keys . indexOf ( data . _id ) ;
571556 if ( idk === - 1 ) {
@@ -581,19 +566,20 @@ export class XTree {
581566 }
582567 return this . persist ( ) ;
583568 }
584- removeIndex ( data : Msg , logFile : string ) {
569+ removeIndex ( data : Msg , logFile : string , drop : boolean ) {
585570 // ? remove other attributes indexes
586571 let idk = this . keys . indexOf ( data . _id ) ;
587572 if ( idk === - 1 ) return ;
588573 for ( const key in data ) {
589574 if ( ! this . tree [ key ] ) continue ;
590575 this . tree [ key ] . drop ( data [ key as "_id" ] , idk ) ;
591576 }
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+ }
597583
598584 return this . persist ( ) ;
599585 }
@@ -631,5 +617,8 @@ export class XTree {
631617 this . tree [ key ] = new XNode ( tree [ key ] ) ;
632618 }
633619 }
620+ if ( ! this . tree [ "_exa_log_index" ] ) {
621+ this . tree [ "_exa_log_index" ] = new XNode ( ) ;
622+ }
634623 }
635624}
0 commit comments