2013-05-30 18:57:33 +00:00
/// <reference path="jquery-1.7.2.js" />
/// <reference path="indexeddb.shim.js" />
var linq2indexedDB ;
var enableLogging = false ;
// Initializes the linq2indexeddb object.
( function ( ) {
"use strict" ;
linq2indexedDB = function ( name , configuration , enableDebugging ) {
/// <summary>Creates a new or opens an existing database for the given name</summary>
/// <param name="name" type="String">The name of the database</param>
/// <param name="configuration" type="Object">
/// [Optional] provide comment
/// </param>
/// <returns type="linq2indexedDB" />
var dbConfig = {
autoGenerateAllowed : true
} ;
if ( name ) {
dbConfig . name = name ;
}
if ( configuration ) {
if ( configuration . version ) {
dbConfig . version = configuration . version ;
}
// From the moment the configuration is provided by the developper, autoGeneration isn't allowed.
// If this would be allowed, the developper wouldn't be able to determine what to do for which version.
if ( configuration . schema ) {
var appVersion = dbConfig . version || - 1 ;
for ( key in configuration . schema ) {
if ( typeof key === "number" ) {
appVersion = version > key ? version : key ;
}
}
if ( version > - 1 ) {
dbConfig . autoGenerateAllowed = false ;
dbConfig . version = appVersion ;
dbConfig . schema = configuration . schema ;
}
}
if ( configuration . definition ) {
dbConfig . autoGenerateAllowed = false ;
dbConfig . definition = configuration . definition ;
}
if ( configuration . onupgradeneeded ) {
dbConfig . autoGenerateAllowed = false ;
dbConfig . onupgradeneeded = configuration . onupgradeneeded ;
}
if ( configuration . oninitializeversion ) {
dbConfig . autoGenerateAllowed = false ;
dbConfig . oninitializeversion = configuration . oninitializeversion ;
}
}
var returnObject = {
utilities : linq2indexedDB . prototype . utilities ,
core : linq2indexedDB . prototype . core ,
linq : linq ( dbConfig ) ,
initialize : function ( ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Initialize Started" ) ;
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
linq2indexedDB . prototype . core . db ( dbConfig . name , dbConfig . version ) . then ( function ( args ) /*db*/ {
var db = args [ 0 ] ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Close dbconnection" ) ;
db . close ( ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Initialize Succesfull" ) ;
pw . complete ( ) ;
} , pw . error , function ( args ) /*txn, e*/ {
var txn = args [ 0 ] ;
var e = args [ 1 ] ;
if ( e . type == "upgradeneeded" ) {
upgradeDatabase ( dbConfig , e . oldVersion , e . newVersion , txn ) ;
}
} ) ;
} ) ;
} ,
deleteDatabase : function ( ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
linq2indexedDB . prototype . core . deleteDb ( dbConfig . name ) . then ( function ( ) {
pw . complete ( ) ;
} , pw . error ) ;
} ) ;
}
} ;
enableLogging = enableDebugging ;
if ( enableDebugging ) {
returnObject . viewer = viewer ( dbConfig ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . warning , "Debugging enabled: be carefull when using in production enviroment. Complex objects get written to the log and may cause memory leaks." )
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
} else {
returnObject . viewer = null ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
return returnObject ;
} ;
function linq ( dbConfig ) {
var queryBuilderObj = function ( objectStoreName ) {
this . from = objectStoreName ;
this . where = [ ] ;
this . select = [ ] ;
this . sortClauses = [ ] ;
this . get = [ ] ;
this . insert = [ ] ;
this . merge = [ ] ;
this . update = [ ] ;
this . remove = [ ] ;
this . clear = false ;
} ;
queryBuilderObj . prototype = {
executeQuery : function ( ) {
executeQuery ( this ) ;
}
} ;
function from ( queryBuilder , objectStoreName ) {
queryBuilder . from = objectStoreName ;
return {
where : function ( filter ) {
/// <summary>Filters the selected data.</summary>
/// <param name="filter">
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
///</param>
return where ( queryBuilder , filter , true , false ) ;
} ,
orderBy : function ( propertyName ) {
/// <summary>Sorts the selected data ascending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , false ) ;
} ,
orderByDesc : function ( propertyName ) {
/// <summary>Sorts the selected data descending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , true ) ;
} ,
select : function ( propertyNames ) {
/// <summary>Selects the data.</summary>
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
/// <returns type="Array">A list with the selected objects.</returns>
return select ( queryBuilder , propertyNames ) ;
} ,
insert : function ( data , key ) {
/// <summary>inserts data.</summary>
/// <param name="data" type="Object">The object you want to insert.</param>
/// <param name="key" type="Object">
/// [Optional] The key of the data you want to insert.
/// </param>
/// <returns type="Object">The object that was inserted.</returns>
return insert ( queryBuilder , data , key ) ;
} ,
update : function ( data , key ) {
/// <summary>updates data.</summary>
/// <param name="data" type="Object">The object you want to update.</param>
/// <param name="key" type="Object">
/// [Optional] The key of the data you want to update.
/// </param>
/// <returns type="Object">The object that was updated.</returns>
return update ( queryBuilder , data , key ) ;
} ,
merge : function ( data , key ) {
/// <summary>merges data.</summary>
/// <param name="data" type="Object">The data you want to merge.</param>
/// <param name="key" type="Object">
/// The key of the data you want to update.
/// </param>
/// <returns type="Object">The object that was updated.</returns>
return merge ( queryBuilder , data , key ) ;
} ,
remove : function ( key ) {
/// <summary>Removes data from the objectstore by his key.</summary>
/// <param name="key" type="Object">The key of the object you want to remove.</param>
return remove ( queryBuilder , key ) ;
} ,
clear : function ( ) {
/// <summary>Removes all data from the objectstore.</summary>
return clear ( queryBuilder ) ;
} ,
get : function ( key ) {
/// <summary>Gets an object by his key.</summary>
/// <param name="key" type="Object">The key of the object you want to retrieve.</param>
/// <returns type="Object">The object that has the provided key.</returns>
return get ( queryBuilder , key ) ;
}
} ;
}
function where ( queryBuilder , filter , isAndClause , isOrClause , isNotClause ) {
var whereClauses = { } ;
var filterMetaData ;
if ( isNotClause === "undefined" ) {
whereClauses . not = function ( ) {
return where ( queryBuilder , filter , isAndClause , isOrClause , true ) ;
} ;
}
if ( typeof filter === "function" ) {
filterMetaData = {
propertyName : filter ,
isOrClause : isOrClause ,
isAndClause : isAndClause ,
isNotClause : ( isNotClause === "undefined" ? false : isNotClause ) ,
filter : linq2indexedDB . prototype . linq . createFilter ( "anonymous" + queryBuilder . where . length , filter , null )
} ;
return whereClause ( queryBuilder , filterMetaData ) ;
} else if ( typeof filter === "string" ) {
// Builds up the where filter methodes
for ( var filterName in linq2indexedDB . prototype . linq . filters ) {
filterMetaData = {
propertyName : filter ,
isOrClause : isOrClause ,
isAndClause : isAndClause ,
isNotClause : ( typeof isNotClause === "undefined" ? false : isNotClause ) ,
filter : linq2indexedDB . prototype . linq . filters [ filterName ]
} ;
if ( typeof linq2indexedDB . prototype . linq . filters [ filterName ] . filter !== "function" ) {
throw "Linq2IndexedDB: a filter methods needs to be provided for the filter '" + filterName + "'" ;
}
if ( typeof linq2indexedDB . prototype . linq . filters [ filterName ] . name === "undefined" ) {
throw "Linq2IndexedDB: a filter name needs to be provided for the filter '" + filterName + "'" ;
}
whereClauses [ linq2indexedDB . prototype . linq . filters [ filterName ] . name ] = linq2indexedDB . prototype . linq . filters [ filterName ] . filter ( whereClause , queryBuilder , filterMetaData ) ;
}
}
return whereClauses ;
}
function whereClause ( queryBuilder , filterMetaData ) {
queryBuilder . where . push ( filterMetaData ) ;
return {
and : function ( filter ) {
/// <summary>Adds an extra filter.</summary>
/// <param name="filter">
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
///</param>
return where ( queryBuilder , filter , true , false ) ;
} ,
or : function ( filter ) {
/// <summary>Adds an extra filter.</summary>
/// <param name="filter">
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
///</param>
return where ( queryBuilder , filter , false , true ) ;
} ,
orderBy : function ( propertyName ) {
/// <summary>Sorts the selected data ascending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , false ) ;
} ,
orderByDesc : function ( propertyName ) {
/// <summary>Sorts the selected data descending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , true ) ;
} ,
select : function ( propertyNames ) {
/// <summary>Selects the data.</summary>
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
return select ( queryBuilder , propertyNames ) ;
} ,
remove : function ( ) {
return remove ( queryBuilder ) ;
} ,
merge : function ( data ) {
return merge ( queryBuilder , data ) ;
}
} ;
}
function orderBy ( queryBuilder , propName , descending ) {
queryBuilder . sortClauses . push ( { propertyName : propName , descending : descending } ) ;
return {
orderBy : function ( propertyName ) {
/// <summary>Sorts the selected data ascending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , false ) ;
} ,
orderByDesc : function ( propertyName ) {
/// <summary>Sorts the selected data descending.</summary>
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
return orderBy ( queryBuilder , propertyName , true ) ;
} ,
select : function ( propertyNames ) {
/// <summary>Selects the data.</summary>
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
return select ( queryBuilder , propertyNames ) ;
}
} ;
}
function select ( queryBuilder , propertyNames ) {
if ( propertyNames ) {
if ( ! linq2indexedDB . prototype . utilities . isArray ( propertyNames ) ) {
propertyNames = [ propertyNames ] ;
}
for ( var i = 0 ; i < propertyNames . length ; i ++ ) {
queryBuilder . select . push ( propertyNames [ i ] ) ;
}
}
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
var returnData = [ ] ;
executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , executeWhere ) . then ( function ( ) {
pw . complete ( this , returnData ) ;
} , pw . error , function ( args ) {
var obj = selectData ( args [ 0 ] . data , queryBuilder . select ) ;
returnData . push ( obj ) ;
pw . progress ( this , obj /*[obj]*/ ) ;
} ) ;
} ) ;
}
function insert ( queryBuilder , data , key ) {
queryBuilder . insert . push ( { data : data , key : key } ) ;
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , pw , transaction ) {
var objectStorePromis = linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) ;
if ( linq2indexedDB . prototype . utilities . isArray ( qb . insert [ 0 ] . data ) && ! qb . insert [ 0 ] . key ) {
var returnData = [ ] ;
for ( var i = 0 ; i < qb . insert [ 0 ] . data . length ; i ++ ) {
linq2indexedDB . prototype . core . insert ( objectStorePromis , qb . insert [ 0 ] . data [ i ] ) . then ( function ( args /*storedData, storedkey*/ ) {
pw . progress ( this , { object : args [ 0 ] , key : args [ 1 ] } /*[storedData, storedkey]*/ ) ;
returnData . push ( { object : args [ 0 ] , key : args [ 1 ] } ) ;
if ( returnData . length == qb . insert [ 0 ] . data . length ) {
pw . complete ( this , returnData ) ;
}
} , pw . error ) ;
}
}
else {
linq2indexedDB . prototype . core . insert ( objectStorePromis , qb . insert [ 0 ] . data , qb . insert [ 0 ] . key ) . then ( function ( args /*storedData, storedkey*/ ) {
pw . complete ( this , { object : args [ 0 ] , key : args [ 1 ] } /*[storedData, storedkey]*/ ) ;
} , pw . error ) ;
}
} ) ;
}
function update ( queryBuilder , data , key ) {
queryBuilder . update . push ( { data : data , key : key } ) ;
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , pw , transaction ) {
linq2indexedDB . prototype . core . update ( linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) , qb . update [ 0 ] . data , qb . update [ 0 ] . key ) . then ( function ( args /*storedData, storedkey*/ ) {
pw . complete ( this , { object : args [ 0 ] , key : args [ 1 ] } /*[storedData, storedkey]*/ ) ;
} , pw . error ) ;
} ) ;
}
function merge ( queryBuilder , data , key ) {
queryBuilder . merge . push ( { data : data , key : key } ) ;
if ( key ) {
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , pw , transaction ) {
var objectStore = linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) ;
var obj = null ;
linq2indexedDB . prototype . core . cursor ( objectStore , IDBKeyRange . only ( qb . merge [ 0 ] . key ) ) . then ( function ( ) {
} , pw . error , function ( args /*data*/ ) {
obj = args [ 0 ] . data ;
for ( var prop in qb . merge [ 0 ] . data ) {
obj [ prop ] = qb . merge [ 0 ] . data [ prop ] ;
}
args [ 0 ] . update ( obj ) ;
pw . complete ( this , obj ) ;
} , pw . error ) ;
} ) ;
}
else {
var returnData = [ ] ;
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , executeWhere ) . then ( function ( args ) {
if ( returnData . length > 0 ) {
pw . complete ( this , returnData ) ;
}
else {
executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , promise , transaction ) {
linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) . then ( function ( objectStoreArgs ) {
for ( var i = 0 ; i < args . length ; i ++ ) {
var obj = args [ i ] ;
for ( var prop in queryBuilder . merge [ 0 ] . data ) {
obj [ prop ] = queryBuilder . merge [ 0 ] . data [ prop ] ;
}
linq2indexedDB . prototype . core . update ( objectStoreArgs [ 1 ] , obj ) . then ( function ( args1 /*data*/ ) {
pw . progress ( this , args1 [ 0 ] /*[data]*/ ) ;
returnData . push ( args1 [ 0 ] ) ;
if ( returnData . length == args . length ) {
promise . complete ( this , returnData ) ;
}
} , promise . error ) ;
}
} , promise . error ) ;
} ) . then ( pw . complete , pw . error , pw . progress ) ;
}
} , null , function ( args ) {
if ( args [ 0 ] . update ) {
var obj = args [ 0 ] . data ;
for ( var prop in queryBuilder . merge [ 0 ] . data ) {
obj [ prop ] = queryBuilder . merge [ 0 ] . data [ prop ] ;
}
args [ 0 ] . update ( obj ) ;
pw . progress ( this , obj ) ;
returnData . push ( obj ) ;
}
} ) ;
} ) ;
}
}
function remove ( queryBuilder , key ) {
if ( key ) {
queryBuilder . remove . push ( { key : key } ) ;
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , pw , transaction ) {
linq2indexedDB . prototype . core . remove ( linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) , qb . remove [ 0 ] . key ) . then ( function ( ) {
pw . complete ( this , queryBuilder . remove [ 0 ] . key /*[queryBuilder.remove[0].key]*/ ) ;
} , pw . error ) ;
} ) ;
}
else {
var cursorDelete = false ;
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , executeWhere ) . then ( function ( data ) {
if ( cursorDelete ) {
pw . complete ( this ) ;
}
else {
executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , promise , transaction ) {
linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) . then ( function ( objectStoreArgs ) {
var itemsDeleted = 0 ;
for ( var i = 0 ; i < data . length ; i ++ ) {
linq2indexedDB . prototype . core . remove ( objectStoreArgs [ 1 ] , linq2indexedDB . prototype . utilities . getPropertyValue ( data [ i ] , objectStoreArgs [ 1 ] . keyPath ) ) . then ( function ( args1 /*data*/ ) {
pw . progress ( this , args1 [ 0 ] /*[data]*/ ) ;
if ( ++ itemsDeleted == data . length ) {
promise . complete ( this ) ;
}
} , promise . error ) ;
}
} , promise . error ) ;
} ) . then ( pw . complete , pw . error , pw . progress ) ;
}
} , null , function ( args ) {
if ( args [ 0 ] . remove ) {
args [ 0 ] . remove ( ) ;
pw . progress ( this ) ;
cursorDelete = true ;
}
} ) ;
} ) ;
}
}
function clear ( queryBuilder ) {
queryBuilder . clear = true ;
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _WRITE , function ( qb , pw , transaction ) {
linq2indexedDB . prototype . core . clear ( linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) ) . then ( function ( ) {
pw . complete ( this ) ;
} , pw . error ) ;
} ) ;
}
function get ( queryBuilder , key ) {
queryBuilder . get . push ( { key : key } ) ;
return executeQuery ( queryBuilder , linq2indexedDB . prototype . core . transactionTypes . READ _ONLY , function ( qb , pw , transaction ) {
linq2indexedDB . prototype . core . get ( linq2indexedDB . prototype . core . objectStore ( transaction , qb . from ) , qb . get [ 0 ] . key ) . then ( function ( args /*data*/ ) {
pw . complete ( this , args [ 0 ] /*[data]*/ ) ;
} , pw . error ) ;
} ) ;
}
function executeQuery ( queryBuilder , transactionType , callBack ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
// Create DB connection
linq2indexedDB . prototype . core . db ( dbConfig . name , dbConfig . version ) . then ( function ( args /* [db, event] */ ) {
// Opening a transaction
linq2indexedDB . prototype . core . transaction ( args [ 0 ] , queryBuilder . from , transactionType , dbConfig . autoGenerateAllowed ) . then ( function ( transactionArgs /* [transaction] */ ) {
var txn = transactionArgs [ 0 ] ;
txn . db . close ( ) ;
// call complete if it isn't called already
//pw.complete();
} ,
pw . error ,
function ( transactionArgs /* [transaction] */ ) {
callBack ( queryBuilder , pw , transactionArgs [ 0 ] ) ;
} ) ;
}
, pw . error
, function ( args /*txn, e*/ ) {
var txn = args [ 0 ] ;
var e = args [ 1 ] ;
// Upgrading the database to the correct version
if ( e . type == "upgradeneeded" ) {
upgradeDatabase ( dbConfig , e . oldVersion , e . newVersion , txn ) ;
}
} ) ;
} ) ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
function executeWhere ( queryBuilder , pw , transaction ) {
linq2indexedDB . prototype . core . objectStore ( transaction , queryBuilder . from ) . then ( function ( objArgs ) {
try {
var objectStore = objArgs [ 1 ] ;
var whereClauses = queryBuilder . where || [ ] ;
var returnData = [ ] ;
var cursorPromise = determineCursor ( objectStore , whereClauses ) ;
cursorPromise . then (
function ( args1 /*data*/ ) {
var data = args1 [ 0 ] ;
linq2indexedDB . prototype . utilities . linq2indexedDBWorker ( data , whereClauses , queryBuilder . sortClauses ) . then ( function ( d ) {
// No need to notify again if it allready happend in the onProgress method of the cursor.
if ( returnData . length == 0 ) {
for ( var j = 0 ; j < d . length ; j ++ ) {
pw . progress ( this , [ d [ j ] ] /*[obj]*/ ) ;
}
}
pw . complete ( this , d /*[returnData]*/ ) ;
} ) ;
} ,
pw . error ,
function ( args1 /*data*/ ) {
// When there are no more where clauses to fulfill and the collection doesn't need to be sorted, the data can be returned.
// In the other case let the complete handle it.
if ( whereClauses . length == 0 && queryBuilder . sortClauses . length == 0 ) {
returnData . push ( { data : args1 [ 0 ] . data , key : args1 [ 0 ] . key } ) ;
pw . progress ( this , args1 /*[obj]*/ ) ;
}
}
) ;
} catch ( ex ) {
// Handle errors like an invalid keyRange.
linq2indexedDB . prototype . core . abortTransaction ( args [ 0 ] ) ;
pw . error ( this , [ ex . message , ex ] ) ;
}
} , pw . error ) ;
}
function determineCursor ( objectStore , whereClauses ) {
var cursorPromise ;
// Checks if an indexeddb filter can be used
if ( whereClauses . length > 0
&& ! whereClauses [ 0 ] . isNotClause
&& whereClauses [ 0 ] . filter . indexeddbFilter
&& ( whereClauses . length == 1 || ( whereClauses . length > 1 && ! whereClauses [ 1 ] . isOrClause ) ) ) {
var source = objectStore ;
var indexPossible = dbConfig . autoGenerateAllowed || objectStore . indexNames . contains ( whereClauses [ 0 ] . propertyName + linq2indexedDB . prototype . core . indexSuffix ) ;
// Checks if we can use an index
if ( whereClauses [ 0 ] . propertyName != objectStore . keyPath && indexPossible ) {
source = linq2indexedDB . prototype . core . index ( objectStore , whereClauses [ 0 ] . propertyName , dbConfig . autoGenerateAllowed ) ;
}
// Checks if we can use indexeddb filter
if ( whereClauses [ 0 ] . propertyName == objectStore . keyPath
|| indexPossible ) {
// Gets the where clause + removes it from the collection
var clause = whereClauses . shift ( ) ;
switch ( clause . filter ) {
case linq2indexedDB . prototype . linq . filters . equals :
cursorPromise = linq2indexedDB . prototype . core . cursor ( source , IDBKeyRange . only ( clause . value ) ) ;
break ;
case linq2indexedDB . prototype . linq . filters . between :
cursorPromise = linq2indexedDB . prototype . core . cursor ( source , IDBKeyRange . bound ( clause . minValue , clause . maxValue , clause . minValueIncluded , clause . maxValueIncluded ) ) ;
break ;
case linq2indexedDB . prototype . linq . filters . greaterThan :
cursorPromise = linq2indexedDB . prototype . core . cursor ( source , IDBKeyRange . lowerBound ( clause . value , clause . valueIncluded ) ) ;
break ;
case linq2indexedDB . prototype . linq . filters . smallerThan :
cursorPromise = linq2indexedDB . prototype . core . cursor ( source , IDBKeyRange . upperBound ( clause . value , clause . valueIncluded ) ) ;
break ;
default :
cursorPromise = linq2indexedDB . prototype . core . cursor ( source ) ;
break ;
}
} else {
// Get everything if the index can't be used
cursorPromise = linq2indexedDB . prototype . core . cursor ( source ) ;
}
} else {
// Get's everything, manually filter data
cursorPromise = linq2indexedDB . prototype . core . cursor ( objectStore ) ;
}
return cursorPromise ;
}
function selectData ( data , propertyNames ) {
if ( propertyNames && propertyNames . length > 0 ) {
if ( ! linq2indexedDB . prototype . utilities . isArray ( propertyNames ) ) {
propertyNames = [ propertyNames ] ;
}
var obj = new Object ( ) ;
for ( var i = 0 ; i < propertyNames . length ; i ++ ) {
linq2indexedDB . prototype . utilities . setPropertyValue ( obj , propertyNames [ i ] , linq2indexedDB . prototype . utilities . getPropertyValue ( data , propertyNames [ i ] ) ) ;
}
return obj ;
}
return data ;
}
return {
from : function ( objectStoreName ) {
return from ( new queryBuilderObj ( objectStoreName ) , objectStoreName ) ;
}
} ;
}
function viewer ( dbConfig ) {
var dbView = { } ;
var refresh = true ;
function refreshInternal ( ) {
if ( refresh ) {
refresh = false ;
getDbInformation ( dbView , dbConfig ) ;
}
}
dbView . Configuration = {
name : dbConfig . name ,
version : dbConfig . version ,
autoGenerateAllowed : dbConfig . autoGenerateAllowed ,
schema : dbConfig . schema ,
definition : dbConfig . definition ,
onupgradeneeded : dbConfig . onupgradeneeded ,
oninitializeversion : dbConfig . oninitializeversion
} ;
dbView . refresh = function ( ) {
refresh = true ;
refreshInternal ( ) ;
} ;
linq2indexedDB . prototype . core . dbStructureChanged . addListener ( linq2indexedDB . prototype . core . databaseEvents . databaseUpgrade , function ( ) {
refresh = true ;
} ) ;
linq2indexedDB . prototype . core . dbStructureChanged . addListener ( linq2indexedDB . prototype . core . databaseEvents . databaseOpened , function ( ) {
refreshInternal ( ) ;
} ) ;
linq2indexedDB . prototype . core . dbStructureChanged . addListener ( linq2indexedDB . prototype . core . databaseEvents . databaseRemoved , function ( ) {
dbView . name = null ;
dbView . version = null ;
dbView . ObjectStores = [ ] ;
} ) ;
linq2indexedDB . prototype . core . dbDataChanged . addListener ( [ linq2indexedDB . prototype . core . dataEvents . dataInserted , linq2indexedDB . prototype . core . dataEvents . dataRemoved , linq2indexedDB . prototype . core . dataEvents . dataUpdated , linq2indexedDB . prototype . core . dataEvents . objectStoreCleared ] , function ( ) {
dbView . refresh ( ) ;
} ) ;
return dbView ;
}
function getDbInformation ( dbView , dbConfig ) {
linq2indexedDB . prototype . core . db ( dbConfig . name ) . then ( function ( ) {
var connection = arguments [ 0 ] [ 0 ] ;
dbView . name = connection . name ;
dbView . version = connection . version ;
dbView . ObjectStores = [ ] ;
linq2indexedDB . prototype . core . dbStructureChanged . addListener ( linq2indexedDB . prototype . core . databaseEvents . databaseBlocked , function ( ) {
connection . close ( ) ;
} ) ;
var objectStoreNames = [ ] ;
for ( var k = 0 ; k < connection . objectStoreNames . length ; k ++ ) {
objectStoreNames . push ( connection . objectStoreNames [ k ] ) ;
}
if ( objectStoreNames . length > 0 ) {
linq2indexedDB . prototype . core . transaction ( connection , objectStoreNames , linq2indexedDB . prototype . core . transactionTypes . READ _ONLY , false ) . then ( null , null , function ( ) {
var transaction = arguments [ 0 ] [ 0 ] ;
for ( var i = 0 ; i < connection . objectStoreNames . length ; i ++ ) {
linq2indexedDB . prototype . core . objectStore ( transaction , connection . objectStoreNames [ i ] ) . then ( function ( ) {
var objectStore = arguments [ 0 ] [ 1 ] ;
var indexes = [ ] ;
var objectStoreData = [ ] ;
for ( var j = 0 ; j < objectStore . indexNames . length ; j ++ ) {
linq2indexedDB . prototype . core . index ( objectStore , objectStore . indexNames [ j ] , false ) . then ( function ( ) {
var index = arguments [ 0 ] [ 1 ] ;
var indexData = [ ] ;
linq2indexedDB . prototype . core . cursor ( index ) . then ( null , null , function ( ) {
var data = arguments [ 0 ] [ 0 ] ;
var key = arguments [ 0 ] [ 1 ] . primaryKey ;
indexData . push ( { key : key , data : data } ) ;
} ) ;
indexes . push ( {
name : index . name ,
keyPath : index . keyPath ,
multiEntry : index . multiEntry ,
data : indexData
} ) ;
} ) ;
}
linq2indexedDB . prototype . core . cursor ( objectStore ) . then ( null , null , function ( ) {
var data = arguments [ 0 ] [ 0 ] ;
var key = arguments [ 0 ] [ 1 ] . primaryKey ;
objectStoreData . push ( { key : key , data : data } ) ;
} ) ;
dbView . ObjectStores . push ( {
name : objectStore . name ,
keyPath : objectStore . keyPath ,
autoIncrement : objectStore . autoIncrement ,
indexes : indexes ,
data : objectStoreData
} ) ;
} ) ;
}
} ) ;
}
} , null , function ( args ) {
if ( args [ 1 ] . type == "upgradeneeded" ) {
args [ 0 ] . abort ( ) ;
}
} ) ;
}
function getVersionDefinition ( version , definitions ) {
var result = null ;
for ( var i = 0 ; i < definitions . length ; i ++ ) {
if ( parseInt ( definitions [ i ] . version ) == parseInt ( version ) ) {
result = definitions [ i ] ;
}
}
return result ;
}
function initializeVersion ( txn , definition ) {
try {
if ( definition . objectStores ) {
for ( var i = 0 ; i < definition . objectStores . length ; i ++ ) {
var objectStoreDefinition = definition . objectStores [ i ] ;
if ( objectStoreDefinition . remove ) {
linq2indexedDB . prototype . core . deleteObjectStore ( txn , objectStoreDefinition . name ) ;
} else {
linq2indexedDB . prototype . core . createObjectStore ( txn , objectStoreDefinition . name , objectStoreDefinition . objectStoreOptions ) ;
}
}
}
if ( definition . indexes ) {
for ( var j = 0 ; j < definition . indexes . length ; j ++ ) {
var indexDefinition = definition . indexes [ j ] ;
if ( indexDefinition . remove ) {
linq2indexedDB . prototype . core . deleteIndex ( linq2indexedDB . prototype . core . objectStore ( txn , indexDefinition . objectStoreName ) , indexDefinition . propertyName ) ;
} else {
linq2indexedDB . prototype . core . createIndex ( linq2indexedDB . prototype . core . objectStore ( txn , indexDefinition . objectStoreName ) , indexDefinition . propertyName , indexDefinition . indexOptions ) ;
}
}
}
if ( definition . defaultData ) {
for ( var k = 0 ; k < definition . defaultData . length ; k ++ ) {
var defaultDataDefinition = definition . defaultData [ k ] ;
if ( defaultDataDefinition . remove ) {
linq2indexedDB . prototype . core . remove ( linq2indexedDB . prototype . core . objectStore ( txn , defaultDataDefinition . objectStoreName ) , defaultDataDefinition . key ) ;
} else {
linq2indexedDB . prototype . core . insert ( linq2indexedDB . prototype . core . objectStore ( txn , defaultDataDefinition . objectStoreName ) , defaultDataDefinition . data , defaultDataDefinition . key ) ;
}
}
}
} catch ( ex ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . exception , "initialize version exception: " , ex ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
}
}
function upgradeDatabase ( dbConfig , oldVersion , newVersion , txn ) {
if ( dbConfig . onupgradeneeded ) {
dbConfig . onupgradeneeded ( txn , oldVersion , newVersion ) ;
}
if ( dbConfig . oninitializeversion || dbConfig . schema || dbConfig . definition ) {
for ( var version = oldVersion + 1 ; version <= newVersion ; version ++ ) {
if ( dbConfig . schema ) {
dbConfig . schema [ version ] ( txn ) ;
}
if ( dbConfig . definition ) {
var versionDefinition = getVersionDefinition ( version , dbConfig . definition ) ;
if ( versionDefinition ) {
initializeVersion ( txn , versionDefinition ) ;
}
} else if ( dbConfig . oninitializeversion ) {
dbConfig . oninitializeversion ( txn , version ) ;
}
}
}
}
} ) ( ) ;
// Namespace linq2indexedDB.prototype.linq
( function ( ) {
linq2indexedDB . prototype . linq = {
addFilter : function ( name , isValid , filterCallback ) {
if ( typeof linq2indexedDB . prototype . linq . filters [ name ] !== 'undefined' ) {
throw "linq2IndexedDB: A filter with the name '" + name + "' already exists." ;
}
linq2indexedDB . prototype . linq . filters [ name ] = linq2indexedDB . prototype . linq . createFilter ( name , isValid , filterCallback ) ;
} ,
createFilter : function ( name , isValid , filterCallback ) {
if ( typeof name === 'undefined' ) {
throw "linq2IndexedDB: No name argument provided to the addFilter method." ;
}
if ( typeof name !== 'string' ) {
throw "linq2IndexedDB: The name argument provided to the addFilterObject method must be a string." ;
}
if ( typeof isValid === 'undefined' ) {
throw "linq2IndexedDB: No isValid argument provided to the addFilter method." ;
}
if ( typeof isValid !== 'function' ) {
throw "linq2IndexedDB: The isValid argument provided to the addFilterObject method must be a function." ;
}
if ( typeof filterCallback === 'undefined' ) {
throw "linq2IndexedDB: No filterCallback argument provided to the addFilter method." ;
}
//if (typeof filterCallback !== 'function') {
// throw "linq2IndexedDB: The filterCallback argument provided to the addFilterObject method must be a function.";
//}
return {
name : name ,
indexeddbFilter : false ,
sortOrder : 99 ,
isValid : isValid ,
filter : filterCallback
} ;
} ,
filters : {
equals : {
name : "equals" ,
indexeddbFilter : true ,
sortOrder : 0 ,
isValid : function ( data , filter ) {
return linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) == filter . value ;
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( value ) {
if ( typeof ( value ) === "undefined" ) {
throw "linq2indexedDB: value needs to be provided to the equal clause" ;
}
filterMetaData . value = value ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
between : {
name : "between" ,
sortOrder : 1 ,
indexeddbFilter : true ,
isValid : function ( data , filter ) {
var value = linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) ;
return ( value > filter . minValue || ( filter . minValueIncluded && value == filter . minValue ) )
&& ( value < filter . maxValue || ( filter . maxValueIncluded && value == filter . maxValue ) ) ;
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( minValue , maxValue , minValueIncluded , maxValueIncluded ) {
var isMinValueIncluded = typeof ( minValueIncluded ) === undefined ? false : minValueIncluded ;
var isMasValueIncluded = typeof ( maxValueIncluded ) === undefined ? false : maxValueIncluded ;
if ( typeof ( minValue ) === "undefined" ) {
throw "linq2indexedDB: minValue needs to be provided to the between clause" ;
}
if ( typeof ( maxValue ) === "undefined" ) {
throw "linq2indexedDB: maxValue needs to be provided to the between clause" ;
}
filterMetaData . minValue = minValue ;
filterMetaData . maxValue = maxValue ;
filterMetaData . minValueIncluded = isMinValueIncluded ;
filterMetaData . maxValueIncluded = isMasValueIncluded ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
greaterThan : {
name : "greaterThan" ,
sortOrder : 2 ,
indexeddbFilter : true ,
isValid : function ( data , filter ) {
var value = linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) ;
return value > filter . value || ( filter . valueIncluded && value == filter . value ) ;
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( value , valueIncluded ) {
if ( typeof ( value ) === "undefined" ) {
throw "linq2indexedDB: value needs to be provided to the greatherThan clause" ;
}
var isValueIncluded = typeof ( valueIncluded ) === undefined ? false : valueIncluded ;
filterMetaData . value = value ;
filterMetaData . valueIncluded = isValueIncluded ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
smallerThan : {
name : "smallerThan" ,
sortOrder : 2 ,
indexeddbFilter : true ,
isValid : function ( data , filter ) {
var value = linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) ;
return value < filter . value || ( filter . valueIncluded && value == filter . value ) ;
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( value , valueIncluded ) {
if ( typeof ( value ) === "undefined" ) {
throw "linq2indexedDB: value needs to be provided to the smallerThan clause" ;
}
var isValueIncluded = typeof ( valueIncluded ) === undefined ? false : valueIncluded ;
filterMetaData . value = value ;
filterMetaData . valueIncluded = isValueIncluded ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
inArray : {
name : "inArray" ,
sortOrder : 3 ,
indexeddbFilter : false ,
isValid : function ( data , filter ) {
var value = linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) ;
if ( value ) {
return filter . value . indexOf ( value ) >= 0 ;
}
else {
return false ;
}
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( array ) {
if ( typeof ( array ) === "undefined" || typeof array !== "Array" ) {
throw "linq2indexedDB: array needs to be provided to the inArray clause" ;
}
filterMetaData . value = array ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
like : {
name : "like" ,
sortOrder : 4 ,
indexeddbFilter : false ,
isValid : function ( data , filter ) {
var value = linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) ;
if ( value ) {
return value . indexOf ( filter . value ) >= 0 ;
}
else {
return false ;
}
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( value ) {
if ( typeof ( value ) === "undefined" ) {
throw "linq2indexedDB: value needs to be provided to the like clause" ;
}
filterMetaData . value = value ;
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
} ,
isUndefined : {
name : "isUndefined" ,
sortOrder : 5 ,
indexeddbFilter : false ,
isValid : function ( data , filter ) {
return linq2indexedDB . prototype . utilities . getPropertyValue ( data , filter . propertyName ) === undefined ;
} ,
filter : function ( callback , queryBuilder , filterMetaData ) {
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
/// <param name="callback" type="function">
/// Callback method so the query expression can be builded.
/// </param>
/// <param name="queryBuilder" type="Object">
/// The objects that builds up the query for the user.
/// </param>
/// <param name="filterMetaData" type="string">
/// The metadata for the filter.
/// </param>
/// <returns type="function">
/// returns a function to retrieve the necessary values for the filter
/// </returns>
return function ( ) {
return callback ( queryBuilder , filterMetaData ) ;
} ;
}
}
}
} ;
} ) ( ) ;
// Namespace linq2indexedDB.prototype.utitlities
( function ( isMetroApp ) {
"use strict" ;
var utilities = {
linq2indexedDBWorkerFileLocation : "/Scripts/Linq2IndexedDB.js" ,
linq2indexedDBWorker : function ( data , filters , sortClauses ) {
return utilities . promiseWrapper ( function ( pw ) {
if ( ! ! window . Worker ) {
var worker = new Worker ( utilities . linq2indexedDBWorkerFileLocation ) ;
worker . onmessage = function ( event ) {
pw . complete ( this , event . data ) ;
worker . terminate ( ) ;
} ;
worker . onerror = pw . error ;
var filtersString = JSON . stringify ( filters , linq2indexedDB . prototype . utilities . serialize ) ;
worker . postMessage ( { data : data , filters : filtersString , sortClauses : sortClauses } ) ;
} else {
// Fallback when there are no webworkers present. Beware, this runs on the UI thread and can block the UI
pw . complete ( this , utilities . filterSort ( data , filters , sortClauses ) ) ;
}
} ) ;
} ,
isArray : function ( array ) {
if ( array instanceof Array ) {
return true ;
} else {
return false ;
}
} ,
JSONComparer : function ( propertyName , descending ) {
return {
sort : function ( valueX , valueY ) {
if ( descending ) {
return ( ( valueX [ propertyName ] == valueY [ propertyName ] ) ? 0 : ( ( valueX [ propertyName ] > valueY [ propertyName ] ) ? - 1 : 1 ) ) ;
} else {
return ( ( valueX [ propertyName ] == valueY [ propertyName ] ) ? 0 : ( ( valueX [ propertyName ] > valueY [ propertyName ] ) ? 1 : - 1 ) ) ;
}
}
} ;
} ,
promiseWrapper : function ( promise , arg1 , arg2 , arg3 , arg4 , arg5 ) {
if ( isMetroApp ) {
return new WinJS . Promise ( function ( completed , error , progress ) {
promise ( {
complete : function ( context , args ) {
completed ( args ) ;
} ,
error : function ( context , args ) {
error ( args ) ;
} ,
progress : function ( context , args ) {
progress ( args ) ;
}
} , arg1 , arg2 , arg3 , arg4 , arg5 ) ;
} ) ;
} else if ( typeof ( $ ) === "function" && $ . Deferred ) {
return $ . Deferred ( function ( dfd ) {
promise ( {
complete : function ( context , args ) {
dfd . resolveWith ( context , [ args ] ) ;
} ,
error : function ( context , args ) {
dfd . rejectWith ( context , [ args ] ) ;
} ,
progress : function ( context , args ) {
dfd . notifyWith ( context , [ args ] ) ;
}
} , arg1 , arg2 , arg3 , arg4 , arg5 ) ;
} ) . promise ( ) ;
} else {
throw "linq2indexedDB: No framework (WinJS or jQuery) that supports promises found. Please ensure jQuery or WinJS is referenced before the linq2indexedDB.js file." ;
}
} ,
log : function ( ) {
if ( ( window && typeof ( window . console ) === "undefined" ) || ! enableLogging ) {
return false ;
}
var currtime = ( function currentTime ( ) {
var time = new Date ( ) ;
return time . getHours ( ) + ':' + time . getMinutes ( ) + ':' + time . getSeconds ( ) + '.' + time . getMilliseconds ( ) ;
} ) ( ) ;
var args = [ ] ;
var severity = arguments [ 0 ] ;
args . push ( currtime + ' Linq2IndexedDB: ' ) ;
for ( var i = 1 ; i < arguments . length ; i ++ ) {
args . push ( arguments [ i ] ) ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
switch ( severity ) {
case linq2indexedDB . prototype . utilities . severity . exception :
if ( window . console . exception ) {
window . console . exception . apply ( console , args ) ;
} else {
window . console . error . apply ( console , args ) ;
}
break ;
case linq2indexedDB . prototype . utilities . severity . error :
window . console . error . apply ( console , args ) ;
break ;
case linq2indexedDB . prototype . utilities . severity . warning :
window . console . warning . apply ( console , args ) ;
break ;
case linq2indexedDB . prototype . utilities . severity . information :
window . console . log . apply ( console , args ) ;
break ;
default :
window . console . log . apply ( console , args ) ;
}
return true ;
} ,
logError : function ( error ) {
return linq2indexedDB . prototype . utilities . log ( error . severity , error . message , error . type , error . method , error . orignialError ) ;
} ,
filterSort : function ( data , filters , sortClauses ) {
var returnData = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ ) {
if ( utilities . isDataValid ( data [ i ] . data , filters ) ) {
returnData = utilities . addToSortedArray ( returnData , data [ i ] , sortClauses ) ;
}
}
return returnData ;
} ,
isDataValid : function ( data , filters ) {
var isValid = true ;
for ( var i = 0 ; i < filters . length ; i ++ ) {
var filterValid = filters [ i ] . filter . isValid ( data , filters [ i ] ) ;
if ( filters [ i ] . isNotClause ) {
filterValid = ! filterValid ;
}
if ( filters [ i ] . isAndClause ) {
isValid = isValid && filterValid ;
} else if ( filters [ i ] . isOrClause ) {
isValid = isValid || filterValid ;
}
}
return isValid ;
} ,
addToSortedArray : function ( array , data , sortClauses ) {
var newArray = [ ] ;
if ( array . length == 0 || sortClauses . length == 0 ) {
newArray = array ;
newArray . push ( data ) ;
} else {
var valueAdded = false ;
for ( var i = 0 ; i < array . length ; i ++ ) {
var valueX = array [ i ] . data ;
var valueY = data . data ;
for ( var j = 0 ; j < sortClauses . length ; j ++ ) {
var sortPropvalueX = linq2indexedDB . prototype . utilities . getPropertyValue ( valueX , sortClauses [ j ] . propertyName ) ;
var sortPropvalueY = linq2indexedDB . prototype . utilities . getPropertyValue ( valueY , sortClauses [ j ] . propertyName ) ;
if ( sortPropvalueX != sortPropvalueY ) {
if ( ( sortClauses [ j ] . descending && sortPropvalueX > sortPropvalueY )
|| ( ! sortClauses [ j ] . descending && sortPropvalueX < sortPropvalueY ) ) {
newArray . push ( array [ i ] ) ;
} else {
if ( ! valueAdded ) {
valueAdded = true ;
newArray . push ( data ) ;
}
newArray . push ( array [ i ] ) ;
}
}
else if ( j == ( sortClauses . length - 1 ) ) {
newArray . push ( array [ i ] ) ;
}
}
}
// Add at the end
if ( ! valueAdded ) {
newArray . push ( data ) ;
}
}
return newArray ;
} ,
serialize : function ( key , value ) {
if ( typeof value === 'function' ) {
return value . toString ( ) ;
}
return value ;
} ,
deserialize : function ( key , value ) {
if ( value && typeof value === "string" && value . substr ( 0 , 8 ) == "function" ) {
var startBody = value . indexOf ( '{' ) + 1 ;
var endBody = value . lastIndexOf ( '}' ) ;
var startArgs = value . indexOf ( '(' ) + 1 ;
var endArgs = value . indexOf ( ')' ) ;
return new Function ( value . substring ( startArgs , endArgs ) , value . substring ( startBody , endBody ) ) ;
}
return value ;
} ,
getPropertyValue : function ( data , propertyName ) {
var structure = propertyName . split ( "." ) ;
var value = data ;
for ( var i = 0 ; i < structure . length ; i ++ ) {
if ( value ) {
value = value [ structure [ i ] ] ;
}
}
return value ;
} ,
setPropertyValue : function ( data , propertyName , value ) {
var structure = propertyName . split ( "." ) ;
var obj = data ;
for ( var i = 0 ; i < structure . length ; i ++ ) {
if ( i != ( structure . length - 1 ) ) {
obj [ structure [ i ] ] = { } ;
obj = obj [ structure [ i ] ] ;
}
else {
obj [ structure [ i ] ] = value ;
}
}
return obj ;
} ,
severity : {
information : 0 ,
warning : 1 ,
error : 2 ,
exception : 3
}
} ;
linq2indexedDB . prototype . utilities = utilities ;
} ) ( typeof Windows !== "undefined" ) ;
if ( typeof window !== "undefined" ) {
2013-05-31 07:52:04 +00:00
// UI Thread
2013-05-30 18:57:33 +00:00
// Namespace linq2indexedDB.prototype.core
( function ( window , isMetroApp ) {
"use strict" ;
// Region variables
var defaultDatabaseName = "Default" ;
var implementations = {
NONE : 0 ,
NATIVE : 1 ,
MICROSOFT : 2 ,
MOZILLA : 3 ,
GOOGLE : 4 ,
MICROSOFTPROTOTYPE : 5 ,
SHIM : 6
} ;
var transactionTypes = {
READ _ONLY : "readonly" ,
READ _WRITE : "readwrite" ,
VERSION _CHANGE : "versionchange"
} ;
var implementation = initializeIndexedDb ( ) ;
var handlers = {
IDBRequest : function ( request ) {
return deferredHandler ( IDBRequestHandler , request ) ;
} ,
IDBBlockedRequest : function ( request ) {
return deferredHandler ( IDBBlockedRequestHandler , request ) ;
} ,
IDBOpenDBRequest : function ( request ) {
return deferredHandler ( IDBOpenDbRequestHandler , request ) ;
} ,
IDBDatabase : function ( database ) {
return deferredHandler ( IDBDatabaseHandler , database ) ;
} ,
IDBTransaction : function ( txn ) {
return deferredHandler ( IDBTransactionHandler , txn ) ;
} ,
IDBCursorRequest : function ( request ) {
return deferredHandler ( IDBCursorRequestHandler , request ) ;
}
} ;
//Copyright (c) 2010 Nicholas C. Zakas. All rights reserved.
//MIT License
function eventTarget ( ) {
this . _listeners = { } ;
}
eventTarget . prototype = {
constructor : eventTarget ,
addListener : function ( type , listener ) {
if ( ! linq2indexedDB . prototype . utilities . isArray ( type ) ) {
type = [ type ] ;
}
for ( var i = 0 ; i < type . length ; i ++ ) {
if ( typeof this . _listeners [ type [ i ] ] == "undefined" ) {
this . _listeners [ type [ i ] ] = [ ] ;
}
this . _listeners [ type [ i ] ] . push ( listener ) ;
}
} ,
fire : function ( event ) {
if ( typeof event == "string" ) {
event = { type : event } ;
}
if ( ! event . target ) {
event . target = this ;
}
if ( ! event . type ) { //falsy
throw new Error ( "Event object missing 'type' property." ) ;
}
if ( this . _listeners [ event . type ] instanceof Array ) {
var listeners = this . _listeners [ event . type ] ;
for ( var i = 0 , len = listeners . length ; i < len ; i ++ ) {
listeners [ i ] . call ( this , event ) ;
}
}
} ,
removeListener : function ( type , listener ) {
if ( ! linq2indexedDB . prototype . utilities . isArray ( type ) ) {
type = [ type ] ;
}
for ( var j = 0 ; j < type [ j ] . length ; j ++ ) {
if ( this . _listeners [ type [ j ] ] instanceof Array ) {
var listeners = this . _listeners [ type [ j ] ] ;
for ( var i = 0 , len = listeners . length ; i < len ; i ++ ) {
if ( listeners [ i ] === listener ) {
listeners . splice ( i , 1 ) ;
break ;
}
}
}
}
}
} ;
// End copyright
var dbEvents = {
objectStoreCreated : "Object store created" ,
objectStoreRemoved : "Object store removed" ,
indexCreated : "Index created" ,
indexRemoved : "Index removed" ,
databaseRemoved : "Database removed" ,
databaseBlocked : "Database blocked" ,
databaseUpgrade : "Database upgrade" ,
databaseOpened : "Database opened"
} ;
var dataEvents = {
dataInserted : "Data inserted" ,
dataUpdated : "Data updated" ,
dataRemoved : "Data removed" ,
objectStoreCleared : "Object store cleared"
} ;
var upgradingDatabase = false ;
var internal = {
db : function ( pw , name , version ) {
var req ;
try {
// Initializing defaults
name = name ? name : defaultDatabaseName ;
// Creating a new database conection
if ( version ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "db opening" , name , version ) ;
req = window . indexedDB . open ( name , version ) ;
} else {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "db opening" , name ) ;
req = window . indexedDB . open ( name ) ;
}
// Handle the events of the creation of the database connection
handlers . IDBOpenDBRequest ( req ) . then (
function ( args /*db, e*/ ) {
var db = args [ 0 ] ;
var e = args [ 1 ] ;
// Database connection established
// Handle the events on the database.
handlers . IDBDatabase ( db ) . then (
function ( /*result, event*/ ) {
// No done present.
} ,
function ( args1 /*error, event*/ ) {
// Database error or abort
linq2indexedDB . prototype . core . closeDatabaseConnection ( args1 [ 1 ] . target ) ;
// When an error occures the result will already be resolved. This way calling the reject won't case a thing
} ,
function ( args1 /*result, event*/ ) {
var event = args1 [ 1 ] ;
if ( event ) {
// Sending a notify won't have any effect because the result is already resolved. There is nothing more to do than close the current connection.
if ( event . type === "versionchange" ) {
if ( event . version != event . target . db . version ) {
// If the version is changed and the current version is different from the requested version, the connection needs to get closed.
linq2indexedDB . prototype . core . closeDatabaseConnection ( event . target ) ;
}
}
}
} ) ;
var currentVersion = internal . getDatabaseVersion ( db ) ;
if ( currentVersion < version || ( version == - 1 ) || currentVersion == "" ) {
// Current version deferres from the requested version, database upgrade needed
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "DB Promise upgradeneeded" , this , db , e , db . connectionId ) ;
internal . changeDatabaseStructure ( db , version || 1 ) . then (
function ( args1 /*txn, event*/ ) {
var txn = args1 [ 0 ] ;
var event = args1 [ 1 ] ;
// Fake the onupgrade event.
var context = txn . db ;
context . transaction = txn ;
var upgardeEvent = { } ;
upgardeEvent . type = "upgradeneeded" ;
upgardeEvent . newVersion = version ;
upgardeEvent . oldVersion = currentVersion ;
upgardeEvent . originalEvent = event ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseUpgrade , data : upgardeEvent } ) ;
pw . progress ( context , [ txn , upgardeEvent ] ) ;
handlers . IDBTransaction ( txn ) . then ( function ( /*trans, args*/ ) {
// When completed return the db + event of the original request.
pw . complete ( this , args ) ;
} ,
function ( args2 /*err, ev*/ ) {
//txn error or abort
pw . error ( this , args2 ) ;
} ) ;
} ,
function ( args1 /*err, event*/ ) {
// txn error or abort
pw . error ( this , args1 ) ;
} ,
function ( args1 /*result, event*/ ) {
// txn blocked
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseBlocked , data : args1 } ) ;
pw . progress ( this , args1 ) ;
} ) ;
} else if ( version && version < currentVersion ) {
linq2indexedDB . prototype . core . closeDatabaseConnection ( db ) ;
var err = {
severity : linq2indexedDB . prototype . utilities . severity . error ,
type : "VersionError" ,
message : "You are trying to open the database in a lower version (" + version + ") than the current version of the database" ,
method : "db"
} ;
linq2indexedDB . prototype . utilities . logError ( err ) ;
pw . error ( this , err ) ;
}
else {
// Database Connection resolved.
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseOpened , data : db } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "DB Promise resolved" , db , e ) ;
pw . complete ( this , [ db , e ] ) ;
}
} ,
function ( args /*error, e*/ ) {
// Database connection error or abort
var err = internal . wrapError ( args [ 1 ] , "db" ) ;
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
// Fix for firefox & chrome
if ( args [ 1 ] . target && args [ 1 ] . target . errorCode == 12 ) {
err . type = "VersionError" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( err . type == "VersionError" ) {
err . message = "You are trying to open the database in a lower version (" + version + ") than the current version of the database" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
// Fix for firefox & chrome
if ( args [ 1 ] . target && args [ 1 ] . target . errorCode == 8 ) {
err . type = "AbortError" ;
}
if ( err . type == "AbortError" ) {
err . message = "The VERSION_CHANGE transaction was aborted." ;
}
// For old firefox implementations
linq2indexedDB . prototype . utilities . logError ( err ) ;
pw . error ( this , err ) ;
} ,
function ( args /*result, e*/ ) {
// Database upgrade + db blocked
if ( args [ 1 ] . type == "blocked" ) {
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseBlocked , data : args } ) ;
} else if ( args [ 1 ] . type == "upgradeneeded" ) {
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseUpgrade , data : args } ) ;
}
pw . progress ( this , args ) ;
}
) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "db" ) ;
if ( ( ex . INVALID _ACCESS _ERR && ex . code == ex . INVALID _ACCESS _ERR ) || ex . name == "InvalidAccessError" ) {
error . type = "InvalidAccessError" ;
error . message = "You are trying to open a database with a negative version number." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
pw . error ( this , error ) ;
}
} ,
transaction : function ( pw , db , objectStoreNames , transactionType , autoGenerateAllowed ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction promise started" , db , objectStoreNames , transactionType ) ;
// Initialize defaults
if ( ! linq2indexedDB . prototype . utilities . isArray ( objectStoreNames ) ) objectStoreNames = [ objectStoreNames ] ;
transactionType = transactionType || linq2indexedDB . prototype . core . transactionTypes . READ _ONLY ;
var nonExistingObjectStores = [ ] ;
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
try {
// Check for non-existing object stores
for ( var i = 0 ; i < objectStoreNames . length ; i ++ ) {
if ( ! db . objectStoreNames || ! db . objectStoreNames . contains ( objectStoreNames [ i ] ) ) {
nonExistingObjectStores . push ( objectStoreNames [ i ] ) ;
}
}
// When non-existing object stores are found and the autoGenerateAllowed is true.
// Then create these object stores
if ( nonExistingObjectStores . length > 0 && autoGenerateAllowed ) {
// setTimeout is necessary when multiple request to generate an index come together.
// This can result in a deadlock situation, there for the setTimeout
setTimeout ( function ( ) {
upgradingDatabase = true ;
var version = internal . getDatabaseVersion ( db ) + 1 ;
var dbName = db . name ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction database upgrade needed: " , db ) ;
// Closing the current connections so it won't block the upgrade.
linq2indexedDB . prototype . core . closeDatabaseConnection ( db ) ;
// Open a new connection with the new version
linq2indexedDB . prototype . core . db ( dbName , version ) . then ( function ( args /*dbConnection, event*/ ) {
upgradingDatabase = false ;
// Necessary for getting it work in WIN 8, WinJS promises have troubles with nesting promises
var txn = args [ 0 ] . transaction ( objectStoreNames , transactionType ) ;
// Handle transaction events
handlers . IDBTransaction ( txn ) . then ( function ( args1 /*result, event*/ ) {
// txn completed
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction completed." , txn ) ;
pw . complete ( this , args1 ) ;
} ,
function ( args1 /*err, event*/ ) {
// txn error or abort
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Transaction error/abort." , args1 ) ;
pw . error ( this , args1 ) ;
} ) ;
// txn created
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction created." , txn ) ;
pw . progress ( txn , [ txn ] ) ;
} ,
function ( args /*error, event*/ ) {
// When an error occures, bubble up.
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Transaction error." , args ) ;
pw . error ( this , args ) ;
} ,
function ( args /*txn, event*/ ) {
var event = args [ 1 ] ;
// When an upgradeneeded event is thrown, create the non-existing object stores
if ( event . type == "upgradeneeded" ) {
for ( var j = 0 ; j < nonExistingObjectStores . length ; j ++ ) {
linq2indexedDB . prototype . core . createObjectStore ( args [ 0 ] , nonExistingObjectStores [ j ] , { keyPath : "Id" , autoIncrement : true } ) ;
}
}
} ) ;
} , upgradingDatabase ? 10 : 1 ) ;
} else {
// If no non-existing object stores are found, create the transaction.
var transaction = db . transaction ( objectStoreNames , transactionType ) ;
// Handle transaction events
handlers . IDBTransaction ( transaction ) . then ( function ( args /*result, event*/ ) {
// txn completed
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction completed." , args ) ;
pw . complete ( this , args ) ;
} ,
function ( args /*err, event*/ ) {
var err = internal . wrapError ( args [ 1 ] , "transaction" ) ;
if ( args [ 1 ] . type == "abort" ) {
err . type = "abort" ;
err . severity = "abort" ;
err . message = "Transaction was aborted" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
// Fix for firefox & chrome
if ( args [ 1 ] . target && args [ 1 ] . target . errorCode == 4 ) {
err . type = "ConstraintError" ;
}
if ( err . type == "ConstraintError" ) {
err . message = "A mutation operation in the transaction failed. For more details look at the error on the instert, update, remove or clear statement." ;
2013-05-31 07:52:04 +00:00
}
2013-05-30 18:57:33 +00:00
// txn error or abort
linq2indexedDB . prototype . utilities . logError ( err ) ;
pw . error ( this , err ) ;
} ) ;
// txn created
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Transaction transaction created." , transaction ) ;
pw . progress ( transaction , [ transaction ] ) ;
}
}
catch ( ex ) {
var error = internal . wrapException ( ex , "transaction" ) ;
if ( ( ex . INVALID _ACCESS _ERR && ex . code == ex . INVALID _ACCESS _ERR ) || ex . name == "InvalidAccessError" ) {
error . type = "InvalidAccessError" ;
error . message = "You are trying to open a transaction without providing an object store as scope." ;
}
if ( ( ex . NOT _FOUND _ERR && ex . code == ex . NOT _FOUND _ERR ) || ex . name == "NotFoundError" ) {
var objectStores = "" ;
for ( var m = 0 ; m < nonExistingObjectStores . length ; m ++ ) {
if ( m > 0 ) {
objectStores += ", " ;
}
objectStores += nonExistingObjectStores [ m ] ;
}
error . type = "NotFoundError" ;
error . message = "You are trying to open a transaction for object stores (" + objectStores + "), that doesn't exist." ;
}
if ( ( ex . QUOTA _ERR && ex . code == ex . QUOTA _ERR ) || ex . name == "QuotaExceededError" ) {
error . type = "QuotaExceededError" ;
error . message = "The size quota of the indexedDB database is reached." ;
}
if ( ( ex . UNKNOWN _ERR && ex . code == ex . UNKNOWN _ERR ) || ex . name == "UnknownError" ) {
error . type = "UnknownError" ;
error . message = "An I/O exception occured." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
pw . error ( this , error ) ;
}
} ,
changeDatabaseStructure : function ( db , version ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "changeDatabaseStructure started" , db , version ) ;
handlers . IDBBlockedRequest ( db . setVersion ( version ) ) . then ( function ( args /*txn, event*/ ) {
// txn created
pw . complete ( this , args ) ;
} ,
function ( args /*error, event*/ ) {
// txn error or abort
pw . error ( this , args ) ;
} ,
function ( args /*txn, event*/ ) {
// txn blocked
pw . progress ( this , args ) ;
} ) ;
} ) ;
} ,
objectStore : function ( pw , transaction , objectStoreName ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "objectStore started" , transaction , objectStoreName ) ;
try {
var store = transaction . objectStore ( objectStoreName ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "objectStore completed" , transaction , store ) ;
pw . complete ( store , [ transaction , store ] ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "objectStore" ) ;
if ( ( ex . NOT _FOUND _ERR && ex . code == ex . NOT _FOUND _ERR ) || ex . name == "NotFoundError" ) {
error . type = "NotFoundError" ;
error . message = "You are trying to open an object store (" + objectStoreName + "), that doesn't exist or isn't in side the transaction scope." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to open an object store (" + objectStoreName + ") outside a transaction." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( transaction ) ;
pw . error ( this , error ) ;
}
} ,
createObjectStore : function ( pw , transaction , objectStoreName , objectStoreOptions ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "createObjectStore started" , transaction , objectStoreName , objectStoreOptions ) ;
try {
if ( ! transaction . db . objectStoreNames . contains ( objectStoreName ) ) {
// If the object store doesn't exists, create it
var options = new Object ( ) ;
if ( objectStoreOptions ) {
if ( objectStoreOptions . keyPath ) options . keyPath = objectStoreOptions . keyPath ;
options . autoIncrement = objectStoreOptions . autoIncrement ;
} else {
options . autoIncrement = true ;
}
var store = transaction . db . createObjectStore ( objectStoreName , options , options . autoIncrement ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "ObjectStore Created" , transaction , store ) ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . objectStoreCreated , data : store } ) ;
pw . complete ( store , [ transaction , store ] ) ;
} else {
// If the object store exists, retrieve it
linq2indexedDB . prototype . core . objectStore ( transaction , objectStoreName ) . then ( function ( args /*trans, store*/ ) {
// store resolved
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "ObjectStore Found" , args [ 1 ] , objectStoreName ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "createObjectStore Promise" , args [ 0 ] , args [ 1 ] ) ;
pw . complete ( store , args ) ;
} ,
function ( args /*error, event*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
}
} catch ( ex ) {
// store exception
var error = internal . wrapException ( ex , "createObjectStore" ) ;
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to create an object store in a readonly or readwrite transaction." ;
}
if ( ( ex . INVALID _ACCESS _ERR && ex . code == ex . INVALID _ACCESS _ERR ) || ex . name == "InvalidAccessError" ) {
error . type = "InvalidAccessError" ;
error . message = "The object store can't have autoIncrement on and an empty string or an array with an empty string as keyPath." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
if ( error . type != "InvalidStateError" ) {
linq2indexedDB . prototype . core . abortTransaction ( transaction ) ;
}
pw . error ( this , error ) ;
}
} ,
deleteObjectStore : function ( pw , transaction , objectStoreName ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "deleteObjectStore Promise started" , transaction , objectStoreName ) ;
try {
transaction . db . deleteObjectStore ( objectStoreName ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "ObjectStore Deleted" , objectStoreName ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "deleteObjectStore completed" , objectStoreName ) ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . objectStoreRemoved , data : objectStoreName } ) ;
pw . complete ( this , [ transaction , objectStoreName ] ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "deleteObjectStore" ) ;
if ( ( ex . NOT _FOUND _ERR && ex . code == ex . NOT _FOUND _ERR ) || ex . name == "NotFoundError" ) {
error . type = "NotFoundError" ;
error . message = "You are trying to delete an object store (" + objectStoreName + "), that doesn't exist." ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to delete an object store in a readonly or readwrite transaction." ;
}
// store exception
linq2indexedDB . prototype . utilities . logError ( error ) ;
if ( error . type != "InvalidStateError" ) {
linq2indexedDB . prototype . core . abortTransaction ( transaction ) ;
}
pw . error ( this , error ) ;
}
} ,
index : function ( pw , objectStore , propertyName , autoGenerateAllowed ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Index started" , objectStore , propertyName , autoGenerateAllowed ) ;
var indexName = propertyName ;
if ( propertyName . indexOf ( linq2indexedDB . prototype . core . indexSuffix ) == - 1 ) {
indexName = indexName + linq2indexedDB . prototype . core . indexSuffix ;
}
try {
if ( ! objectStore . indexNames . contains ( indexName ) && autoGenerateAllowed ) {
// setTimeout is necessary when multiple request to generate an index come together.
// This can result in a deadlock situation, there for the setTimeout
setTimeout ( ( function ( objStore ) {
upgradingDatabase = true ;
// If index doesn't exists, create it if autoGenerateAllowed
var version = internal . getDatabaseVersion ( objStore . transaction . db ) + 1 ;
var dbName = objStore . transaction . db . name ;
var transactionType = objStore . transaction . mode ;
var objectStoreNames = [ objStore . name ] ; //transaction.objectStoreNames;
var objectStoreName = objStore . name ;
// Close the currenct database connections so it won't block
linq2indexedDB . prototype . core . closeDatabaseConnection ( objStore ) ;
// Open a new connection with the new version
linq2indexedDB . prototype . core . db ( dbName , version ) . then ( function ( args /*dbConnection, event*/ ) {
upgradingDatabase = false ;
// When the upgrade is completed, the index can be resolved.
linq2indexedDB . prototype . core . transaction ( args [ 0 ] , objectStoreNames , transactionType , autoGenerateAllowed ) . then ( function ( /*transaction, ev*/ ) {
// txn completed
// TODO: what to do in this case
} ,
function ( args1 /*error, ev*/ ) {
// txn error or abort
pw . error ( this , args1 ) ;
} ,
function ( args1 /*transaction*/ ) {
// txn created
linq2indexedDB . prototype . core . index ( linq2indexedDB . prototype . core . objectStore ( args1 [ 0 ] , objectStoreName ) , propertyName ) . then ( function ( args2 /*trans, index, store*/ ) {
pw . complete ( this , args2 ) ;
} , function ( args2 /*error, ev*/ ) {
// txn error or abort
pw . error ( this , args2 ) ;
} ) ;
} ) ;
} ,
function ( args /*error, event*/ ) {
// When an error occures, bubble up.
pw . error ( this , args ) ;
} ,
function ( args /*trans, event*/ ) {
var trans = args [ 0 ] ;
var event = args [ 1 ] ;
// When an upgradeneeded event is thrown, create the non-existing object stores
if ( event . type == "upgradeneeded" ) {
linq2indexedDB . prototype . core . createIndex ( linq2indexedDB . prototype . core . objectStore ( trans , objectStoreName ) , propertyName ) . then ( function ( /*index, store, transaction*/ ) {
// index created
} ,
function ( args1 /*error, ev*/ ) {
// When an error occures, bubble up.
pw . error ( this , args1 ) ;
} ) ;
}
} ) ;
} ) ( objectStore ) , upgradingDatabase ? 10 : 1 ) ;
} else {
// If index exists, resolve it
var index = objectStore . index ( indexName ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Index completed" , objectStore . transaction , index , objectStore ) ;
pw . complete ( this , [ objectStore . transaction , index , objectStore ] ) ;
}
} catch ( ex ) {
var error = internal . wrapException ( ex , "index" ) ;
if ( ( ex . NOT _FOUND _ERR && ex . code == ex . NOT _FOUND _ERR ) || ex . name == "NotFoundError" ) {
error . type = "NotFoundError" ;
error . message = "You are trying to open an index (" + indexName + "), that doesn't exist." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to open an object store (" + indexName + ") outside a transaction." ;
}
// index exception
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
createIndex : function ( pw , objectStore , propertyName , indexOptions ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "createIndex started" , objectStore , propertyName , indexOptions ) ;
try {
var indexName = propertyName ;
if ( propertyName . indexOf ( linq2indexedDB . prototype . core . indexSuffix ) == - 1 ) {
indexName = indexName + linq2indexedDB . prototype . core . indexSuffix ;
}
if ( ! objectStore . indexNames . contains ( indexName ) ) {
var index = objectStore . createIndex ( indexName , propertyName , { unique : indexOptions ? indexOptions . unique : false , multiRow : indexOptions ? indexOptions . multirow : false , multiEntry : indexOptions ? indexOptions . multirow : false } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "createIndex completed" , objectStore . transaction , index , objectStore ) ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . indexCreated , data : index } ) ;
pw . complete ( this , [ objectStore . transaction , index , objectStore ] ) ;
} else {
// if the index exists retrieve it
linq2indexedDB . prototype . core . index ( objectStore , propertyName , false ) . then ( function ( args ) {
pw . complete ( this , args ) ;
} ) ;
}
} catch ( ex ) {
// store exception
var error = internal . wrapException ( ex , "createIndex" ) ;
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to create an index in a readonly or readwrite transaction." ;
}
if ( error . type != "InvalidStateError" ) {
linq2indexedDB . prototype . core . abortTransaction ( transaction ) ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
pw . error ( this , error ) ;
}
} ,
deleteIndex : function ( pw , objectStore , propertyName ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "deleteIndex started" , objectStore , propertyName ) ;
var indexName = propertyName ;
if ( propertyName . indexOf ( linq2indexedDB . prototype . core . indexSuffix ) == - 1 ) {
indexName = indexName + linq2indexedDB . prototype . core . indexSuffix ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
try {
objectStore . deleteIndex ( indexName ) ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . indexRemoved , data : indexName } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "deleteIndex completed" , objectStore . transaction , propertyName , objectStore ) ;
pw . complete ( this , [ objectStore . transaction , propertyName , objectStore ] ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "deleteIndex" ) ;
if ( ( ex . NOT _FOUND _ERR && ex . code == ex . NOT _FOUND _ERR ) || ex . name == "NotFoundError" ) {
error . type = "NotFoundError" ;
error . message = "You are trying to delete an index (" + indexName + ", propertyName: " + propertyName + " ), that doesn't exist." ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to delete an index in a readonly or readwrite transaction." ;
}
// store exception
linq2indexedDB . prototype . utilities . logError ( error ) ;
if ( error . type != "InvalidStateError" ) {
linq2indexedDB . prototype . core . abortTransaction ( transaction ) ;
}
pw . error ( this , error ) ;
}
} ,
cursor : function ( pw , source , range , direction ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor Promise Started" , source ) ;
var keyRange ;
var returnData = [ ] ;
var request ;
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
try {
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
keyRange = range ;
if ( ! keyRange ) {
if ( implementation != implementations . GOOGLE ) {
keyRange = IDBKeyRange . lowerBound ( 0 ) ;
} else {
keyRange = IDBKeyRange . lowerBound ( parseFloat ( 0 ) ) ;
}
}
// direction can not be null when passed.
if ( direction ) {
request = handlers . IDBCursorRequest ( source . openCursor ( keyRange , direction ) ) ;
} else if ( keyRange ) {
request = handlers . IDBCursorRequest ( source . openCursor ( keyRange ) ) ;
} else {
request = handlers . IDBCursorRequest ( source . openCursor ( ) ) ;
}
request . then ( function ( args1 /*result, e*/ ) {
var e = args1 [ 1 ] ;
var transaction = source . transaction || source . objectStore . transaction ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor completed" , returnData , transaction , e ) ;
pw . complete ( this , [ returnData , transaction , e ] ) ;
} ,
function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Cursor error" , args ) ;
pw . error ( this , args ) ;
} ,
function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor progress" , result , e ) ;
if ( result . value ) {
var progressObj = {
data : result . value ,
key : result . primaryKey ,
skip : function ( number ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor skip" , result , e ) ;
try {
result . advance ( number ) ;
}
catch ( advanceEx ) {
var advanceErr = internal . wrapException ( advanceEx , "cursor - skip" ) ;
if ( ( advanceEx . DATA _ERR && advanceEx . code == advanceEx . DATA _ERR ) || advanceEx . name == "DataError" ) {
advanceErr . type = "DataError" ;
advanceErr . message = "The provided range parameter isn't a valid key or key range." ;
}
if ( advanceEx . name == "TypeError" ) {
advanceErr . type = "TypeError" ;
advanceErr . message = "The provided count parameter is zero or a negative number." ;
}
if ( ( advanceEx . INVALID _STATE _ERR && advanceEx . code == advanceEx . INVALID _STATE _ERR ) || advanceEx . name == "InvalidStateError" ) {
advanceErr . type = "InvalidStateError" ;
advanceErr . message = "You are trying to skip data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( advanceErr ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , advanceErr ) ;
}
} ,
update : function ( obj ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor update" , result , e ) ;
try {
result . update ( obj ) ;
}
catch ( updateEx ) {
var updateError = internal . wrapException ( updateEx , "cursor - update" ) ;
if ( ( updateEx . DATA _ERR && updateEx . code == updateEx . DATA _ERR ) || updateEx . name == "DataError" ) {
updateError . type = "DataError" ;
updateError . message = "The underlying object store uses in-line keys and the property in value at the object store's key path does not match the key in this cursor's position." ;
}
if ( ( updateEx . READ _ONLY _ERR && ex . code == updateEx . READ _ONLY _ERR ) || updateEx . name == "ReadOnlyError" ) {
updateError . type = "ReadOnlyError" ;
updateError . message = "You are trying to update data in a readonly transaction." ;
}
if ( updateEx . name == "TransactionInactiveError" ) {
updateError . type = "TransactionInactiveError" ;
updateError . message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( updateEx . DATA _CLONE _ERR && updateEx . code == updateEx . DATA _CLONE _ERR ) || updateEx . name == "DataCloneError" ) {
updateError . type = "DataCloneError" ;
updateError . message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data." ;
}
if ( ( updateEx . INVALID _STATE _ERR && updateEx . code == updateEx . INVALID _STATE _ERR ) || updateEx . name == "InvalidStateError" ) {
updateError . type = "InvalidStateError" ;
updateError . message = "You are trying to update data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( updateError ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , updateError ) ;
}
} ,
remove : function ( ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Cursor remove" , result , e ) ;
try {
result [ "delete" ] ( ) ;
}
catch ( deleteEx ) {
var deleteError = internal . wrapException ( deleteEx , "cursor - delete" ) ;
if ( ( deleteEx . READ _ONLY _ERR && deleteEx . code == deleteEx . READ _ONLY _ERR ) || deleteEx . name == "ReadOnlyError" ) {
deleteError . type = "ReadOnlyError" ;
deleteError . message = "You are trying to remove data in a readonly transaction." ;
}
if ( deleteEx . name == "TransactionInactiveError" ) {
deleteError . type = "TransactionInactiveError" ;
deleteError . message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( deleteEx . INVALID _STATE _ERR && deleteEx . code == deleteEx . INVALID _STATE _ERR ) || deleteEx . name == "InvalidStateError" ) {
deleteError . type = "InvalidStateError" ;
deleteError . message = "You are trying to remove data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( deleteError ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , deleteError ) ;
}
}
} ;
pw . progress ( this , [ progressObj , result , e ] ) ;
returnData . push ( { data : progressObj . data , key : progressObj . key } ) ;
}
result [ "continue" ] ( ) ;
} ) ;
} catch ( ex ) {
var txn = source . transaction || source . objectStore . transaction ;
var error = internal . wrapException ( ex , "cursor" ) ;
if ( ( ex . DATA _ERR && error . code == ex . DATA _ERR ) || ex . name == "DataError" ) {
error . type = "DataError" ;
error . message = "The provided range parameter isn't a valid key or key range." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ex . name == "TypeError" ) {
error . type = "TypeError" ;
error . message = "The provided directory parameter is invalid" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to insert data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , error ) ;
}
finally {
keyRange = null ;
}
} ,
keyCursor : function ( pw , index , range , direction ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor Started" , index , range , direction ) ;
var returnData = [ ] ;
try {
var request ;
var keyRange = range ;
if ( ! keyRange ) {
keyRange = IDBKeyRange . lowerBound ( 0 ) ;
}
// direction can not be null when passed.
if ( direction ) {
request = handlers . IDBCursorRequest ( source . openKeyCursor ( keyRange , direction ) ) ;
} else {
request = handlers . IDBCursorRequest ( source . openKeyCursor ( keyRange ) ) ;
}
request . then ( function ( args /*result, e*/ ) {
var e = args [ 1 ] ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor completed" , returnData , index . objectStore . transaction , e ) ;
pw . complete ( this , [ returnData , index . objectStore . transaction , e ] ) ;
} ,
function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "keyCursor error" , args ) ;
pw . error ( this , args ) ;
} ,
function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor progress" , result , e ) ;
if ( result . value ) {
var progressObj = {
data : result . value ,
key : result . primaryKey ,
skip : function ( number ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor skip" , result , e ) ;
try {
result . advance ( number ) ;
}
catch ( advanceEx ) {
var advanceErr = internal . wrapException ( advanceEx , "keyCursor - skip" ) ;
if ( ( advanceEx . DATA _ERR && advanceEx . code == advanceEx . DATA _ERR ) || advanceEx . name == "DataError" ) {
advanceErr . type = "DataError" ;
advanceErr . message = "The provided range parameter isn't a valid key or key range." ;
}
if ( advanceEx . name == "TypeError" ) {
advanceErr . type = "TypeError" ;
advanceErr . message = "The provided count parameter is zero or a negative number." ;
}
if ( ( advanceEx . INVALID _STATE _ERR && advanceEx . code == advanceEx . INVALID _STATE _ERR ) || advanceEx . name == "InvalidStateError" ) {
advanceErr . type = "InvalidStateError" ;
advanceErr . message = "You are trying to skip data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( advanceErr ) ;
linq2indexedDB . prototype . core . abortTransaction ( index . objectStore . transaction ) ;
pw . error ( this , advanceErr ) ;
}
} ,
update : function ( obj ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor update" , result , e ) ;
try {
result . update ( obj ) ;
}
catch ( updateEx ) {
var updateError = internal . wrapException ( updateEx , "keyCursor - update" ) ;
if ( ( updateEx . DATA _ERR && updateEx . code == updateEx . DATA _ERR ) || updateEx . name == "DataError" ) {
updateError . type = "DataError" ;
updateError . message = "The underlying object store uses in-line keys and the property in value at the object store's key path does not match the key in this cursor's position." ;
}
if ( ( updateEx . READ _ONLY _ERR && ex . code == updateEx . READ _ONLY _ERR ) || updateEx . name == "ReadOnlyError" ) {
updateError . type = "ReadOnlyError" ;
updateError . message = "You are trying to update data in a readonly transaction." ;
}
if ( updateEx . name == "TransactionInactiveError" ) {
updateError . type = "TransactionInactiveError" ;
updateError . message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( updateEx . DATA _CLONE _ERR && updateEx . code == updateEx . DATA _CLONE _ERR ) || updateEx . name == "DataCloneError" ) {
updateError . type = "DataCloneError" ;
updateError . message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data." ;
}
if ( ( updateEx . INVALID _STATE _ERR && updateEx . code == updateEx . INVALID _STATE _ERR ) || updateEx . name == "InvalidStateError" ) {
updateError . type = "InvalidStateError" ;
updateError . message = "You are trying to update data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( updateError ) ;
linq2indexedDB . prototype . core . abortTransaction ( index . objectStore . transaction ) ;
pw . error ( this , updateError ) ;
}
} ,
remove : function ( ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "keyCursor remove" , result , e ) ;
try {
result [ "delete" ] ( ) ;
}
catch ( deleteEx ) {
var deleteError = internal . wrapException ( deleteEx , "keyCursor - delete" ) ;
if ( ( deleteEx . READ _ONLY _ERR && deleteEx . code == deleteEx . READ _ONLY _ERR ) || deleteEx . name == "ReadOnlyError" ) {
deleteError . type = "ReadOnlyError" ;
deleteError . message = "You are trying to remove data in a readonly transaction." ;
}
if ( deleteEx . name == "TransactionInactiveError" ) {
deleteError . type = "TransactionInactiveError" ;
deleteError . message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( deleteEx . INVALID _STATE _ERR && deleteEx . code == deleteEx . INVALID _STATE _ERR ) || deleteEx . name == "InvalidStateError" ) {
deleteError . type = "InvalidStateError" ;
deleteError . message = "You are trying to remove data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( deleteError ) ;
linq2indexedDB . prototype . core . abortTransaction ( index . objectStore . transaction ) ;
pw . error ( this , deleteError ) ;
}
}
} ;
pw . progress ( this , [ progressObj , result , e ] ) ;
returnData . push ( progressObj . data ) ;
}
result [ "continue" ] ( ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "keyCursor" ) ;
if ( ( ex . DATA _ERR && error . code == ex . DATA _ERR ) || ex . name == "DataError" ) {
error . type = "DataError" ;
error . message = "The provided range parameter isn't a valid key or key range." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ex . name == "TypeError" ) {
error . type = "TypeError" ;
error . message = "The provided directory parameter is invalid" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to insert data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( index . objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
get : function ( pw , source , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Get Started" , source ) ;
try {
handlers . IDBRequest ( source . get ( key ) ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
var transaction = source . transaction || source . objectStore . transaction ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Get completed" , result , transaction , e ) ;
pw . complete ( this , [ result , transaction , e ] ) ;
} , function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Get error" , args ) ;
pw . error ( this , args ) ;
} ) ;
} catch ( ex ) {
var txn = source . transaction || source . objectStore . transaction ;
var error = internal . wrapException ( ex , "get" ) ;
if ( error . code == ex . DATA _ERR || ex . name == "DataError" ) {
error . message = "The provided key isn't a valid key (must be an array, string, date or number)." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to retrieve data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , error ) ;
}
} ,
count : function ( pw , source , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Count Started" , source ) ;
try {
var req ;
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( key ) {
req = source . count ( key ) ;
}
else {
req = source . count ( ) ;
}
handlers . IDBRequest ( req ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
var transaction = source . transaction || source . objectStore . transaction ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Count completed" , result , transaction , e ) ;
pw . complete ( this , [ result , transaction , e ] ) ;
} , function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Count error" , args ) ;
pw . error ( this , args ) ;
} ) ;
} catch ( ex ) {
var txn = source . transaction || source . objectStore . transaction ;
var error = internal . wrapException ( ex , "count" ) ;
if ( error . code == ex . DATA _ERR || ex . name == "DataError" ) {
error . type = "DataError" ;
error . message = "The provided key isn't a valid key or keyRange." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to count data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to count data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( txn ) ;
pw . error ( this , error ) ;
}
} ,
getKey : function ( pw , index , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "GetKey Started" , index , key ) ;
try {
handlers . IDBRequest ( index . getKey ( key ) ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "GetKey completed" , result , index . objectStore . transaction , e ) ;
pw . complete ( this , [ result , index . objectStore . transaction , e ] ) ;
} , function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "GetKey error" , args ) ;
pw . error ( this , args ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "getKey" ) ;
if ( error . code == ex . DATA _ERR || ex . name == "DataError" ) {
error . type = "DataError" ;
error . message = "The provided key isn't a valid key or keyRange." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to getKey data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to getKey data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( index . objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
insert : function ( pw , objectStore , data , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Insert Started" , objectStore , data , key ) ;
try {
var req ;
if ( key /*&& !store.keyPath*/ ) {
req = handlers . IDBRequest ( objectStore . add ( data , key ) ) ;
} else {
/*if (key) linq2indexedDB.prototype.utilities.log("Key can't be provided when a keyPath is defined on the object store", store, key, data);*/
req = handlers . IDBRequest ( objectStore . add ( data ) ) ;
}
req . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
// Add key to the object if a keypath exists
if ( objectStore . keyPath ) {
data [ objectStore . keyPath ] = result ;
}
linq2indexedDB . prototype . core . dbDataChanged . fire ( { type : dataEvents . dataInserted , data : data , objectStore : objectStore } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Insert completed" , data , result , objectStore . transaction , e ) ;
pw . complete ( this , [ data , result , objectStore . transaction , e ] ) ;
} , function ( args /*error, e*/ ) {
var err = internal . wrapError ( args [ 1 ] , "insert" ) ;
// Fix for firefox & chrome
if ( args [ 1 ] . target && args [ 1 ] . target . errorCode == 4 ) {
err . type = "ConstraintError" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( err . type == "ConstraintError" ) {
var duplicateKey = key ;
if ( ! duplicateKey && objectStore . keyPath ) {
duplicateKey = data [ objectStore . keyPath ] ;
}
err . message = "A record for the key (" + duplicateKey + ") already exists in the database or one of the properties of the provided data has a unique index declared." ;
}
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
linq2indexedDB . prototype . utilities . logError ( err ) ;
pw . error ( this , err ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "insert" ) ;
if ( error . code == ex . DATA _ERR || ex . name == "DataError" ) {
error . type = "DataError" ;
var possibleKey = key ;
if ( ! possibleKey && objectStore . keyPath ) {
possibleKey = data [ objectStore . keyPath ] ;
}
if ( ! possibleKey ) {
error . message = "There is no key provided for the data you want to insert for an object store without autoIncrement." ;
} else if ( key && objectStore . keyPath ) {
error . message = "An external key is provided while the object store expects a keyPath key." ;
} else if ( typeof possibleKey !== "string"
&& typeof possibleKey !== "number"
&& typeof possibleKey !== "Date"
&& ! linq2indexedDB . prototype . utilities . isArray ( possibleKey ) ) {
error . message = "The provided key isn't a valid key (must be an array, string, date or number)." ;
}
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ( ex . READ _ONLY _ERR && ex . code == ex . READ _ONLY _ERR ) || ex . name == "ReadOnlyError" ) {
error . type = "ReadOnlyError" ;
error . message = "You are trying to insert data in a readonly transaction." ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to insert data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ( ex . DATA _CLONE _ERR && ex . code == ex . DATA _CLONE _ERR ) || ex . name == "DataCloneError" ) {
error . type = "DataCloneError" ;
error . message = "The data you are trying to insert could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to insert the data." ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to insert data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
update : function ( pw , objectStore , data , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Update Started" , objectStore , data , key ) ;
try {
var req ;
if ( key /*&& !store.keyPath*/ ) {
req = handlers . IDBRequest ( objectStore . put ( data , key ) ) ;
} else {
/*if (key) linq2indexedDB.prototype.utilities.log("Key can't be provided when a keyPath is defined on the object store", store, key, data);*/
req = handlers . IDBRequest ( objectStore . put ( data ) ) ;
}
req . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
if ( objectStore . keyPath && data [ objectStore . keyPath ] === undefined ) {
data [ objectStore . keyPath ] = result ;
}
linq2indexedDB . prototype . core . dbDataChanged . fire ( { type : dataEvents . dataUpdated , data : data , objectStore : objectStore } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Update completed" , data , result , objectStore . transaction , e ) ;
pw . complete ( this , [ data , result , objectStore . transaction , e ] ) ;
} , function ( args /*error, e*/ ) {
var err = internal . wrapError ( args [ 1 ] , "update" ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
linq2indexedDB . prototype . utilities . logError ( err ) ;
pw . error ( this , err ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "update" ) ;
if ( error . code == ex . DATA _ERR || ex . name == "DataError" ) {
error . type = "DataError" ;
var possibleKey = key ;
if ( ! possibleKey && objectStore . keyPath ) {
possibleKey = data [ objectStore . keyPath ] ;
}
if ( ! possibleKey ) {
error . message = "There is no key provided for the data you want to update for an object store without autoIncrement." ;
} else if ( key && objectStore . keyPath ) {
error . message = "An external key is provided while the object store expects a keyPath key." ;
} else if ( typeof possibleKey !== "string"
&& typeof possibleKey !== "number"
&& typeof possibleKey !== "Date"
&& ! linq2indexedDB . prototype . utilities . isArray ( possibleKey ) ) {
error . message = "The provided key isn't a valid key (must be an array, string, date or number)." ;
}
}
if ( ( ex . READ _ONLY _ERR && ex . code == ex . READ _ONLY _ERR ) || ex . name == "ReadOnlyError" ) {
error . type = "ReadOnlyError" ;
error . message = "You are trying to update data in a readonly transaction." ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
if ( ( ex . DATA _CLONE _ERR && ex . code == ex . DATA _CLONE _ERR ) || ex . name == "DataCloneError" ) {
error . type = "DataCloneError" ;
error . message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data." ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to update data on a removed object store." ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
remove : function ( pw , objectStore , key ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Remove Started" , objectStore , key ) ;
try {
handlers . IDBRequest ( objectStore [ "delete" ] ( key ) ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . core . dbDataChanged . fire ( { type : dataEvents . dataRemoved , data : key , objectStore : objectStore } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Remove completed" , result , objectStore . transaction , e ) ;
pw . complete ( this , [ result , objectStore . transaction , e ] ) ;
} ,
function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Remove error" , args ) ;
pw . error ( this , args ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "delete" ) ;
if ( ( ex . READ _ONLY _ERR && ex . code == ex . READ _ONLY _ERR ) || ex . name == "ReadOnlyError" ) {
error . type = "ReadOnlyError" ;
error . message = "You are trying to remove data in a readonly transaction." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to remove data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
clear : function ( pw , objectStore ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Clear Started" , objectStore ) ;
try {
handlers . IDBRequest ( objectStore . clear ( ) ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . core . dbDataChanged . fire ( { type : dataEvents . objectStoreCleared , objectStore : objectStore } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Clear completed" , result , objectStore . transaction , e ) ;
pw . complete ( this , [ result , objectStore . transaction , e ] ) ;
} ,
function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Clear error" , args ) ;
pw . error ( this , args ) ;
} ) ;
} catch ( ex ) {
var error = internal . wrapException ( ex , "clear" ) ;
if ( ( ex . READ _ONLY _ERR && ex . code == ex . READ _ONLY _ERR ) || ex . name == "ReadOnlyError" ) {
error . type = "ReadOnlyError" ;
error . message = "You are trying to clear data in a readonly transaction." ;
}
if ( ex . name == "TransactionInactiveError" ) {
error . type = "TransactionInactiveError" ;
error . message = "You are trying to clear data on an inactieve transaction. (The transaction was already aborted or committed)" ;
}
if ( ( ex . INVALID _STATE _ERR && ex . code == ex . INVALID _STATE _ERR ) || ( ex . NOT _ALLOWED _ERR && ex . code == ex . NOT _ALLOWED _ERR ) || ex . name == "InvalidStateError" ) {
error . type = "InvalidStateError" ;
error . message = "You are trying to clear data on a removed object store." ;
}
linq2indexedDB . prototype . utilities . logError ( error ) ;
linq2indexedDB . prototype . core . abortTransaction ( objectStore . transaction ) ;
pw . error ( this , error ) ;
}
} ,
deleteDb : function ( pw , name ) {
try {
if ( typeof ( window . indexedDB . deleteDatabase ) != "undefined" ) {
handlers . IDBBlockedRequest ( window . indexedDB . deleteDatabase ( name ) ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseRemoved } ) ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Delete Database Promise completed" , result , e , name ) ;
pw . complete ( this , [ result , e , name ] ) ;
} , function ( args /*error, e*/ ) {
var error = args [ 0 ] ;
var e = args [ 1 ] ;
// added for FF, If a db gets deleted that doesn't exist an errorCode 6 ('NOT_ALLOWED_ERR') is given
if ( e . currentTarget && e . currentTarget . errorCode == 6 ) {
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseRemoved } ) ;
pw . complete ( this , [ error , e , name ] ) ;
} else if ( implementation == implementations . SHIM
&& e . message == "Database does not exist" ) {
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseRemoved } ) ;
pw . complete ( this , [ error , e , name ] ) ;
} else {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Delete Database Promise error" , error , e ) ;
pw . error ( this , [ error , e ] ) ;
}
} , function ( args /*result, e*/ ) {
if ( args [ 0 ] == "blocked" ) {
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseBlocked } ) ;
}
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Delete Database Promise blocked" , args /*result*/ ) ;
pw . progress ( this , args /*[result, e]*/ ) ;
} ) ;
} else {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Delete Database function not found" , name ) ;
// Workaround for older versions of chrome and FireFox
// Doesn't delete the database, but clears him
linq2indexedDB . prototype . core . db ( name , - 1 ) . then ( function ( args /*result, e*/ ) {
var result = args [ 0 ] ;
var e = args [ 1 ] ;
linq2indexedDB . prototype . core . dbStructureChanged . fire ( { type : dbEvents . databaseRemoved } ) ;
pw . complete ( this , [ result , e , name ] ) ;
} ,
function ( args /*error, e*/ ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . error , "Clear Promise error" , args /*error, e*/ ) ;
pw . error ( this , args /*[error, e]*/ ) ;
} ,
function ( args /*dbConnection, event*/ ) {
var dbConnection = args [ 0 ] ;
var event = args [ 1 ] ;
// When an upgradeneeded event is thrown, create the non-existing object stores
if ( event . type == "upgradeneeded" ) {
for ( var i = 0 ; i < dbConnection . objectStoreNames . length ; i ++ ) {
linq2indexedDB . prototype . core . deleteObjectStore ( dbConnection . txn , dbConnection . objectStoreNames [ i ] ) ;
}
linq2indexedDB . prototype . core . closeDatabaseConnection ( dbConnection ) ;
}
} ) ;
}
} catch ( ex ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . exception , "Delete Database Promise exception" , ex ) ;
pw . error ( this , [ ex . message , ex ] ) ;
}
} ,
getDatabaseVersion : function ( db )
{
var dbVersion = parseInt ( db . version ) ;
if ( isNaN ( dbVersion ) || dbVersion < 0 ) {
return 0 ;
} else {
return dbVersion ;
}
} ,
wrapException : function ( exception , method ) {
return {
code : exception . code ,
severity : linq2indexedDB . prototype . utilities . severity . exception ,
orignialError : exception ,
method : method ,
type : "unknown"
} ;
} ,
wrapError : function ( error , method ) {
return {
severity : linq2indexedDB . prototype . utilities . severity . error ,
orignialError : error ,
type : ( error . target && error . target . error && error . target . error . name ) ? error . target . error . name : "unknown" ,
method : method
} ;
}
} ;
linq2indexedDB . prototype . core = {
db : function ( name , version ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
internal . db ( pw , name , version ) ;
} ) ;
} ,
transaction : function ( db , objectStoreNames , transactionType , autoGenerateAllowed ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( db . then ) {
db . then ( function ( args /*db, e*/ ) {
// Timeout necessary for letting it work on win8. If not, progress event triggers before listeners are coupled
if ( isMetroApp ) {
setTimeout ( function ( ) {
internal . transaction ( pw , args [ 0 ] , objectStoreNames , transactionType , autoGenerateAllowed ) ;
} , 1 ) ;
} else {
internal . transaction ( pw , args [ 0 ] , objectStoreNames , transactionType , autoGenerateAllowed ) ;
}
} ,
function ( args /*error, e*/ ) {
pw . error ( this , args ) ;
} ,
function ( args /**/ ) {
pw . progress ( this , args ) ;
} ) ;
} else {
if ( isMetroApp ) {
// Timeout necessary for letting it work on win8. If not, progress event triggers before listeners are coupled
setTimeout ( function ( ) {
internal . transaction ( pw , db , objectStoreNames , transactionType , autoGenerateAllowed ) ;
} , 1 ) ;
} else {
internal . transaction ( pw , db , objectStoreNames , transactionType , autoGenerateAllowed ) ;
}
}
} ) ;
} ,
objectStore : function ( transaction , objectStoreName ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( transaction . then ) {
transaction . then ( function ( /*txn, e*/ ) {
// transaction completed
// TODO: what todo in this case?
} , function ( args /*error, e*/ ) {
pw . error ( this , args ) ;
} , function ( args /*txn, e*/ ) {
internal . objectStore ( pw , args [ 0 ] , objectStoreName ) ;
} ) ;
} else {
internal . objectStore ( pw , transaction , objectStoreName ) ;
}
} ) ;
} ,
createObjectStore : function ( transaction , objectStoreName , objectStoreOptions ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( transaction . then ) {
transaction . then ( function ( /*txn, e*/ ) {
// txn completed
// TODO: what todo in this case?
} ,
function ( args /*error, e*/ ) {
// txn error or abort
pw . error ( this , args ) ;
} ,
function ( args /*txn, e*/ ) {
internal . createObjectStore ( pw , args [ 0 ] , objectStoreName , objectStoreOptions ) ;
} ) ;
} else {
internal . createObjectStore ( pw , transaction , objectStoreName , objectStoreOptions ) ;
}
} ) ;
} ,
deleteObjectStore : function ( transaction , objectStoreName ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( transaction . then ) {
transaction . then ( function ( /*txn, e*/ ) {
// txn completed
// TODO: what todo in this case?
} , function ( args /*error, e*/ ) {
// txn error
pw . error ( this , args ) ;
} ,
function ( args /*txn, e*/ ) {
internal . deleteObjectStore ( pw , args [ 0 ] , objectStoreName ) ;
} ) ;
} else {
internal . deleteObjectStore ( pw , transaction , objectStoreName ) ;
}
} ) ;
} ,
index : function ( objectStore , propertyName , autoGenerateAllowed ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, objectStore*/ ) {
internal . index ( pw , args [ 1 ] , propertyName , autoGenerateAllowed ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . index ( pw , objectStore , propertyName , autoGenerateAllowed ) ;
}
} ) ;
} ,
createIndex : function ( objectStore , propertyName , indexOptions ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, objectStore*/ ) {
internal . createIndex ( pw , args [ 1 ] , propertyName , indexOptions ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . createIndex ( pw , objectStore , propertyName , indexOptions ) ;
}
} ) ;
} ,
deleteIndex : function ( objectStore , propertyName ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, objectStore*/ ) {
internal . deleteIndex ( pw , args [ 1 ] , propertyName ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . deleteIndex ( pw , objectStore , propertyName ) ;
}
} ) ;
} ,
cursor : function ( source , range , direction ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( source . then ) {
source . then ( function ( args /*txn, source*/ ) {
internal . cursor ( pw , args [ 1 ] , range , direction ) ;
} , function ( args /*error, e*/ ) {
// store or index error
pw . error ( this , args ) ;
} ) ;
} else {
internal . cursor ( pw , source , range , direction ) ;
}
} ) ;
} ,
keyCursor : function ( index , range , direction ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( index . then ) {
index . then ( function ( args /*txn, index, store*/ ) {
internal . keyCursor ( pw , args [ 1 ] , range , direction ) ;
} , function ( args /*error, e*/ ) {
// index error
pw . error ( this , args ) ;
} ) ;
} else {
internal . keyCursor ( pw , index , range , direction ) ;
}
} ) ;
} ,
get : function ( source , key ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( source . then ) {
source . then ( function ( args /*txn, source*/ ) {
internal . get ( pw , args [ 1 ] , key ) ;
} , function ( args /*error, e*/ ) {
// store or index error
pw . error ( this , args ) ;
} ) ;
} else {
internal . get ( pw , source , key ) ;
}
} ) ;
} ,
count : function ( source ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( source . then ) {
source . then ( function ( args /*txn, source*/ ) {
internal . count ( pw , args [ 1 ] ) ;
} , function ( args /*error, e*/ ) {
// store or index error
pw . error ( this , args ) ;
} ) ;
} else {
internal . count ( pw , source ) ;
}
} ) ;
} ,
getKey : function ( index , key ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( index . then ) {
index . then ( function ( args /*txn, index, objectStore*/ ) {
internal . getKey ( pw , args [ 1 ] , key ) ;
} , function ( args /*error, e*/ ) {
// index error
pw . error ( this , args ) ;
} ) ;
} else {
internal . getKey ( pw , index , key ) ;
}
} ) ;
} ,
insert : function ( objectStore , data , key ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, store*/ ) {
internal . insert ( pw , args [ 1 ] , data , key ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . insert ( pw , objectStore , data , key ) ;
}
} ) ;
} ,
update : function ( objectStore , data , key ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, store*/ ) {
internal . update ( pw , args [ 1 ] , data , key ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . update ( pw , objectStore , data , key ) ;
}
} ) ;
} ,
remove : function ( objectStore , key ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, store*/ ) {
internal . remove ( pw , args [ 1 ] , key ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . remove ( pw , objectStore , key ) ;
}
} ) ;
} ,
clear : function ( objectStore ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
if ( objectStore . then ) {
objectStore . then ( function ( args /*txn, store*/ ) {
internal . clear ( pw , args [ 1 ] ) ;
} , function ( args /*error, e*/ ) {
// store error
pw . error ( this , args ) ;
} ) ;
} else {
internal . clear ( pw , objectStore ) ;
}
} ) ;
} ,
deleteDb : function ( name ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
internal . deleteDb ( pw , name ) ;
} ) ;
} ,
closeDatabaseConnection : function ( target ) {
var db ;
if ( target instanceof IDBCursor ) {
target = target . source ;
}
if ( target instanceof IDBDatabase ) {
db = target ;
} else if ( target instanceof IDBTransaction ) {
db = target . db ;
} else if ( target instanceof IDBObjectStore || target instanceof IDBRequest ) {
db = target . transaction . db ;
} else if ( target instanceof IDBIndex ) {
db = target . objectStore . transaction . db ;
2013-05-31 07:52:04 +00:00
}
2013-05-30 18:57:33 +00:00
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Close database Connection: " , db ) ;
db . close ( ) ;
} ,
abortTransaction : function ( transaction ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Abort transaction: " + transaction ) ;
// Calling the abort, blocks the database in IE10
if ( implementation != implementations . MICROSOFT ) {
transaction . abort ( ) ;
linq2indexedDB . prototype . core . closeDatabaseConnection ( transaction ) ;
}
} ,
transactionTypes : transactionTypes ,
dbStructureChanged : new eventTarget ( ) ,
dbDataChanged : new eventTarget ( ) ,
databaseEvents : dbEvents ,
dataEvents : dataEvents ,
implementation : implementation ,
implementations : implementations
} ;
if ( implementation == implementations . SHIM ) {
linq2indexedDB . prototype . core . indexSuffix = "IIndex" ;
} else {
linq2indexedDB . prototype . core . indexSuffix = "-Index" ;
}
// Region Functions
function initializeIndexedDb ( ) {
if ( window === 'undefined' ) {
return implementations . NONE ;
}
if ( window . indexedDB ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Native implementation" , window . indexedDB ) ;
return implementations . NATIVE ;
} else {
// Initialising the window.indexedDB Object for FireFox
if ( window . mozIndexedDB ) {
window . indexedDB = window . mozIndexedDB ;
if ( typeof window . IDBTransaction . READ _ONLY === "number"
&& typeof window . IDBTransaction . READ _WRITE === "number"
&& typeof window . IDBTransaction . VERSION _CHANGE === "number" ) {
transactionTypes . READ _ONLY = window . IDBTransaction . READ _ONLY ;
transactionTypes . READ _WRITE = window . IDBTransaction . READ _WRITE ;
transactionTypes . VERSION _CHANGE = window . IDBTransaction . VERSION _CHANGE ;
}
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "FireFox Initialized" , window . indexedDB ) ;
return implementations . MOZILLA ;
}
// Initialising the window.indexedDB Object for Chrome
else if ( window . webkitIndexedDB ) {
if ( ! window . indexedDB ) window . indexedDB = window . webkitIndexedDB ;
if ( ! window . IDBCursor ) window . IDBCursor = window . webkitIDBCursor ;
if ( ! window . IDBDatabase ) window . IDBDatabase = window . webkitIDBDatabase ; //if (!window.IDBDatabaseError) window.IDBDatabaseError = window.webkitIDBDatabaseError
if ( ! window . IDBDatabaseException ) window . IDBDatabaseException = window . webkitIDBDatabaseException ;
if ( ! window . IDBFactory ) window . IDBFactory = window . webkitIDBFactory ;
if ( ! window . IDBIndex ) window . IDBIndex = window . webkitIDBIndex ;
if ( ! window . IDBKeyRange ) window . IDBKeyRange = window . webkitIDBKeyRange ;
if ( ! window . IDBObjectStore ) window . IDBObjectStore = window . webkitIDBObjectStore ;
if ( ! window . IDBRequest ) window . IDBRequest = window . webkitIDBRequest ;
if ( ! window . IDBTransaction ) window . IDBTransaction = window . webkitIDBTransaction ;
if ( ! window . IDBOpenDBRequest ) window . IDBOpenDBRequest = window . webkitIDBOpenDBRequest ;
if ( typeof window . IDBTransaction . READ _ONLY === "number"
&& typeof window . IDBTransaction . READ _WRITE === "number"
&& typeof window . IDBTransaction . VERSION _CHANGE === "number" ) {
transactionTypes . READ _ONLY = window . IDBTransaction . READ _ONLY ;
transactionTypes . READ _WRITE = window . IDBTransaction . READ _WRITE ;
transactionTypes . VERSION _CHANGE = window . IDBTransaction . VERSION _CHANGE ;
}
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Chrome Initialized" , window . indexedDB ) ;
return implementations . GOOGLE ;
}
// Initialiseing the window.indexedDB Object for IE 10 preview 3+
else if ( window . msIndexedDB ) {
window . indexedDB = window . msIndexedDB ;
transactionTypes . READ _ONLY = 0 ;
transactionTypes . READ _WRITE = 1 ;
transactionTypes . VERSION _CHANGE = 2 ;
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "IE10+ Initialized" , window . indexedDB ) ;
return implementations . MICROSOFT ;
}
2013-05-31 07:52:04 +00:00
2013-05-30 18:57:33 +00:00
// Initialising the window.indexedDB Object for IE 8 & 9
else if ( navigator . appName == 'Microsoft Internet Explorer' ) {
try {
window . indexedDB = new ActiveXObject ( "SQLCE.Factory.4.0" ) ;
window . indexedDBSync = new ActiveXObject ( "SQLCE.FactorySync.4.0" ) ;
} catch ( ex ) {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Initializing IE prototype exception" , ex ) ;
}
if ( window . JSON ) {
window . indexedDB . json = window . JSON ;
window . indexedDBSync . json = window . JSON ;
} else {
var jsonObject = {
parse : function ( txt ) {
if ( txt === "[]" ) return [ ] ;
if ( txt === "{}" ) return { } ;
throw { message : "Unrecognized JSON to parse: " + txt } ;
}
} ;
window . indexedDB . json = jsonObject ;
window . indexedDBSync . json = jsonObject ;
}
// Add some interface-level constants and methods.
window . IDBDatabaseException = {
UNKNOWN _ERR : 0 ,
NON _TRANSIENT _ERR : 1 ,
NOT _FOUND _ERR : 2 ,
CONSTRAINT _ERR : 3 ,
DATA _ERR : 4 ,
NOT _ALLOWED _ERR : 5 ,
SERIAL _ERR : 11 ,
RECOVERABLE _ERR : 21 ,
TRANSIENT _ERR : 31 ,
TIMEOUT _ERR : 32 ,
DEADLOCK _ERR : 33
} ;
window . IDBKeyRange = {
SINGLE : 0 ,
LEFT _OPEN : 1 ,
RIGHT _OPEN : 2 ,
LEFT _BOUND : 4 ,
RIGHT _BOUND : 8
} ;
window . IDBRequest = {
INITIAL : 0 ,
LOADING : 1 ,
DONE : 2
} ;
window . IDBTransaction = {
READ _ONLY : 0 ,
READ _WRITE : 1 ,
VERSION _CHANGE : 2
} ;
transactionTypes . READ _ONLY = 0 ;
transactionTypes . READ _WRITE = 1 ;
transactionTypes . VERSION _CHANGE = 2 ;
window . IDBKeyRange . only = function ( value ) {
return window . indexedDB . range . only ( value ) ;
} ;
window . IDBKeyRange . leftBound = function ( bound , open ) {
return window . indexedDB . range . lowerBound ( bound , open ) ;
} ;
window . IDBKeyRange . rightBound = function ( bound , open ) {
return window . indexedDB . range . upperBound ( bound , open ) ;
} ;
window . IDBKeyRange . bound = function ( left , right , openLeft , openRight ) {
return window . indexedDB . range . bound ( left , right , openLeft , openRight ) ;
} ;
window . IDBKeyRange . lowerBound = function ( left , openLeft ) {
return window . IDBKeyRange . leftBound ( left , openLeft ) ;
} ;
return implementations . MICROSOFTPROTOTYPE ;
} else if ( window . shimIndexedDB ) {
window . indexedDB = window . shimIndexedDB ;
return implementations . SHIM ;
} else {
linq2indexedDB . prototype . utilities . log ( linq2indexedDB . prototype . utilities . severity . information , "Your browser doesn't support indexedDB." ) ;
return implementations . NONE ;
}
}
} ;
function deferredHandler ( handler , request ) {
return linq2indexedDB . prototype . utilities . promiseWrapper ( function ( pw ) {
try {
handler ( pw , request ) ;
} catch ( e ) {
e . type = "exception" ;
pw . error ( request , [ e . message , e ] ) ;
}
finally {
request = null ;
}
} ) ;
} ;
function IDBSuccessHandler ( pw , request ) {
request . onsuccess = function ( e ) {
pw . complete ( e . target , [ e . target . result , e ] ) ;
} ;
} ;
function IDBErrorHandler ( pw , request ) {
request . onerror = function ( e ) {
pw . error ( e . target , [ e . target . errorCode , e ] ) ;
} ;
} ;
function IDBAbortHandler ( pw , request ) {
request . onabort = function ( e ) {
pw . error ( e . target , [ e . target . errorCode , e ] ) ;
} ;
} ;
function IDBVersionChangeHandler ( pw , request ) {
request . onversionchange = function ( e ) {
pw . progress ( e . target , [ e . target . result , e ] ) ;
} ;
} ;
function IDBCompleteHandler ( pw , request ) {
request . oncomplete = function ( e ) {
pw . complete ( e . target , [ e . target , e ] ) ;
} ;
} ;
function IDBRequestHandler ( pw , request ) {
IDBSuccessHandler ( pw , request ) ;
IDBErrorHandler ( pw , request ) ;
} ;
function IDBCursorRequestHandler ( pw , request ) {
request . onsuccess = function ( e ) {
if ( ! e . target . result ) {
pw . complete ( e . target , [ e . target . result , e ] ) ;
} else {
pw . progress ( e . target , [ e . target . result , e ] ) ;
}
} ;
IDBErrorHandler ( pw , request ) ;
} ;
function IDBBlockedRequestHandler ( pw , request ) {
IDBRequestHandler ( pw , request ) ;
request . onblocked = function ( e ) {
pw . progress ( e . target , [ "blocked" , e ] ) ;
} ;
} ;
function IDBOpenDbRequestHandler ( pw , request ) {
IDBBlockedRequestHandler ( pw , request ) ;
request . onupgradeneeded = function ( e ) {
pw . progress ( e . target , [ e . target . transaction , e ] ) ;
} ;
} ;
function IDBDatabaseHandler ( pw , database ) {
IDBAbortHandler ( pw , database ) ;
IDBErrorHandler ( pw , database ) ;
IDBVersionChangeHandler ( pw , database ) ;
} ;
function IDBTransactionHandler ( pw , txn ) {
IDBCompleteHandler ( pw , txn ) ;
IDBAbortHandler ( pw , txn ) ;
IDBErrorHandler ( pw , txn ) ;
} ;
} ) ( window , typeof Windows !== "undefined" ) ;
window . linq2indexedDB = linq2indexedDB ;
} else {
// Web Worker Thread
onmessage = function ( event ) {
var data = event . data . data ;
var filtersString = event . data . filters || "[]" ;
var sortClauses = event . data . sortClauses || [ ] ;
var filters = JSON . parse ( filtersString , linq2indexedDB . prototype . utilities . deserialize ) ;
var returnData = linq2indexedDB . prototype . utilities . filterSort ( data , filters , sortClauses ) ;
postMessage ( returnData ) ;
return ;
} ;
}
// Extend array for Opera
2013-05-31 07:52:04 +00:00
//Array.prototype.contains = function (obj) {
// return this.indexOf(obj) > -1;
//};