db.js is a wrapper for IndexedDB to make it easier to work against

Related tags

Storage db.js
Overview

Build Status Selenium Test Status npm version bower version License

Selenium Test Status

db.js

db.js is a wrapper for IndexedDB to make it easier to work against, making it look more like a queryable API.

Usage

Add a reference to db.js in your application before you want to use IndexedDB:

<script src='/dist/db.js'></script>

Alternatively, db.js includes an optional define call, and can be loaded as a module using the AMD loader of your choice.

Opening/Creating a database and connection

Once you have the script included you can then open connections to each different database within your application:

var server;
db.open({
    server: 'my-app',
    version: 1,
    schema: {
        people: {
            key: {keyPath: 'id', autoIncrement: true},
            // Optionally add indexes
            indexes: {
                firstName: {},
                answer: {unique: true}
            }
        }
    }
}).then(function (s) {
    server = s;
});

Note that open() takes an options object with the following properties:

  • version - The current version of the database to open. Should be an integer. You can start with 1. You must increase the version if updating the schema or otherwise the schema property will have no effect.

  • server - The name of this server. Any subsequent attempt to open a server with this name (and with the current version) will reuse the already opened connection (unless it has been closed).

  • schema - Expects an object, or, if a function is supplied, a schema object should be returned). A schema object optionally has store names as keys (these stores will be auto-created if not yet added and modified otherwise). The values of these schema objects should be objects, optionally with the property "key" and/or "indexes". The "key" property, if present, should contain valid createObjectStore parameters (keyPath or autoIncrement). The "indexes" property should contain an object whose keys are the desired index keys and whose values are objects which can include the optional parameters and values available to createIndex (unique, multiEntry, and, for Firefox-only, locale). Note that the keyPath of the index will be set to the supplied index key, or if present, a keyPath property on the provided parameter object. Note also that when a schema is supplied for a new version, any object stores not present on the schema object will be deleted.

A connection is intended to be persisted, and you can perform multiple operations while it's kept open.

In the event a connection has already been opened for modification (whether in the same instance or in another tab/window), a blocking error will occur, for which you can listen by adding a Promise.catch statement and communicate with blocking instances still holding a connection so that they may close the connection. You can then return the resume property (a promise) to recover to continue the original open operation and proceed to the following then condition.

var server;
db.open({
    // ...
}).catch(function (err) {
    if (err.type === 'blocked') {
        oldConnection.close();
        return err.resume;
    }
    // Handle other errors here
    throw err;
}).then(function (s) {
    server = s;
    // One can add a versionchange handler here to self-close
    //   the connection upon future upgrade attempts (likely to
    //   be one made in other tabs) and thereby
    //   avoid such attempts having to face blocking errors.
});

Check out the /tests/specs folder for more examples.

General server/store methods

Note that by default the methods below (not including close, addEventListener, and removeEventListener) can be called either as server.people.xxx( arg1, arg2, ... ) or server.xxx( 'people', arg1, arg2, ... ).

To reduce some memory requirements or avoid a however unlikely potential conflict with server method names, however, one may supply noServerMethods: true as part of options supplied to db.open() and under such conditions, only the second method signature above can be used.

Store modification

Adding items

server.people.add({
    firstName: 'Aaron',
    lastName: 'Powell',
    answer: 42
}).then(function (item) {
    // item stored
});

Multiple items can be added as additional arguments to add. Another way multiple items can be added is when an array is supplied for any of the arguments in which case, its top level contents will be treated as separate items. If you want unambiguous results where the data to be added could itself be an array, be sure to wrap item supplied in your argument within an array.

Note also when add is provided with objects containing a property item (and optionally a key property), the value of item will be treated as the record to be added, while any key will be used as the key. To supply unambiguous items (where you are not sure whether item may exist on the record to be added), you may wish to consistently wrap your items within an object with an item property even if you are not supplying a key.

Updating

server.people.update({
    firstName: 'Aaron',
    lastName: 'Powell',
    answer: 42
}).then(function (item) {
    // item added or updated
});

