Skip to content

Table.hook('updating')

David Fahlander edited this page Apr 22, 2014 · 31 revisions

Syntax

db.[tableName].hook('updating', function (modifications, primKey, obj, transaction) {
    // You may use transaction to do additional database operations.
    // You may not do any modifications on any of the given arguments.
    // You may set this.onsuccess = callback when update operation completes.
    // You may set this.onerror = callback if update operation fails.
    // If you want to make additional modifications, return another modifications object
    // containing the additional or overridden modifications to make. Any returned
    // object will be merged to the given modifications object.
});

Parameters

modifications Object of keyPaths and values that is about to be applied as a patch to the existing object. If a property is being deleted, mods.hasOwnPropert(propName) will be true, but the value will be undefined. Changes made to this object will not affect the update operation unless the object is also returned as return value.
primKey The primary key of the object being updated
obj Object that is about to be updated. This object MUST NOT be modified. Instead modify the _modifications_ object by setting your desired keyPath as key and your desired value as value and then return the modified modifications object.
transaction Transaction instance.
<this context> Possibility to be notified when the update operation succeeds or fails. Done by setting this.onsuccess = function(){} or this.onerror = function(){}

Return Value

If you do not want to change any modification, dont return any value (return undefined). If you want to add additional modifications or change any of the modifications in the given modifications argument, you should return another object containing the additional or overridden modifications to make.

Description

This event is called whenever an existing database object is being updated (through any of the WriteableTable.update() or WriteableCollection.modify() methods.

A subscriber may use the given transaction object to do additional operations on the database. The chain of operations can be considered atomic since the subscriber can work on the same transaction as being used for updating the object. If any exception or database error event occur, the entire transaction will abort.

Error Handling

If subscriber throws an exception, the update operation will fail and the caller of the update operation will get the failure as a Promise rejection that may be catched/handled or not. If the caller of the update operation does not catch the excetion using Promise.catch(), the transaction will be aborted.

If a database operation initiated by the subscriber, results in a failure, the transaction will be aborted no matter if the origin caller of the update operation calls catch() or not. However, the origin caller will recieve your error if catching transaction failures, but then the transaction has already aborted. If you as the implementor of the subscriber want to ignore errors resulting from your operations, you may catch() your database operations to prohibit transaction from being aborted. However, it is normally better to let the transaction abort in case a failure of your database operation would impinge database consistancy.

If setting this.onsuccess or this.onerror, those callback functions are responsible of not throwing any exception. Any code within that callback must either be bullet proof or surrounded by try/catch.

Use Cases of the CRUD events

Dexie CRUD events can be used to implement several addons to Dexie such as:

  • Server Synchronization
  • Automatic primary key generation
  • Views
  • Full-text search or other custom indexes
  • etc.

Internally the hook('reading') event is used by the methods Table.defineClass() and Table.mapToClass() in order to make all objects retrieved from database inherit a given class using prototypal inheritance.

Sample

This example is a simple implementation of full-text search based on multi-valued indexes and Dexie hooks. NOTE: Multi-valued indexes are only supported in Opera, Firefox and Chrome. Does not work with IE so far. To see an example that works with IE, see FullTextSearch2.js

var db = new Dexie("FullTextSample");

db.version(1).stores({emails: "++id,subject,from,*to,*cc,*bcc,message,*messageWords"});

// To explain the structure of an email, let's declare it as a class (optional!)
var Email = db.emails.defineClass({
    id: Number,
    subject: String,
    from: String,
    to: [String],
    cc: [String],
    bcc: [String],
    message: String,
    messageWords: [String]
});

// Add hooks that will index "message" for full-text search:
db.emails.hook("creating", function (primKey, obj, trans) {
    if (typeof obj.message == 'string') obj.messageWords = getAllWords(obj.message);
});
db.emails.hook("updating", function (mods, primKey, obj, trans) {
    if (typeof mods.message == 'string')
        return { messageWords: getAllWords(mods.message) };
    else
        return { messageWords: []};
});
function getAllWords(text) {
    /// <param name="text" type="String"></param>
    var allWordsIncludingDups = text.split(' ');
    var wordSet = allWordsIncludingDups.reduce(function (prev, current) {
        prev[current] = true;
        return prev;
    }, {});
    return Object.keys(set);
}

// Open database to allow application code using it.
db.open();


//
// Application code:
//

db.transaction('rw', db.emails, function (emails) {
    // Add an email:
    emails.add(new Email({
        subject: "Testing full-text search",
        from: "[email protected]",
        to: ["[email protected]"],
        message: "Here is my very long message that I want to write"
    }));

    // Search for emails:
    emails.where("messageWords").startsWithIgnoreCase("v").distinct().toArray(function (a) {
        alert("Found " + a.length + " emails containing a word starting with 'v'");
    });
}).catch(function (e) {
    alert(e.stack || e);
});

See Also

Table.hook('creating')

Table.hook('reading')

Table.hook('deleting')

Clone this wiki locally