--- a/dom/sms/src/ril/SmsDatabaseService.js
+++ b/dom/sms/src/ril/SmsDatabaseService.js
@@ -10,17 +10,17 @@ Cu.import("resource://gre/modules/XPCOMU
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
const RIL_SMSDATABASESERVICE_CONTRACTID = "@mozilla.org/sms/rilsmsdatabaseservice;1";
const RIL_SMSDATABASESERVICE_CID = Components.ID("{a1fa610c-eb6c-4ac2-878f-b005d5e89249}");
const DEBUG = false;
const DB_NAME = "sms";
-const DB_VERSION = 6;
+const DB_VERSION = 7;
const STORE_NAME = "sms";
const MOST_RECENT_STORE_NAME = "most-recent";
const DELIVERY_SENDING = "sending";
const DELIVERY_RECEIVED = "received";
const DELIVERY_STATUS_NOT_APPLICABLE = "not-applicable";
const DELIVERY_STATUS_SUCCESS = "success";
@@ -189,16 +189,20 @@ SmsDatabaseService.prototype = {
case 4:
if (DEBUG) debug("Upgrade to version 5. Populate quick threads view.")
self.upgradeSchema4(event.target.transaction);
break;
case 5:
if (DEBUG) debug("Upgrade to version 6. Use PhonenumberJS.")
self.upgradeSchema5(event.target.transaction);
break;
+ case 6:
+ if (DEBUG) debug("Upgrade to version 7. Use multiple entry indexes.")
+ self.upgradeSchema6(event.target.transaction);
+ break;
default:
event.target.transaction.abort();
callback("Old database version: " + event.oldVersion, null);
break;
}
currentVersion++;
}
}
@@ -265,19 +269,16 @@ SmsDatabaseService.prototype = {
* Create the initial database schema.
*
* TODO need to worry about number normalization somewhere...
* TODO full text search on body???
*/
createSchema: function createSchema(db) {
// This objectStore holds the main SMS data.
let objectStore = db.createObjectStore(STORE_NAME, { keyPath: "id" });
- objectStore.createIndex("delivery", "delivery", { unique: false });
- objectStore.createIndex("sender", "sender", { unique: false });
- objectStore.createIndex("receiver", "receiver", { unique: false });
objectStore.createIndex("timestamp", "timestamp", { unique: false });
if (DEBUG) debug("Created object stores and indexes");
},
/**
* Upgrade to the corresponding database schema version.
*/
upgradeSchema: function upgradeSchema(objectStore) {
@@ -361,16 +362,61 @@ SmsDatabaseService.prototype = {
cursor.continue();
}
},
upgradeSchema5: function upgradeSchema5(transaction) {
// Don't perform any upgrade. See Bug 819560.
},
+ upgradeSchema6: function upgradeSchema6(transaction) {
+ let objectStore = transaction.objectStore(STORE_NAME);
+
+ // Delete "delivery" index.
+ if (objectStore.indexNames.contains("delivery")) {
+ objectStore.deleteIndex("delivery");
+ }
+ // Delete "sender" index.
+ if (objectStore.indexNames.contains("sender")) {
+ objectStore.deleteIndex("sender");
+ }
+ // Delete "receiver" index.
+ if (objectStore.indexNames.contains("receiver")) {
+ objectStore.deleteIndex("receiver");
+ }
+ // Delete "read" index.
+ if (objectStore.indexNames.contains("read")) {
+ objectStore.deleteIndex("read");
+ }
+
+ // Create new "delivery", "number" and "read" indexes.
+ objectStore.createIndex("delivery", "deliveryIndex");
+ objectStore.createIndex("number", "numberIndex", { multiEntry: true });
+ objectStore.createIndex("read", "readIndex");
+
+ // Populate new "deliverIndex", "numberIndex" and "readIndex" attributes.
+ objectStore.openCursor().onsuccess = function(event) {
+ let cursor = event.target.result;
+ if (!cursor) {
+ return;
+ }
+
+ let message = cursor.value;
+ let timestamp = message.timestamp;
+ message.deliveryIndex = [message.delivery, timestamp];
+ message.numberIndex = [
+ [message.sender, timestamp],
+ [message.receiver, timestamp]
+ ];
+ message.readIndex = [message.read, timestamp];
+ cursor.update(message);
+ cursor.continue();
+ }
+ },
+
/**
* Helper function to make the intersection of the partial result arrays
* obtained within createMessageList.
*
* @param keys
* Object containing the partial result arrays.
* @param fiter
* Object containing the filter search criteria used to retrieved the
@@ -521,24 +567,30 @@ SmsDatabaseService.prototype = {
let sender = aSender;
if (sender) {
let parsedNumber = PhoneNumberUtils.parse(sender);
sender = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: sender;
}
- let message = {delivery: DELIVERY_RECEIVED,
- deliveryStatus: DELIVERY_STATUS_SUCCESS,
- sender: sender,
- receiver: receiver,
- body: aBody,
- messageClass: aMessageClass,
- timestamp: aDate,
- read: FILTER_READ_UNREAD};
+ let message = {
+ deliveryIndex: [DELIVERY_RECEIVED, aDate],
+ numberIndex: [[sender, aDate], [receiver, aDate]],
+ readIndex: [FILTER_READ_UNREAD, aDate],
+
+ delivery: DELIVERY_RECEIVED,
+ deliveryStatus: DELIVERY_STATUS_SUCCESS,
+ sender: sender,
+ receiver: receiver,
+ body: aBody,
+ messageClass: aMessageClass,
+ timestamp: aDate,
+ read: FILTER_READ_UNREAD
+ };
return this.saveMessage(message);
},
saveSendingMessage: function saveSendingMessage(aReceiver, aBody, aDate) {
let sender = this.mRIL.rilContext.icc ? this.mRIL.rilContext.icc.msisdn : null;
// Workaround an xpconnect issue with undefined string objects.
// See bug 808220
@@ -556,24 +608,30 @@ SmsDatabaseService.prototype = {
if (sender) {
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
sender = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: sender;
}
- let message = {delivery: DELIVERY_SENDING,
- deliveryStatus: DELIVERY_STATUS_PENDING,
- sender: sender,
- receiver: receiver,
- body: aBody,
- messageClass: MESSAGE_CLASS_NORMAL,
- timestamp: aDate,
- read: FILTER_READ_READ};
+ let message = {
+ deliveryIndex: [DELIVERY_SENDING, aDate],
+ numberIndex: [[sender, aDate], [receiver, aDate]],
+ readIndex: [FILTER_READ_READ, aDate],
+
+ delivery: DELIVERY_SENDING,
+ deliveryStatus: DELIVERY_STATUS_PENDING,
+ sender: sender,
+ receiver: receiver,
+ body: aBody,
+ messageClass: MESSAGE_CLASS_NORMAL,
+ timestamp: aDate,
+ read: FILTER_READ_READ
+ };
return this.saveMessage(message);
},
setMessageDelivery: function setMessageDelivery(messageId, delivery, deliveryStatus) {
if (DEBUG) {
debug("Setting message " + messageId + " delivery to " + delivery
+ ", and deliveryStatus to " + deliveryStatus);
}
@@ -602,16 +660,17 @@ SmsDatabaseService.prototype = {
&& (message.deliveryStatus == deliveryStatus)) {
if (DEBUG) {
debug("The values of attribute delivery and deliveryStatus are the"
+ " the same with given parameters.");
}
return;
}
message.delivery = delivery;
+ message.deliveryIndex = [delivery, message.timestamp];
message.deliveryStatus = deliveryStatus;
if (DEBUG) {
debug("Message.delivery set to: " + delivery
+ ", and Message.deliveryStatus set to: " + deliveryStatus);
}
store.put(message);
};
});
@@ -715,54 +774,39 @@ SmsDatabaseService.prototype = {
// This must exist.
let mostRecentEntry = event.target.result;
if (!message.read) {
mostRecentEntry.unreadCount--;
}
if (mostRecentEntry.id == messageId) {
- // This sucks, we have to find a new most-recent message.
- message = null;
-
- // Check most recent sender.
- smsStore.index("sender").openCursor(number, "prev").onsuccess = function(event) {
- let cursor = event.target.result;
- if (cursor) {
- message = cursor.value;
- }
- };
-
- // Check most recent receiver.
- smsStore.index("receiver").openCursor(number, "prev").onsuccess = function(event) {
+ // Check most recent sender/receiver.
+ let numberRange = IDBKeyRange.bound([number, 0], [number, ""]);
+ let numberRequest = smsStore.index("number")
+ .openCursor(numberRange, PREV);
+ numberRequest.onsuccess = function(event) {
let cursor = event.target.result;
- if (cursor) {
- if (!message || cursor.value.timeStamp > message.timestamp) {
- message = cursor.value;
- }
- }
-
- // If we found a new message then we need to update the data
- // in the most-recent store. Otherwise we can delete it.
- if (message) {
- mostRecentEntry.id = message.id;
- mostRecentEntry.timestamp = message.timestamp;
- mostRecentEntry.body = message.body;
- if (DEBUG) {
- debug("Updating mru entry: " +
- JSON.stringify(mostRecentEntry));
- }
- mruStore.put(mostRecentEntry);
- }
- else {
+ if (!cursor) {
if (DEBUG) {
debug("Deleting mru entry for number '" + number + "'");
}
mruStore.delete(number);
+ return;
}
+
+ let nextMsg = cursor.value;
+ mostRecentEntry.id = nextMsg.id;
+ mostRecentEntry.timestamp = nextMsg.timestamp;
+ mostRecentEntry.body = nextMsg.body;
+ if (DEBUG) {
+ debug("Updating mru entry: " +
+ JSON.stringify(mostRecentEntry));
+ }
+ mruStore.put(mostRecentEntry);
};
} else if (!message.read) {
// Shortcut, just update the unread count.
if (DEBUG) {
debug("Updating unread count for number '" + number + "': " +
(mostRecentEntry.unreadCount + 1) + " -> " +
mostRecentEntry.unreadCount);
}
@@ -847,48 +891,47 @@ SmsDatabaseService.prototype = {
timeRequest.onsuccess = function onsuccess(event) {
successCb(event.target.result, FILTER_TIMESTAMP);
};
timeRequest.onerror = errorCb;
// Retrieve the keys from the 'delivery' index that matches the
// value of filter.delivery.
if (filter.delivery) {
- let deliveryKeyRange = IDBKeyRange.only(filter.delivery);
+ let deliveryKeyRange = IDBKeyRange.bound([filter.delivery, 0],
+ [filter.delivery, ""]);
let deliveryRequest = store.index("delivery")
.openKeyCursor(deliveryKeyRange);
deliveryRequest.onsuccess = function onsuccess(event) {
successCb(event.target.result, FILTER_DELIVERY);
};
deliveryRequest.onerror = errorCb;
}
// Retrieve the keys from the 'sender' and 'receiver' indexes that
// match the values of filter.numbers
if (filter.numbers) {
for (let i = 0; i < filter.numbers.length; i++) {
- let numberKeyRange = IDBKeyRange.only(filter.numbers[i]);
- let senderRequest = store.index("sender")
+ let numberKeyRange = IDBKeyRange.bound([filter.numbers[i], 0],
+ [filter.numbers[i], ""]);
+ let numberRequest = store.index("number")
.openKeyCursor(numberKeyRange);
- let receiverRequest = store.index("receiver")
- .openKeyCursor(numberKeyRange);
- senderRequest.onsuccess = receiverRequest.onsuccess =
- function onsuccess(event){
- successCb(event.target.result, FILTER_NUMBERS);
- };
- senderRequest.onerror = receiverRequest.onerror = errorCb;
+ numberRequest.onsuccess = function onsuccess(event) {
+ successCb(event.target.result, FILTER_NUMBERS);
+ };
+ numberRequest.onerror = errorCb;
}
}
// Retrieve the keys from the 'read' index that matches the value of
// filter.read
if (filter.read != undefined) {
let read = filter.read ? FILTER_READ_READ : FILTER_READ_UNREAD;
if (DEBUG) debug("filter.read " + read);
- let readKeyRange = IDBKeyRange.only(read);
+ let readKeyRange = IDBKeyRange.bound([read, 0], [read, ""]);
let readRequest = store.index("read")
.openKeyCursor(readKeyRange);
readRequest.onsuccess = function onsuccess(event) {
successCb(event.target.result, FILTER_READ);
};
readRequest.onerror = errorCb;
}
@@ -1003,16 +1046,17 @@ SmsDatabaseService.prototype = {
// If the value to be set is the same as the current message `read`
// value, we just notify successfully.
if (message.read == value) {
if (DEBUG) debug("The value of message.read is already " + value);
aRequest.notifyMessageMarkedRead(message.read);
return;
}
message.read = value ? FILTER_READ_READ : FILTER_READ_UNREAD;
+ message.readIndex = [message.read, message.timestamp];
if (DEBUG) debug("Message.read set to: " + value);
event.target.source.put(message).onsuccess = function onsuccess(event) {
if (DEBUG) {
debug("Update successfully completed. Message: " +
JSON.stringify(event.target.result));
}
// Now update the unread count.