As with add, update shares the same behaviors as far as flattening of the top level of array arguments and checking of item/key properties, so if you need unambiguous results, please see the discussion above.

Using update will cause a record to be added if it does not yet exist.

put is also available as an alias of update.

Removing

server.people.remove(1).then(function (key) {
    // item removed
});

delete is also available as an alias of remove.

Clearing

This allows removing all items in a table/collection:

server.people.clear()
    .then(function() {
        // all table data is gone.
    });

Fetching

Getting a single object by key

server.people.get(5)
    .then(function (results) {
        // do something with the results
    });

Getting a single object by key range

If more than one match, it will retrieve the first.

With a MongoDB-style range:

server.people.get({gte: 1, lt: 3})
    .then(function (results) {
        // do something with the results
    });

With an IDBKeyRange:

server.people.get(IDBKeyRange.bound(1, 3, false, true))
    .then(function (results) {
        // do something with the results
    });

Querying

Queries require one or more methods to determine the type of querying (all items, filtering, applying ranges, limits, distinct values, or custom mapping--some of which can be combined with some of the others), any methods for cursor direction, and then a subsequent call to execute() (followed by a then or catch).

Querying all objects
server.people.query()
    .all()
    .execute()
    .then(function (results) {
        // do something with the results
    });
Querying using indexes
server.people.query('specialProperty')
    .all()
    .execute()
    .then(function (results) {
        // do something with the results (items which possess `specialProperty`)
    });
Querying with filtering

Note that unlike the other methods after a query, filter can be executed multiple times.

Filter with property and value
server.people.query()
    .filter('firstName', 'Aaron')
    .execute()
    .then(function (results) {
        // do something with the results
    });
Filter with function
server.people.query()
    .filter(function(person) {return person.group === 'hipster';})
    .execute()
    .then(function (results) {
        // do something with the results
    });
Querying for distinct values

Will return only one record:

server.people
    .query('firstName')
    .only('Aaron')
    .distinct()
    .execute()
    .then(function (data) {
        //
    });
Querying with ranges

All ranges supported by IDBKeyRange can be used (only, bound, lowerBound, upperBound).

server.people.query('firstName')
    .only('Aaron')
    .then(function (results) {
        // do something with the results
    });

server.people.query('answer')
    .bound(30, 50)
    .then(function (results) {
        // do something with the results
    });

MongoDB-style ranges (as implemented in idb-range-driven libraries) are also supported:

server.people.query('firstName')
    .range({eq: 'Aaron'})
    .then(function (results) {
        // do something with the results
    });

server.people.query('answer')
    .range({gte: 30, lte: 50})
    .then(function (results) {
        // do something with the results
    });

Note that IndexedDB allows you to use array keys within ranges (and other methods where a key is accepted) as long as you have created your store with an array keyPath (and optionally with an index keyPath).

// The definition:
schema: {
    people: {
        key: {
            keyPath: ['lastName', 'firstName']
        },
        indexes: {
            name: {
                keyPath: ['lastName', 'firstName']
            },
            lastName: {},
            firstName: {}
        }
    }
}

// ...elsewhere...

// The query:
s.test.query('name')
    .only(['Zamir', 'Brett'])
    .execute()
    .then(function (results) {
        // do something with the results
    });
Limiting cursor range

Unlike key ranges which filter by the range of present values, one may define a cursor range to determine whether to skip through a certain number of initial result items and to select how many items (up to the amount available) should be retrieved from that point in the navigation of the cursor.

server.people
    .query('firstName')
    .all()
    .limit(1, 3)
    .execute()
    .then(function (data) {
        // Skips the first item and obtains the next 3 items (or less if there are fewer)
    });

Cursor direction (desc)

The desc method may be used to change cursor direction to descending order:

server.people.query()
    .all()
    .desc()
    .execute()
    .then(function (results) {
        // Array of results will be in descending order
    });

