Advertisement
Uno-Dan

DBMagic

Mar 2nd, 2021
1,009
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.    
  2. const log = console.log;
  3.  
  4. const indexedDB = window.indexedDB || window.mozIndexedDB ||
  5.     window.webkitIndexedDB || window.msIndexedDB;
  6.    
  7. class Table {
  8.   constructor( db, name) {
  9.     this.db = db;
  10.     this.name = name;
  11.     this.debug = db.debug;
  12.     this.limitSize = 0;
  13.   }
  14.  
  15.   limit( limit ) {
  16.     this.limitSize = limit;
  17.     return this;
  18.   }
  19.  
  20.   orderby( keys, mode = 'asc' ) {
  21.     this.order = ( mode === 'asc' ? true : false );
  22.     this.orderby = Array.isArray( keys ) ? keys : [ keys ];
  23.     return this;
  24.   }
  25.  
  26.   async transaction( store, mode ) {    
  27.     const db = this.db.name;  
  28.    
  29.     return new Promise(( resolve, reject ) => {
  30.       let openReq = indexedDB.open( db );
  31.  
  32.       openReq.onerror = e => reject( e );
  33.  
  34.       openReq.onsuccess = () => {
  35.         const tx = openReq.result.transaction ( [ store ], mode );
  36.         resolve( tx );
  37.         openReq.result.close();
  38.       };
  39.     } );
  40.   }
  41.  
  42.   async add( args, opt=false ) {
  43.     const db = this.db.name;
  44.    
  45.     if ( ! Array.isArray( args ) ) args = [ args ];
  46.    
  47.     const stores = await this.db.stores();
  48.     const version = await this.db.version();
  49.     const create_store = ! stores.contains( this.name );
  50.    
  51.     let promise = false;
  52.    
  53.     if ( create_store ) {
  54.       promise = new Promise( ( resolve, reject ) => {
  55.         let req = indexedDB.open( db, version + 1 );
  56.        
  57.         req.onerror = e => {
  58.           reject( e )
  59.         };
  60.         req.onsuccess = () => { req.result.close(); resolve(); };
  61.         req.onupgradeneeded = () => {
  62.           req.result.createObjectStore( this.name, { keyPath: 'id' } );
  63.         };
  64.       } );
  65.     }
  66.    
  67.     if ( promise ) await promise;
  68.    
  69.     let promises = [];
  70.    
  71.     return new Promise( ( resolve, reject ) => {
  72.       args.forEach( item => { promises.push( this.que_add( item, opt ) ); } );
  73.       Promise.all( promises )
  74.       .then( () => resolve( this ) )
  75.       .catch( err => reject( err ) );
  76.     } );
  77.   }
  78.  
  79.   async get( args ) {
  80.     const sortColumns = ( arr, props, mode = true ) => {
  81.       if ( ! Array.isArray( props ) ) props = [ props ];
  82.      
  83.       const sorted = arr.sort( ( a, b ) => {
  84.         let prop = props[ 0 ];
  85.         for ( let idx = 0; idx < props.length; idx++ ) {
  86.           const curProp = props[ idx ];
  87.           if ( a[ curProp ] !== b[ curProp ] ) {
  88.             prop = curProp;
  89.             break;
  90.           }  
  91.         }  
  92.         if ( a[ prop ] === b[ prop ] ) return 0;
  93.           return ( a[ prop ] > b[ prop ] ? -1 : 1 ) * ( mode ? -1 : 1 );
  94.       } );  
  95.       return sorted;
  96.     };
  97.    
  98.     const db = this.db.name;
  99.     const stores = await this.db.stores();
  100.     if ( ! stores.contains( this.name ) ) return false;
  101.    
  102.     if ( ! Array.isArray( args ) ) args = [ args ];
  103.    
  104.     let promises = [];
  105.     return new Promise( ( resolve, reject ) => {
  106.       if ( args )
  107.         args.forEach( item => { promises.push( this.que_get( item) ); } );
  108.       else
  109.         promises.push( this.que_get() );
  110.              
  111.       Promise.all(promises)      
  112.       .then( results => {
  113.         if ( results.length ) {
  114.           if ( this.limitSize )
  115.             results = [ results[ 0 ].slice( 0, this.limitSize ) ];
  116.           results = sortColumns( results[ 0 ], this.orderby, this.order );
  117.         }
  118.         this.limitSize = 0;
  119.         resolve( results );
  120.       } )
  121.       .catch( err => reject( err ) );
  122.     } );
  123.   }
  124.          
  125.   async update( args ) {
  126.     const db = this.db.name;
  127.     const stores = await this.db.stores();
  128.     if ( ! stores.contains( this.name ) ) return false;
  129.    
  130.     let promises = [];
  131.    
  132.     return new Promise( ( resolve, reject ) => {
  133.      
  134.       args.forEach( item => { promises.push( this.que_update( item ) ); } );
  135.       Promise.all( promises )
  136.       .then( () => resolve( this ) )
  137.       .catch( err => reject( err ) );
  138.     } );
  139.   }
  140.  
  141.   async delete() {
  142.     const db = this.db.name;
  143.     const stores = await this.db.stores();
  144.     const version = await this.db.version();
  145.    
  146.     return new Promise( ( resolve, reject ) => {
  147.       var req = indexedDB.open( this.db.name, version + 1  );
  148.  
  149.         req.onerror = e => reject( e );
  150.  
  151.         req.onsuccess = ( ) => { req.result.close(); resolve( this ); };
  152.        
  153.         req.onupgradeneeded = () => {
  154.           req.result.deleteObjectStore( this.name );
  155.         };
  156.     } );
  157.   }
  158.  
  159.   async que_add( args, opt=false ) {
  160.     const db = this.db.name;
  161.     const tx = await this.transaction( [ this.name ], 'readwrite' );
  162.    
  163.     return new Promise(( resolve, reject ) => {
  164.       let addReq = tx.objectStore( this.name ).add( args );
  165.  
  166.       addReq.onerror = e => {
  167.         if ( this.debug ) {  
  168.           const err = opt ? 'WARN' : 'ERROR';
  169.           const msg = `[ ${ err }:add ], could not add key [${ args.id
  170.           }] in store [${  addReq.source.name }] in database [${ db }], ` +
  171.           e.target.error;
  172.           log( msg );
  173.         }
  174.         opt ? resolve( this ) : reject( e );  
  175.       };
  176.  
  177.       addReq.onsuccess = () => {  
  178.         if ( this.debug )
  179.           log( `[ INFO:add ], Added key [${ args.id }] in store [${
  180.           addReq.source.name }] in database [${ db }]` );
  181.         resolve( this );  
  182.       };
  183.     } );
  184.   }
  185.  
  186.   async que_get( args ) {
  187.     const db = this.db.name;
  188.     const tx = await this.transaction( [ this.name ], 'readonly' );
  189.    
  190.     return new Promise( ( resolve, reject ) => {
  191.       let obj = tx.objectStore( this.name );
  192.       let req = args ? obj.get( args.id ) : obj.getAll();
  193.       req.onerror = e => {
  194.         if ( this.debug )
  195.           log( `[ ERROR:getAll ], could not retrieve keys from store [${
  196.           req.source.name }] in database [${ db }]` );
  197.         reject( e );  
  198.       };
  199.  
  200.       req.onsuccess = () => {
  201.         if ( this.debug )
  202.           log( `[ INFO:getAll ], Retrieved all keys from store [${
  203.           req.source.name }] in database [${ db }]` );
  204.  
  205.         const result = ! Array.isArray( req.result ) ?
  206.         [ req.result ] : req.result;
  207.         resolve( result );  
  208.       };
  209.     } );
  210.   }
  211.  
  212.   async que_update( args ) {
  213.     const db = this.db.name;
  214.    
  215.     const values = await this.get( { id: args.id } );
  216.     if ( ! values.length ) return this;
  217.    
  218.     args = { ...values[0], ...args };
  219.  
  220.     const tx = await this.transaction( [ this.name ], 'readwrite' );
  221.     return new Promise(( resolve, reject ) => {
  222.         let addReq = tx.objectStore( this.name ).put( args );
  223.  
  224.         addReq.onerror = e => {
  225.           if ( this.debug )
  226.             log( `[ ERROR:add ], could not update key [${ args.id
  227.             }] in store [${ addReq.source.name }] in database [${ db }]` );
  228.           reject( e );  
  229.         };
  230.  
  231.         addReq.onsuccess = () => {  
  232.           if ( this.debug )
  233.             log( `[ INFO:update ], Updated key [${ args.id }] in store [${
  234.             addReq.source.name }] in database [${ db }]` );
  235.           resolve( this );  
  236.         };
  237.     } );
  238.   }
  239. }
  240.  
  241. export default class DBMagic {
  242.   constructor( name ) {
  243.     this.name = name;
  244.     this.debug = false;
  245.     this.tables = {};
  246.     this.init();
  247.   }
  248.  
  249.   init() {
  250.     Object.values( this.stores() ).forEach( name => this.table( name ) );
  251.   }
  252.  
  253.   table( name ) {
  254.     let args = {}
  255.     if ( ! ( name in this.tables ) ) {
  256.       this.tables[ name ] = new Table( this, name, args );
  257.     }
  258.     return this.tables[ name ];
  259.   }
  260.  
  261.   config( args ) {
  262.     for (var key in args )
  263.       this[ key ] = args[ key ];
  264.     return this;
  265.   }
  266.  
  267.   delete( args ) {
  268.     if ( args ) {
  269.       if ( ! Array.isArray( args ) ) args = [ args ];
  270.    
  271.       args.forEach( store => {
  272.         if ( store in this.tables ) {
  273.           this.tables[ store ].delete();
  274.           delete this.tables[ store ];
  275.         }
  276.       } );
  277.     } else {
  278.       return new Promise( ( resolve, reject ) => {
  279.         var req = indexedDB.deleteDatabase( this.name );
  280.  
  281.         req.onerror = err => { reject( err ); };
  282.  
  283.         req.onsuccess = () => {
  284.           if( this.debug )
  285.             log( '[INFO:delete], Deleted database [' + this.name + ']');
  286.          
  287.           this.tables = {};
  288.           resolve( this );
  289.         };
  290.       } );
  291.     }
  292.   }
  293.  
  294.   stores() {
  295.     return new Promise( ( resolve, reject ) => {
  296.       var req = indexedDB.open( this.name );
  297.  
  298.       req.onerror = err => { reject( err ); };
  299.  
  300.       req.onsuccess = () => {
  301.         let names = req.result.objectStoreNames;
  302.         if( this.debug )
  303.           log( '[INFO:db_version], Database [' + this.name +
  304.           '], version []');
  305.  
  306.         resolve( names );
  307.         req.result.close();
  308.       };
  309.      
  310.       req.onupgradeneeded = () => { return true; };
  311.     } );
  312.   }
  313.  
  314.   version() {
  315.     const db = this.name;
  316.     return new Promise( ( resolve, reject ) => {
  317.       var req = indexedDB.open( db );
  318.  
  319.       req.onerror = err => { reject( err ); };
  320.  
  321.       req.onsuccess = () => {
  322.         let version = req.result.version;
  323.         if( this.debug )
  324.           log( '[INFO:db_version], Database [' + db +
  325.           '], version [' + version + ']');
  326.  
  327.         req.result.close();
  328.         resolve( version );
  329.       };
  330.       req.onupgradeneeded = () => { return true; };
  331.     } );
  332.   }
  333. }
  334.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement