Icontem

File: lib-js/xbskey.js

Recommend this page to a friend!
  Classes of Alexey Znaev  >  XBSDB  >  lib-js/xbskey.js  >  Download  
File: lib-js/xbskey.js
Role: Class source
Content type: text/plain
Description: Key class
Class: XBSDB
Manipulate arrays with an SQL-like language
Author: By
Last change: changed Listing priority
Date: 8 years ago
Size: 17,344 bytes
 

Contents

Class file image Download
///////////////////////////////////////////////////////////////////////////
//
//    XBSDB - Cross-Browser JavaScript Database library
//    Copyright (C) 2010 Alexey A.Znayev
//
//    This file is part of XBSDB.
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
//    Alexey A.Znayev, znaeff@mail.ru
//
///////////////////////////////////////////////////////////////////////////

// This flie contains private class(es) and/or method(s) and may be changed any time

///////////////////////////////////////////////////////////////////////////
// simple index
function XBSKey(oTable,sExprFieldsX,oFields){
 this.sResultCode = 'OK';

 this.oTable = oTable; //object - table
 this.sKeyFunction = sExprFieldsX; //correct expression for key value calculation
 this.oFields = oFields; //object - used fields hash

 this._aNumbersInit = new Array(); // initial sorted packed array of numbers
 this._fIterator = new Function("table", "n", "return(" + this.sKeyFunction + ");"); // function - index expression
 this._aNumbers; // working link
}

XBSKey.prototype.Rebuild = function(aExtNumbers){
// index rebuilding
 this.sResultCode = 'OK';
 var aNumbers;
 if(aExtNumbers){
  aNumbers = aExtNumbers;
 }else{
  aNumbers = this.oTable.GetRecordsAllPacked();
 }
 var nNumbers = aNumbers.length;
 if(nNumbers > 0){
  var fIterator = this._fIterator;
  var oTable = this.oTable;
  try{
   aNumbers.sort(function(n1,n2){
			var value1 = fIterator(oTable,n1);
			var value2 = fIterator(oTable,n2);
			if(value1 < value2){
			    return -1;
			}else if(value1 > value2){
			    return 1;
			}else{
			    return 0;
			}
		    }
   );
  }catch(e){
   this.sResultCode = 'KEY_NOT_BUILDED_UNKNOWN';
   return false;
  }
  if(aNumbers && aNumbers.length == nNumbers){
   if(aExtNumbers){
    aExtNumbers = aNumbers;
   }else{
    this._aNumbersInit = aNumbers;
   }
  }else{
   this.sResultCode = 'KEY_NOT_BUILDED_FULL';
   return false;
  }
 }
 return true;
}

XBSKey.prototype.Load = function(aNumbersInit){
// index loading
 this.sResultCode = 'OK';
 this._aNumbersInit = aNumbersInit; // initial sorted packed array of numbers - loaded (no checking)
 return true;
}

///////////////////////////////////////////////////////////////////////
// next:
// aUpperNumbers - not packed array for upped level records to cutt off result
// aExtNumbers - packed array of external records to seek in (maybe result of previous seek in this index)