Retrieving special types of values

Keys

Keys may be retrieved with or without an index:

server.people.query('firstName')
    .only('Aaron')
    .keys()
    .execute()
    .then(function (results) {
        // `results` will contain one 'Aaron' value for each
        //    item in the people store with that first name
    });
Mapping

The map method allows you to modify the object being returned without correspondingly modifying the actual object stored:

server.people
    .query('age')
    .lowerBound(30)
    .map(function (value) {
        return {
            fullName: value.firstName + ' ' + value.lastName,
            raw: value
        };
    })
    .execute()
    .then(function (data) {
        // An array of people objects containing `fullName` and `raw` properties
    });
Counting

To count while utilizing an index and/or the query-returned methods, you can use the following:

server.people.query('firstName')
    .only('Aaron')
    .count()
    .execute()
    .then(function (results) {
        // `results` will equal the total count of "Aaron"'s
    });

If you only need a count of items in a store with only a key or range, you can utilize server.count:

// With no arguments (count all items)
server.people.count().then(function (ct) {
    // Do something with "ct"
});

// With a key
server.people.count(myKey).then(function (ct) {
    // Do something with "ct"
});

// With a MongoDB-style range
server.people.count({gte: 1, lt: 3}).then(function (ct) {
    // Do something with "ct"
});

// With an IDBKeyRange range
server.people.count(IDBKeyRange.bound(1, 3, false, true)).then(function (ct) {
    // Do something with "ct"
});

Atomic updates

Any query that returns a range of results can also be set to modify the returned records automatically. This is done by adding .modify() at the end of the query (right before .execute()).

modify only runs updates on objects matched by the query, and still returns the same results to the Promise's then() method (however, the results will have the modifications applied to them).

Examples:

// grab all users modified in the last 10 seconds,
server.users.query('last_mod')
    .lowerBound(new Date().getTime() - 10000)
    .modify({last_mod: new Date.getTime()})
    .execute()
    .then(function(results) {
        // now we have a list of recently modified users
    });

// grab all changed records and atomically set them as unchanged
server.users.query('changed')
    .only(true)
    .modify({changed: false})
    .execute()
    .then(...)

// use a function to update the results. the function is passed the original
// (unmodified) record, which allows us to update the data based on the record
// itself.
server.profiles.query('name')
    .lowerBound('marcy')
    .modify({views: function(profile) { return profile.views + 1; }})
    .execute()
    .then(...)

modify changes will be seen by any map functions.

modify can be used after: all, filter, ranges (range, only, bound, upperBound, and lowerBound), desc, distinct, and map.

Other server methods

Closing connection

server.close();

Retrieving the indexedDB.open result object in use

var db = server.getIndexedDB();
var storeNames = db.objectStoreNames;

Server event handlers

All of the following are optional.

server.addEventListener('abort', function (e) {
    // Handle abort event
});
server.addEventListener('error', function (err) {
    // Handle any errors (check err.name)
});
server.addEventListener('versionchange', function (e) {
    // Be notified of version changes (can use e.oldVersion and e.newVersion)
});

All of the following shorter equivalent forms (which also work internally via addEventListener) are optional and can be chained as desired.

server.abort(function (e) {
    // Handle abort event
}).error(function (err) {
    // Handle any errors (check err.name)
}).versionchange(function (e) {
    // Be notified of version changes (can use e.oldVersion and e.newVersion)
});

See the IndexedDB spec for the possible exceptions.

Deleting a database

db.delete(dbName).then(function (ev) {
    // Should have been a successful database deletion
}, function (err) {
    // Error during database deletion
});

Note that, in line with the behavior of the deleteDatabase method of IndexedDB, delete will not actually produce an error if one attempts to delete a database which doesn't exist or even if a non-string is supplied.

However, as with the open operation, a delete operation will produce an error so long as there are already opened blocking connections (i.e., those allowing for database modification) which are open elsewhere in the browser. You can nevertheless recover as follows:

db.delete(dbName).catch(function (err) {
    if (err.type === 'blocked') {
        oldConnection.close();
        return err.resume;
    }
    // Handle other errors here
    throw err;
}).then(function (ev) {
    // Should have been a successful database deletion
});

See the documentation on open for more on such recovery from blocking connections.

Comparing two keys

Returns 1 if the first key is greater than the second, -1 if the first is less than the second, and 0 if the first is equal to the second.

db.cmp(key1, key2).then(function (ret) {
    // Use `ret`
});

Promise notes

db.js used the ES6 Promise spec to handle asynchronous operations.

All operations that are asynchronous will return an instance of the ES6 Promise object that exposes a then method which will take up to two callbacks, onFulfilled and onRejected. Please refer to the ES6 Promise spec for more information.

As of version 0.7.0 db.js's Promise API is designed to work with ES6 Promises, please polyfill it if you would like to use another promise library.

Contributor notes

  • npm install to install all the dependencies

In browser:

  • npm run grunt test:local to run the mocha server
  • Open (http://localhost:9999/tests)[] to run the mocha tests

In Node.js:

  • npm test

or to avoid Saucelabs if set up:

  • npm run grunt phantom

or to also avoid PhantomJS:

  • npm run grunt dev

License

The MIT License

Copyright (c) 2012-2015 Aaron Powell, Brett Zamir

Comments
  • Server handlers

    Server handlers

    Note that for the onerror test with a bad version (too low), Firefox does not recover. Even if we wrap the open() in a try-catch block, Firefox throws an uncatchable error for such VersionError errors.

    I think therefore, the only way we could work around this would be to always open the current version, reflect on what that version is, close the connection, and then either open the connection if the user-supplied version is good, or immediately reject if it is bad. I don't think it is worth doing this though, just to workaround a bug in Firefox. (I haven't reported the issue yet, however.)

    opened by brettz9 20
  • Prototype PhantomJS as a test runner

    Prototype PhantomJS as a test runner

    PhantomJS 2.0 supports indexedDB (from my initial reading). I'd like to see how the tests run in PhantomJS and whether that can be used for CI instead of SauceLabs.

    enhancement 
    opened by aaronpowell 17
  • differences between Firefox and Chrome behaviour on first database create

    differences between Firefox and Chrome behaviour on first database create

    At the first database create, right after that, Google Chrome for Windows does not allow the call

    server.people.add( {
        firstName: 'Aaron',
        lastName: 'Powell',
        answer: 42
    } ).done( function ( item ) {
        console.log("Item 1 stored");
    } );
    

    The error message is : Cannot call method 'add' of undefined After creating the database, after a page Reload (opening an already created database) the above constructions works just fine ! Firefox works fine allowing that type of call even for the first time!

    The sollution I've found is:

    server.add( 'people', {
        firstName: 'Aaron',
        lastName: 'Powell',
        answer: 42
    } ).done( function ( item ) {
        console.log("Item 1 stored");
    } );
    

    Should I do something special on first database creation on Chrome?

    opened by brailateo 15
  • Prototype

    Prototype

    Change to prototype-based methods internally (to reduce functions added into memory); refactor Query to have succincter syntax (via createReturnObject).

    Note that I have not committed dist as it could cause problems upon merges. You can just build dist when doing tests or what not and commit it yourself when you finish a merge or merges. I think this tends to be the most common practice anyways.

    opened by brettz9 12
  • Transaction management

    Transaction management

    I like the idea of db.js – a simple promises-based API that transparently wraps the IndexedDB API (some other libraries have a bit too much magic behind the scenes for me to be comfortable). I really like the “modify” syntax for updating objects too. There are a few minor features I want to recommend adding… but that is for another time.

    My main problem with db.js is transaction support. Currently, each db.js operation runs in its own transaction. This is nice for simplicity, but it completely kills performance. Try doing 1000 adds in a single transaction versus 1000 adds in 1000 different transactions.

    The problem is, transaction handling is kind of messy. Compared to the current db.js, adding transactions to the API would be one more thing for users to worry about. And IndexedDB transactions are pretty confusing to work with due to how auto-committing works.

    How might adding transactions to the db.js API work? Here’s one (probably stupid) idea. Currently, if you wanted to do 1000 adds, you might do something like this:

    var promises = [];
    for (var i = 0; i < 1000; i++) {
        promises.push(server.whatever.add(data[i]));
    }
    return Promise.all(promises);
    

    But that uses 1000 transactions. Here's an alternative:

    var tx = server.tx("whatever", "readwrite");
    for (var i = 0; i < 1000; i++) {
        tx.whatever.add(data[i]);
    }
    return tx.complete();
    

    This would do all the adds in a single transaction tx created by server.tx. server.tx is a wrapper around IDBDatabase.transaction which adds access to the object stores specified in the first argument and complete, a function that returns a promise that resolves after the oncomplete event for the transaction fires. And the first code example would still work just as it does today, the transaction API would be purely optional to use.

    This API was not handed down to me on clay tablets from God. It's just an idea. The larger point is, something is needed to deal with transactions or it’ll continue to be impossible to write performant IDB-heavy apps with db.js.

    Is there interest in adding something like this to db.js? Or do you see db.js as something that should not have this level of complexity?

    opened by dumbmatter 11
  • Add blocked event handler to open() and delete() (with docs and tests),

    Add blocked event handler to open() and delete() (with docs and tests),

    allowing additional "resume" promise property for user to easily resume promise chain (if blocking undone by closing old db connection); Cache server by version as well as name to allow upgrades of same name (and document); Avoid apparently broken saucelabs directive in grunt processing; Minor: Utilize forEach over for loop; Minor: Replace "magic" numbers with descriptive vars. in open() testing Minor: Clarify delete testing by moving db opening to beforeEach (and add some content)

    I recommend starting with the README as the main added features are described there.

    opened by brettz9 9
  • Improvements to the promises implementation

    Improvements to the promises implementation

    Firstly, thank you for a great library. We've used this library successfully on a recent project at @EnableSoftware.

    In the course of using this library, we've found a couple of issues which if addressed we feel will make the library even nicer to work with:

    1. It seems that throughout the code, a string is thrown, rather than an Error (see, for example, A String is not an Error;
    2. Code both rejects and throws;
    3. In a number of places in the code, error handlers appear to be attached too late.

    An example of these issues is the get() method on the Server object:

    this.get = function ( table , id ) {
        if ( closed ) {
            throw 'Database has been closed';
        }
        var transaction = db.transaction( table ),
            store = transaction.objectStore( table );
    
        var req = store.get( id );
        return new Promise(function(resolve, reject){
          req.onsuccess = function ( e ) {
              resolve( e.target.result );
          };
          transaction.onerror = function ( e ) {
              reject( e );
          };
        });
    };
    

    Here we see that a string, rather than an Error is thrown. I believe that the first block in this method should be replaced by

    if ( closed ) {
        throw new Error('Database has been closed');
    }
    

    or should return a Promise.reject() (see below).

    Secondly, we see in the get() method that this method either throws, or returns a Promise. This means that calling code has to handle both cases. This means a try/catch and a .then()/.catch().

    I realise that there is a school of thought that suggests throwing rather than rejecting, but this leads to, in my opinion, overly verbose calling code (the linked article acknowledges that this practice is controversial, and that some people recommend "Reject[ing] whenever possible, [as] it's more performant because throw breaks the stack.").

    With our current codebase, we have had to litter our code which consumes db.js with lots of code like the following, just to handle both the errors thrown and the promises returned:

    return new Promise(function (resolve, reject) {
        try {
            db.open({
                server: "name",
                version: 1
            }).then(function (s) {
                resolve(s);
            }, function (e) {
                reject(e);
            });
        } catch (e) {
            reject(e);
        }
    });
    

    It would be nicer if consumers of db.js only needed to handle the returned promise.

    Finally, it appears that in some cases error handlers are attached too late. In the get() method, above, we can see that a error handler is added to the transaction after the call to store.get(id). It appears from our testing that this means that if an error is thrown during the get operation, it is not handled by the error handler attached to the transaction. It appears that this is a pattern that is employed throughout the code, not just in this get() method.

    Given the concerns above, a re-factored get() method could look something like:

    this.get = function ( table , id ) {
        if ( closed ) {
            return Promise.reject(new Error('Database has been closed'));
        }
    
        return new Promise(function (resolve, reject) {
            var transaction = db.transaction(table);
    
            transaction.onerror = function ( e ) {
                reject( e );
            };
    
            var store = transaction.objectStore(table),
                req = store.get( id );
    
            req.onsuccess = function ( e ) {
                resolve( e.target.result );
            };
        });
    };
    

    I believe that this addresses the concerns outlined above. Please let me know if any of this requires further information or examples.

    opened by cgwrench 9
  • Insert multiple documents

    Insert multiple documents

    I'm trying to insert multiple documents but are inserting only the first document. ex:

    server.person.add({JSON1}).done(function(item){ server.person.add({JSON2}).done(function(item){ alert('ok'); }); });

    The return is: [{JSON1}] Expected: [{JSON1}, {JSON2}]

    is it something very wrong I'm doing? if you place the two in a json array inserts it more when I try to insert anything else he does not insert.

    opened by torto 9
  • Documentation: execute() method does not exist in query()

    Documentation: execute() method does not exist in query()

    In README.md:

    server.people.query( 'firstName' , 'Aaron' )
          .execute()
          .then( function ( results ) {
              // do something with the results
          } );
    

    instead it should be:

    server.people.query( 'firstName' , 'Aaron' )
          .all()
          .execute()
          .then( function ( results ) {
              // do something with the results
          } );
    

    or:

    server.people.query( 'firstName' , 'Aaron' )
          .filter()
          .execute()
          .then( function ( results ) {
              // do something with the results
          } );
    
    opened by miqmago 8
  • Library should not throw immediately if indexedDB cannot be found.

    Library should not throw immediately if indexedDB cannot be found.

    I'm trying to write tests for features the require this library and IndexedDB does not exist in our test environment (Node with Domino JS).

    We can easily swap out our implementation with a fake IndexedDB, but unfortunately, this library throws as soon as it's evaluated.

    I'm considering a pull request that would lazily load the global reference to IndexedDB after the first request rather than immediately upon evaluation.

    Thoughts?

    opened by lukebayes 8
  • Allow array of objects to be supplied to update() for batch processin…

    Allow array of objects to be supplied to update() for batch processin…

    …g (paralleling add() behavior), addressing issue #123; add test; simplify add(); rmv trailing spaces

    Replacing outdated PR #131 .

    Note that some dist/ changes appear to be due to my having just installed babel which was apparently a more recent version than that you used.

    opened by brettz9 7
  • Global 'server' variable becomes undefined?

    Global 'server' variable becomes undefined?

    I'm using a function to open the database and try to use the assigned server variable in other functions:

    var server;
    
    function OpenDB() {
      db.open({
          .....
      }).then(function(s) {
        server = s;
      });
    }
    
    function DoSomethingInDB() {
      console.log("Server var:", server); <<<< undefined
      server.mytable.count().then(function(ct) {  <<<error: Cannot read properties of undefined (reading 'mytable')
        ...
      });
    }
    
    ....
    
    OpenDB();
    DoSomethingInDB();
    

    My database is successfully created in OpenDB(). Unfortunately, it seems that the global server var becomes undefined outside the OpenDB function. From documentation:

    A connection is intended to be persisted, and you can perform multiple operations while it's kept open

    But I didn't close it. Bah? For sure I'm doing something wrong. Can you help me? Thanks.

    opened by radiolondra 0
  • "undefined is not a function (evaluating 'a.addEventListener(b,c)')","name":"TypeError"}

    Issue:

    Got an exception when tried to add listener to db. "undefined is not a function (evaluating 'a.addEventListener(b,c)')","name":"TypeError"}

    How to reproduce on Safari of iOS 8/9:

    var server;
    db.open({
        server: 'my-app',
        version: 1,
        schema: {
            people: {
                key: {keyPath: 'id', autoIncrement: true},
                // Optionally add indexes
                indexes: {
                    firstName: {},
                    answer: {unique: true}
                }
            }
        }
    }).then(function (s) {
        server = s;
       // The line will throw error
        server.addEventListener('versionchange', function(e) {
        });
    });
    
    opened by ls-simon-he 3
  • Schema versioning

    Schema versioning

    There are a bunch of minor fixes or refactoring, testing, and doc improvements in this PR, but the main change in this PR is versioning of schemas. It is backwards-compatible, with the exception that now it will delete unused indexes by default (which I think should be fairly safe and fits in with the behavior that we auto-delete unused stores) and it will also destroy and rebuild stores if they are respecified with different options (e.g., a different keyPath). The README ought to be helpful in visualizing the new schemas (and schemaBuilder) formats.

    • Fix: Ensure return after rejection (in get and count);
    • Fix: Better type-checking for bad schema objects;
    • Fix: Polyfill newVersion for PhantomJS
    • API change (breaking)/Feature: Add clearUnusedIndexes option (defaults to true);
    • API change (breaking)/Feature: Destroy and rebuild stores or indexes if present with different options;
    • API addition: Support a schemas object keyed to version with values as schema objects. (Utilizes own IdbImport class, relying on own fork of idb-schema at least for now.); idb-schema callbacks will be passed db.js Server as second argument
    • API addition: Support a schemaBuilder callback which accepts an idb-schema object for incremental, versioned schema building and whose addCallback method will be passed an enhanced upgradeneeded event object with a Server object as a second argument for making db.js-style queries (e.g., to modify store content), albeit with certain limitations. Along with schemas, addresses issues #84/#109
    • API addition: Support a clearUnusedStores property to conditionally avoid deleting old stores.
    • API addition: Add db.del alias of db.delete
    • API addition: Add del() alias on Server for parity with idb-batch (likely to use or adapt for multiple change transactions);
    • Feature: Change schema (and allow for schemas) to differentiate between "mixed", "whole", "idb-schema", and "merge" types with schemaType option (defaulting to mixed for schema and whole for schemas, maintaining prior behavior in backward-compatible manner);
    • Docs: Update version and schema to take schemaBuilder into account (and document schemaBuilder).
    • Docs: Expand on key behavior examples;
    • Docs: Indicate that key is optional too
    • Docs: Add mention of missing limit on modify
    • Refactoring: Use const where possible;
    • Refactoring: Change variable placement including reordering static variables according to type (built-in alias, IDB, immutables, cache)
    • Refactoring: Avoid try-catch for brevity if will throw in sync body of Promise (but denote which lines may throw)
    • Refactoring: simplify transaction building
    • Refactoring: Add lang attribute for Atom linter-jade package;
    • Code comment: preventDefault not only for Firefox.
    • Code comment: Clarify how old connections may be closed
    • Testing: Schema building tests
    • Testing: Add tests for caching
    • Testing: Add test:local and phantom on package.json scripts
    • Testing: Fix server-handler test (expect specific error)
    • Testing: Fix test-worker to deal with multiple babel-polyfill instances
    • Testing: Remove redundant bad-args test
    • Testing: Unregister service worker
    opened by brettz9 1