///////////////////////////////////////////////////////////////////////
// EQ
XBSKey.prototype.GetRecordsUnpackedEQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records == value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstEQ(v);
  if(iFirst >= 0){
   var iLast = this._GetIndexLastEQ(v);
   if(iLast >= iFirst){
    if(aUpperNumbers){
     for(i=iFirst; i<=iLast; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes[this._aNumbers[i]] = true;
      }
     }
    }else{
     for(i=iFirst; i<=iLast; i++){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }else{
    this.sResultCode = 'KEY_RANGE_LOW_GR_HIGH';
    return false;
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedEQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records == value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstEQ(v);
  if(iFirst >= 0){
   var iLast = this._GetIndexLastEQ(v);
   if(iLast >= iFirst){
    if(aUpperNumbers){
     for(i=iFirst; i<=iLast; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes.push(this._aNumbers[i]);
      }
     }
    }else{
     for(i=iFirst; i<=iLast; i++){
      aRes.push(this._aNumbers[i]);
     }
    }
   }else{
    this.sResultCode = 'KEY_RANGE_LOW_GR_HIGH';
    return false;
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// NE
XBSKey.prototype.GetRecordsUnpackedNE = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records != value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexLastLE(v);
  if(aUpperNumbers){
   for(i=0; i<=iFirst; i++){
    if(aUpperNumbers[this._aNumbers[i]]){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }else{
   for(i=0; i<=iFirst; i++){
    aRes[this._aNumbers[i]] = true;
   }
  }
  var iLast = this._GetIndexFirstGR(v);
  if(iLast > iFirst){ // not '>=' !
   if(aUpperNumbers){
    for(i=iLast; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }else{
    for(i=iLast; i<this._aNumbers.length; i++){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }else{
   if(iLast > 0){
    this.sResultCode = 'KEY_RANGE_LOW_GREQ_HIGH';
    return false;
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedNE = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records != value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexLastLE(v);
  if(aUpperNumbers){
   for(i=0; i<=iFirst; i++){
    if(aUpperNumbers[this._aNumbers[i]]){
     aRes.push(this._aNumbers[i]);
    }
   }
  }else{
   for(i=0; i<=iFirst; i++){
    aRes.push(this._aNumbers[i]);
   }
  }
  var iLast = this._GetIndexFirstGR(v);
  if(iLast > iFirst){ // not '>=' !
   if(aUpperNumbers){
    for(i=iLast; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes.push(this._aNumbers[i]);
     }
    }
   }else{
    for(i=iLast; i<this._aNumbers.length; i++){
     aRes.push(this._aNumbers[i]);
    }
   }
  }else{
   if(iLast > 0){
    this.sResultCode = 'KEY_RANGE_LOW_GREQ_HIGH';
    return false;
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// LE
XBSKey.prototype.GetRecordsUnpackedLE = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records < value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
 var iLast = this._GetIndexLastLE(v);
  if(aUpperNumbers){
   for(i=0; i<=iLast; i++){
    if(aUpperNumbers[this._aNumbers[i]]){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }else{
   for(i=0; i<=iLast; i++){
    aRes[this._aNumbers[i]] = true;
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedLE = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records < value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iLast = this._GetIndexLastLE(v);
  if(aUpperNumbers){
   for(i=0; i<=iLast; i++){
    if(aUpperNumbers[this._aNumbers[i]]){
     aRes.push(this._aNumbers[i]);
    }
   }
  }else{
   for(i=0; i<=iLast; i++){
    aRes.push(this._aNumbers[i]);
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// LEEQ
XBSKey.prototype.GetRecordsUnpackedLEEQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records <= value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iLast = this._GetIndexLastEQ(v);
  if(iLast >= 0){
   if(aUpperNumbers){
    for(i=0; i<=iLast; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }else{
    for(i=0; i<=iLast; i++){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }else{
   iLast = this._GetIndexLastLE(v);
   if(iLast >= 0){
    if(aUpperNumbers){
     for(i=0; i<=iLast; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes[this._aNumbers[i]] = true;
      }
     }
    }else{
     for(i=0; i<=iLast; i++){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedLEEQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records <= value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iLast = this._GetIndexLastEQ(v);
  if(iLast >= 0){
   if(aUpperNumbers){
    for(i=0; i<=iLast; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes.push(this._aNumbers[i]);
     }
    }
   }else{
    for(i=0; i<=iLast; i++){
     aRes.push(this._aNumbers[i]);
    }
   }
  }else{
   iLast = this._GetIndexLastLE(v);
   if(iLast >= 0){
    if(aUpperNumbers){
     for(i=0; i<=iLast; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes.push(this._aNumbers[i]);
      }
     }
    }else{
     for(i=0; i<=iLast; i++){
      aRes.push(this._aNumbers[i]);
     }
    }
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// GR
XBSKey.prototype.GetRecordsUnpackedGR = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records > value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstGR(v);
  if(iFirst >= 0){
   if(aUpperNumbers){
    for(i=iFirst; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }else{
    for(i=iFirst; i<this._aNumbers.length; i++){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedGR = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records > value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstGR(v);
  if(iFirst >= 0){
   if(aUpperNumbers){ 
    for(i=iFirst; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes.push(this._aNumbers[i]);
     }
    }
   }else{
    for(i=iFirst; i<this._aNumbers.length; i++){
     aRes.push(this._aNumbers[i]);
    }
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// GREQ
XBSKey.prototype.GetRecordsUnpackedGREQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records >= value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstEQ(v);
  if(iFirst >= 0){
   if(aUpperNumbers){
    for(i=iFirst; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }else{
    for(i=iFirst; i<this._aNumbers.length; i++){
     aRes[this._aNumbers[i]] = true;
    }
   }
  }else{
   iFirst = this._GetIndexFirstGR(v);
   if(iFirst >= 0){
    if(aUpperNumbers){
     for(i=iFirst; i<this._aNumbers.length; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes[this._aNumbers[i]] = true;
      }
     }
    }else{
     for(i=iFirst; i<this._aNumbers.length; i++){
      aRes[this._aNumbers[i]] = true;
     }
    }
   }
  }
 }
 return aRes;
}

XBSKey.prototype.GetRecordsPackedGREQ = function(v,aUpperNumbers,aExtNumbers){
// getting of array or records >= value
// v - key value
// this.sResultCode = 'OK';
 var aRes = new Array(), i;
 if(aExtNumbers){
  this._aNumbers = aExtNumbers;
 }else{
  this._aNumbers = this._aNumbersInit;
 }
 if(this._aNumbers.length > 0){
  var iFirst = this._GetIndexFirstEQ(v);
  if(iFirst >= 0){
   if(aUpperNumbers){
    for(i=iFirst; i<this._aNumbers.length; i++){
     if(aUpperNumbers[this._aNumbers[i]]){
      aRes.push(this._aNumbers[i]);
     }
    }
   }else{
    for(i=iFirst; i<this._aNumbers.length; i++){
     aRes.push(this._aNumbers[i]);
    }
   }
  }else{
   iFirst = this._GetIndexFirstGR(v);
   if(iFirst >= 0){
    if(aUpperNumbers){
     for(i=iFirst; i<this._aNumbers.length; i++){
      if(aUpperNumbers[this._aNumbers[i]]){
       aRes.push(this._aNumbers[i]);
      }
     }
    }else{
     for(i=iFirst; i<this._aNumbers.length; i++){
      aRes.push(this._aNumbers[i]);
     }
    }
   }
  }
 }
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// next:
// private methods

///////////////////////////////////////////////////////////////////////
// next:
// base methods to find 'fork' of 2 index numbers that have value existing border between

XBSKey.prototype._GetIndexFirstFork = function(v){
// seek of first index fork
// - iterator(i1) < v, iterator(i2) >= v)
// v - key value
 var b1 = 0, b2 = this._aNumbers.length - 1, bx = 0, aRes = new Array();
 var dbx = Math.floor((b2 - b1)/2);
 do{
  bx += dbx;
  var v_bx = this._fIterator(this.oTable,this._aNumbers[bx]);
  if(v_bx < v){ b1 = bx; dbx = Math.floor((b2 - b1)/2); }
  else { b2 = bx; dbx = 0 - Math.floor((b2 - b1)/2); }
 }while(b2 - b1 > 1);
 aRes[0] = b1;
 aRes[1] = b2;
 return aRes;
}

XBSKey.prototype._GetIndexLastFork = function(v){
// seek of last index fork
// - iterator(i1) <= v, iterator(i2) > v)
// v - key value
 var b1 = 0, b2 = this._aNumbers.length - 1, bx = 0, aRes = new Array();
 var dbx = Math.floor((b2 - b1)/2);
 do{
  bx += dbx;
  var v_bx = this._fIterator(this.oTable,this._aNumbers[bx]);
  if(v_bx <= v){ b1 = bx; dbx = Math.floor((b2 - b1)/2); }
  else { b2 = bx; dbx = 0 - Math.floor((b2 - b1)/2); }
 }while(b2 - b1 > 1);
 aRes[0] = b1;
 aRes[1] = b2;
 return aRes;
}

///////////////////////////////////////////////////////////////////////
// next:
// base methods to find first and last index numbers depending of condition

XBSKey.prototype._GetIndexFirstEQ = function(v){
// seek of first index number of record value equal given value
// v - key value
 var aFork = this._GetIndexFirstFork(v);
 if(aFork){
  if( this._fIterator(this.oTable,this._aNumbers[aFork[0]]) == v ) { return aFork[0]; }
  if( this._fIterator(this.oTable,this._aNumbers[aFork[1]]) == v ) { return aFork[1]; }
 }
 return -1;
}

XBSKey.prototype._GetIndexLastEQ = function(v){
// seek of last index number of record value equal given value
// v - key value
 var aFork = this._GetIndexLastFork(v);
 if(aFork){
  if( this._fIterator(this.oTable,this._aNumbers[aFork[1]]) == v ) { return aFork[1]; }
  if( this._fIterator(this.oTable,this._aNumbers[aFork[0]]) == v ) { return aFork[0]; }
 }
 return -1;
}

XBSKey.prototype._GetIndexFirstGR = function(v){
// seek of first index number of record value greater than given value
// v - key value
 var aFork = this._GetIndexLastFork(v);
 if(aFork){
  if( this._fIterator(this.oTable,this._aNumbers[aFork[0]]) > v ) { return aFork[0]; }
  if( this._fIterator(this.oTable,this._aNumbers[aFork[1]]) > v ) { return aFork[1]; }
 }
 return -1;
}

XBSKey.prototype._GetIndexLastLE = function(v){
// seek of last index number of record value less than given value
// v - key value
 var aFork = this._GetIndexFirstFork(v);
 if(aFork){
  if( this._fIterator(this.oTable,this._aNumbers[aFork[1]]) < v ) { return aFork[1]; }
  if( this._fIterator(this.oTable,this._aNumbers[aFork[0]]) < v ) { return aFork[0]; }
 }
 return -1;
}