Releases(0.9.0)
Owner
Aaron Powell
I'm a Cloud Developer Advocate with Microsoft, focusing on web stuff
Aaron Powell
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

localForage localForage is a fast and simple storage library for JavaScript. localForage improves the offline experience of your web app by using asyn

localForage 21.5k Jan 1, 2023
Browser storage interface for IndexedDB, WebSQL, LocalStorage, and in memory data with Schema and data validator.

Client Web Storage Browser storage interface for IndexedDB, WebSQL, LocalStorage, and in memory data with basic Schema and data validation. Installati

Before Semicolon 19 Sep 30, 2022
local storage wrapper for both react-native and browser. Support size controlling, auto expiring, remote data auto syncing and getting batch data in one query.

react-native-storage This is a local storage wrapper for both react native apps (using AsyncStorage) and web apps (using localStorage). ES6 syntax, pr

Sunny Luo 2.9k Dec 16, 2022
A JavaScript Library To Make Your Work Work Easier/Faster

Functionalty.js (beta) About ✍️ This Is A JavaScript Library To Make Your Work Easier/Faster, You Can See Functionalty.js Website From Here Project Cr

Ali-Eldeba 16 Aug 30, 2022
A JavaScript Library To Make Your Work Work Easier/Faster

Functionality.js (beta) About ✍️ This Is A JavaScript Library To Make Your Work Easier/Faster, You Can See Functionalty.js Website From Here Project C

Ali-Eldeba 9 May 25, 2022
A JavaScript Library To Make Your Work Work Easier/Faster

Functionality.js About ✍️ This Is A JavaScript Library To Make Your Work Easier/Faster, You Can See Functionalty.js Website From Here Project Created

functionality 16 Jun 23, 2022
This is a tic-tac-toe game but differs from most others as it carries the option of playing against an AI (COM) or against a friend.

TIC-TAC-TOE This is a simple tic-tac-toe game with the exception of playing against an algorithm or against a friend. At the very start, you have to s

Paul Ibeabuchi C. 4 Jul 2, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
TypeScript isomorphic library to make work with Telegram Web Apps init data easier.

Telegram Web Apps Init Data TypeScript isomorphic library to make work with Telegram Web Apps init data easier. Feel free to use it in browser and Nod

Telegram Web Apps 2 Oct 7, 2022
NestJS implementation of client and strategy hasn't enough features for work with RabbitMQ so i developed this one (basically, just a wrapper for amqp-connection-manager)

NestJS RabbitMQ Client and strategy NestJS implementation of client and strategy hasn't enough features for work with RabbitMQ so i developed this one

ilink 5 Sep 6, 2022
Lightweight WebSocketServer wrapper lib using ws-wrapper to wrap connected WebSockets

ws-server-wrapper Lightweight WebSocketServer wrapper lib using ws-wrapper and ws to wrap connected WebSockets. The only dependency is ws-wrapper itse

Blake Miner 17 May 9, 2022
AlaSQL.js - JavaScript SQL database for browser and Node.js. Handles both traditional relational tables and nested JSON data (NoSQL). Export, store, and import data from localStorage, IndexedDB, or Excel.

Please use version 1.x as prior versions has a security flaw if you use user generated data to concat your SQL strings instead of providing them as a

Andrey Gershun 6.1k Jan 9, 2023
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

localForage localForage is a fast and simple storage library for JavaScript. localForage improves the offline experience of your web app by using asyn

localForage 21.5k Jan 4, 2023
💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

localForage localForage is a fast and simple storage library for JavaScript. localForage improves the offline experience of your web app by using asyn

localForage 21.5k Jan 1, 2023
sqlite3 in ur indexeddb

This is an absurd project. It implements a backend for sql.js (sqlite3 compiled for the web) that treats IndexedDB like a disk and stores data in bloc

James Long 3.6k Jan 4, 2023
Working around a Safari IndexedDB bug

Safari 14 IndexedDB fix Safari on macOS Big Sur 11.4 and iOS 14.6 has a nasty bug where IndexedDB requests get lost and never resolve. This library (w

Jake Archibald 43 Sep 21, 2022
sqlite3 in ur indexeddb

This is an absurd project. It implements a backend for sql.js (sqlite3 compiled for the web) that treats IndexedDB like a disk and stores data in bloc

James Long 3.6k Dec 30, 2022