diff options
Diffstat (limited to 'comm/calendar/providers/storage/CalStorageStatements.jsm')
-rw-r--r-- | comm/calendar/providers/storage/CalStorageStatements.jsm | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/comm/calendar/providers/storage/CalStorageStatements.jsm b/comm/calendar/providers/storage/CalStorageStatements.jsm new file mode 100644 index 0000000000..4906e036e3 --- /dev/null +++ b/comm/calendar/providers/storage/CalStorageStatements.jsm @@ -0,0 +1,751 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var EXPORTED_SYMBOLS = ["CalStorageStatements"]; + +const cICL = Ci.calIChangeLog; + +/** + * CalStorageStatements contains the mozIStorageBaseStatements used by the + * various storage calendar models. Remember to call the finalize() method when + * shutting down the db. + */ +class CalStorageStatements { + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectEvent = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectTodo = null; + + /** + * @type {mozIStorageAsyncStatement} mSelectNonRecurringEventsByRange + */ + mSelectNonRecurringEventsByRange = null; + + /** + * @type {mozIStorageAsyncStatement} mSelectNonRecurringTodosByRange + */ + mSelectNonRecurringTodosByRange = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAttendeesForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAttendeesForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllAttendees = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectPropertiesForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectPropertiesForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllProperties = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectParametersForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectParametersForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllParameters = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectRecurrenceForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllRecurrences = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectEventsWithRecurrence = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectTodosWithRecurrence = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectEventExceptions = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllEventExceptions = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectTodoExceptions = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllTodoExceptions = null; + + /** + * @type {mozIStorageStatement} + */ + mSelectMetaData = null; + + /** + * @type {mozIStorageStatement} + */ + mSelectAllMetaData = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectRelationsForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllRelations = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectRelationsForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAlarmsForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAlarmsForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllAlarms = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAttachmentsForItem = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAttachmentsForItemWithRecurrenceId = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mSelectAllAttachments = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertEvent = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertTodo = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertProperty = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertParameter = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertAttendee = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertRecurrence = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertAttachment = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertRelation = null; + + /** + * @type {mozIStorageStatement} + */ + mInsertMetaData = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mInsertAlarm = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mEditEventOfflineFlag = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mEditTodoOfflineFlag = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteEvent = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteTodo = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteAttendees = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteProperties = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteParameters = null; + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteRecurrence = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteAttachments = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteRelations = null; + + /** + * @type {mozIStorageStatement} + */ + mDeleteMetaData = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteAlarms = null; + + /** + * @type {mozIStorageAsyncStatement[]} + */ + mDeleteEventExtras = []; + + /** + * @type {mozIStorageAsyncStatement[]} + */ + mDeleteTodoExtras = []; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteAllEvents = null; + + /** + * @type {mozIStorageAsyncStatement} + */ + mDeleteAllTodos = null; + + /** + * @type {mozIStorageStatement} + */ + mDeleteAllMetaData = null; + + /** + * @param {CalStorageDatabase} db + * + * @throws - If unable to initialize SQL statements. + */ + constructor(db) { + this.mSelectEvent = db.createAsyncStatement( + `SELECT * FROM cal_events + WHERE id = :id + AND cal_id = :cal_id + AND recurrence_id IS NULL + LIMIT 1` + ); + + this.mSelectTodo = db.createAsyncStatement( + `SELECT * FROM cal_todos + WHERE id = :id + AND cal_id = :cal_id + AND recurrence_id IS NULL + LIMIT 1` + ); + + // The more readable version of the next where-clause is: + // WHERE ((event_end > :range_start OR + // (event_end = :range_start AND + // event_start = :range_start)) + // AND event_start < :range_end) + // + // but that doesn't work with floating start or end times. The logic + // is the same though. + // For readability, a few helpers: + let floatingEventStart = "event_start_tz = 'floating' AND event_start"; + let nonFloatingEventStart = "event_start_tz != 'floating' AND event_start"; + let floatingEventEnd = "event_end_tz = 'floating' AND event_end"; + let nonFloatingEventEnd = "event_end_tz != 'floating' AND event_end"; + // The query needs to take both floating and non floating into account. + this.mSelectNonRecurringEventsByRange = db.createAsyncStatement( + `SELECT * FROM cal_events + WHERE + ((${floatingEventEnd} > :range_start + :start_offset) OR + (${nonFloatingEventEnd} > :range_start) OR + (((${floatingEventEnd} = :range_start + :start_offset) OR + (${nonFloatingEventEnd} = :range_start)) AND + ((${floatingEventStart} = :range_start + :start_offset) OR + (${nonFloatingEventStart} = :range_start)))) + AND + ((${floatingEventStart} < :range_end + :end_offset) OR + (${nonFloatingEventStart} < :range_end)) + AND cal_id = :cal_id AND flags & 16 == 0 AND recurrence_id IS NULL + AND ((:offline_journal IS NULL + AND (offline_journal IS NULL + OR offline_journal != ${cICL.OFFLINE_FLAG_DELETED_RECORD})) + OR (offline_journal == :offline_journal))` + ); + + // + // WHERE (due > rangeStart AND (entry IS NULL OR entry < rangeEnd)) OR + // (due = rangeStart AND (entry IS NULL OR entry = rangeStart)) OR + // (due IS NULL AND (entry >= rangeStart AND entry < rangeEnd)) OR + // (entry IS NULL AND (completed > rangeStart OR completed IS NULL)) + // + let floatingTodoEntry = "todo_entry_tz = 'floating' AND todo_entry"; + let nonFloatingTodoEntry = "todo_entry_tz != 'floating' AND todo_entry"; + let floatingTodoDue = "todo_due_tz = 'floating' AND todo_due"; + let nonFloatingTodoDue = "todo_due_tz != 'floating' AND todo_due"; + let floatingCompleted = "todo_completed_tz = 'floating' AND todo_completed"; + let nonFloatingCompleted = "todo_completed_tz != 'floating' AND todo_completed"; + + this.mSelectNonRecurringTodosByRange = db.createAsyncStatement( + `SELECT * FROM cal_todos + WHERE + ((((${floatingTodoDue} > :range_start + :start_offset) OR + (${nonFloatingTodoDue} > :range_start)) AND + ((todo_entry IS NULL) OR + ((${floatingTodoEntry} < :range_end + :end_offset) OR + (${nonFloatingTodoEntry} < :range_end)))) OR + (((${floatingTodoDue} = :range_start + :start_offset) OR + (${nonFloatingTodoDue} = :range_start)) AND + ((todo_entry IS NULL) OR + ((${floatingTodoEntry} = :range_start + :start_offset) OR + (${nonFloatingTodoEntry} = :range_start)))) OR + ((todo_due IS NULL) AND + (((${floatingTodoEntry} >= :range_start + :start_offset) OR + (${nonFloatingTodoEntry} >= :range_start)) AND + ((${floatingTodoEntry} < :range_end + :end_offset) OR + (${nonFloatingTodoEntry} < :range_end)))) OR + ((todo_entry IS NULL) AND + (((${floatingCompleted} > :range_start + :start_offset) OR + (${nonFloatingCompleted} > :range_start)) OR + (todo_completed IS NULL)))) + AND cal_id = :cal_id AND flags & 16 == 0 AND recurrence_id IS NULL + AND ((:offline_journal IS NULL + AND (offline_journal IS NULL + OR offline_journal != ${cICL.OFFLINE_FLAG_DELETED_RECORD})) + OR (offline_journal == :offline_journal))` + ); + + this.mSelectEventsWithRecurrence = db.createAsyncStatement( + `SELECT * FROM cal_events + WHERE flags & 16 == 16 + AND cal_id = :cal_id + AND recurrence_id is NULL` + ); + + this.mSelectTodosWithRecurrence = db.createAsyncStatement( + `SELECT * FROM cal_todos + WHERE flags & 16 == 16 + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectEventExceptions = db.createAsyncStatement( + `SELECT * FROM cal_events + WHERE id = :id + AND cal_id = :cal_id + AND recurrence_id IS NOT NULL` + ); + this.mSelectAllEventExceptions = db.createAsyncStatement( + `SELECT * FROM cal_events + WHERE cal_id = :cal_id + AND recurrence_id IS NOT NULL` + ); + + this.mSelectTodoExceptions = db.createAsyncStatement( + `SELECT * FROM cal_todos + WHERE id = :id + AND cal_id = :cal_id + AND recurrence_id IS NOT NULL` + ); + this.mSelectAllTodoExceptions = db.createAsyncStatement( + `SELECT * FROM cal_todos + WHERE cal_id = :cal_id + AND recurrence_id IS NOT NULL` + ); + + this.mSelectAttendeesForItem = db.createAsyncStatement( + `SELECT * FROM cal_attendees + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectAttendeesForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT * FROM cal_attendees + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllAttendees = db.createAsyncStatement( + `SELECT item_id, icalString FROM cal_attendees + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectPropertiesForItem = db.createAsyncStatement( + `SELECT * FROM cal_properties + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + this.mSelectPropertiesForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT * FROM cal_properties + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllProperties = db.createAsyncStatement( + `SELECT item_id, key, value FROM cal_properties + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectParametersForItem = db.createAsyncStatement( + `SELECT * FROM cal_parameters + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + this.mSelectParametersForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT * FROM cal_parameters + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllParameters = db.createAsyncStatement( + `SELECT item_id, key1, key2, value FROM cal_parameters + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectRecurrenceForItem = db.createAsyncStatement( + `SELECT * FROM cal_recurrence + WHERE item_id = :item_id + AND cal_id = :cal_id` + ); + this.mSelectAllRecurrences = db.createAsyncStatement( + `SELECT item_id, icalString FROM cal_recurrence + WHERE cal_id = :cal_id` + ); + + this.mSelectAttachmentsForItem = db.createAsyncStatement( + `SELECT * FROM cal_attachments + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + this.mSelectAttachmentsForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT * FROM cal_attachments + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllAttachments = db.createAsyncStatement( + `SELECT item_id, icalString FROM cal_attachments + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectRelationsForItem = db.createAsyncStatement( + `SELECT * FROM cal_relations + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + this.mSelectRelationsForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT * FROM cal_relations + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllRelations = db.createAsyncStatement( + `SELECT item_id, icalString FROM cal_relations + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectMetaData = db.createStatement( + `SELECT * FROM cal_metadata + WHERE item_id = :item_id + AND cal_id = :cal_id` + ); + + this.mSelectAllMetaData = db.createStatement( + `SELECT * FROM cal_metadata + WHERE cal_id = :cal_id` + ); + + this.mSelectAlarmsForItem = db.createAsyncStatement( + `SELECT icalString FROM cal_alarms + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + this.mSelectAlarmsForItemWithRecurrenceId = db.createAsyncStatement( + `SELECT icalString FROM cal_alarms + WHERE item_id = :item_id + AND cal_id = :cal_id + AND recurrence_id = :recurrence_id + AND recurrence_id_tz = :recurrence_id_tz` + ); + this.mSelectAllAlarms = db.createAsyncStatement( + `SELECT item_id, icalString FROM cal_alarms + WHERE cal_id = :cal_id + AND recurrence_id IS NULL` + ); + + // insert statements + this.mInsertEvent = db.createAsyncStatement( + `INSERT INTO cal_events + (cal_id, id, time_created, last_modified, + title, priority, privacy, ical_status, flags, + event_start, event_start_tz, event_end, event_end_tz, event_stamp, + recurrence_id, recurrence_id_tz, alarm_last_ack) + VALUES (:cal_id, :id, :time_created, :last_modified, + :title, :priority, :privacy, :ical_status, :flags, + :event_start, :event_start_tz, :event_end, :event_end_tz, :event_stamp, + :recurrence_id, :recurrence_id_tz, :alarm_last_ack)` + ); + + this.mInsertTodo = db.createAsyncStatement( + `INSERT INTO cal_todos + (cal_id, id, time_created, last_modified, + title, priority, privacy, ical_status, flags, + todo_entry, todo_entry_tz, todo_due, todo_due_tz, todo_stamp, + todo_completed, todo_completed_tz, todo_complete, + recurrence_id, recurrence_id_tz, alarm_last_ack) + VALUES (:cal_id, :id, :time_created, :last_modified, + :title, :priority, :privacy, :ical_status, :flags, + :todo_entry, :todo_entry_tz, :todo_due, :todo_due_tz, :todo_stamp, + :todo_completed, :todo_completed_tz, :todo_complete, + :recurrence_id, :recurrence_id_tz, :alarm_last_ack)` + ); + this.mInsertProperty = db.createAsyncStatement( + `INSERT INTO cal_properties (cal_id, item_id, recurrence_id, recurrence_id_tz, key, value) + VALUES (:cal_id, :item_id, :recurrence_id, :recurrence_id_tz, :key, :value)` + ); + this.mInsertParameter = db.createAsyncStatement( + `INSERT INTO cal_parameters (cal_id, item_id, recurrence_id, recurrence_id_tz, key1, key2, value) + VALUES (:cal_id, :item_id, :recurrence_id, :recurrence_id_tz, :key1, :key2, :value)` + ); + this.mInsertAttendee = db.createAsyncStatement( + `INSERT INTO cal_attendees + (cal_id, item_id, recurrence_id, recurrence_id_tz, icalString) + VALUES (:cal_id, :item_id, :recurrence_id, :recurrence_id_tz, :icalString)` + ); + this.mInsertRecurrence = db.createAsyncStatement( + `INSERT INTO cal_recurrence + (cal_id, item_id, icalString) + VALUES (:cal_id, :item_id, :icalString)` + ); + + this.mInsertAttachment = db.createAsyncStatement( + `INSERT INTO cal_attachments + (cal_id, item_id, icalString, recurrence_id, recurrence_id_tz) + VALUES (:cal_id, :item_id, :icalString, :recurrence_id, :recurrence_id_tz)` + ); + + this.mInsertRelation = db.createAsyncStatement( + `INSERT INTO cal_relations + (cal_id, item_id, icalString, recurrence_id, recurrence_id_tz) + VALUES (:cal_id, :item_id, :icalString, :recurrence_id, :recurrence_id_tz)` + ); + + this.mInsertMetaData = db.createStatement( + `INSERT INTO cal_metadata + (cal_id, item_id, value) + VALUES (:cal_id, :item_id, :value)` + ); + + this.mInsertAlarm = db.createAsyncStatement( + `INSERT INTO cal_alarms + (cal_id, item_id, icalString, recurrence_id, recurrence_id_tz) + VALUES (:cal_id, :item_id, :icalString, :recurrence_id, :recurrence_id_tz)` + ); + // Offline Operations + this.mEditEventOfflineFlag = db.createStatement( + `UPDATE cal_events SET offline_journal = :offline_journal + WHERE id = :id + AND cal_id = :cal_id` + ); + + this.mEditTodoOfflineFlag = db.createStatement( + `UPDATE cal_todos SET offline_journal = :offline_journal + WHERE id = :id + AND cal_id = :cal_id` + ); + + // delete statements + this.mDeleteEvent = db.createAsyncStatement( + "DELETE FROM cal_events WHERE id = :id AND cal_id = :cal_id" + ); + this.mDeleteTodo = db.createAsyncStatement( + "DELETE FROM cal_todos WHERE id = :id AND cal_id = :cal_id" + ); + this.mDeleteAttendees = db.createAsyncStatement( + "DELETE FROM cal_attendees WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteProperties = db.createAsyncStatement( + "DELETE FROM cal_properties WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteParameters = db.createAsyncStatement( + "DELETE FROM cal_parameters WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteRecurrence = db.createAsyncStatement( + "DELETE FROM cal_recurrence WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteAttachments = db.createAsyncStatement( + "DELETE FROM cal_attachments WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteRelations = db.createAsyncStatement( + "DELETE FROM cal_relations WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteMetaData = db.createStatement( + "DELETE FROM cal_metadata WHERE item_id = :item_id AND cal_id = :cal_id" + ); + this.mDeleteAlarms = db.createAsyncStatement( + "DELETE FROM cal_alarms WHERE item_id = :item_id AND cal_id = :cal_id" + ); + + // These are only used when deleting an entire calendar + let extrasTables = [ + "cal_attendees", + "cal_properties", + "cal_parameters", + "cal_recurrence", + "cal_attachments", + "cal_metadata", + "cal_relations", + "cal_alarms", + ]; + + this.mDeleteEventExtras = []; + this.mDeleteTodoExtras = []; + + for (let table in extrasTables) { + this.mDeleteEventExtras[table] = db.createAsyncStatement( + `DELETE FROM ${extrasTables[table]} + WHERE item_id IN + (SELECT id FROM cal_events WHERE cal_id = :cal_id) + AND cal_id = :cal_id` + ); + this.mDeleteTodoExtras[table] = db.createAsyncStatement( + `DELETE FROM ${extrasTables[table]} + WHERE item_id IN + (SELECT id FROM cal_todos WHERE cal_id = :cal_id) + AND cal_id = :cal_id` + ); + } + + // Note that you must delete the "extras" _first_ using the above two + // statements, before you delete the events themselves. + this.mDeleteAllEvents = db.createAsyncStatement( + "DELETE from cal_events WHERE cal_id = :cal_id" + ); + this.mDeleteAllTodos = db.createAsyncStatement("DELETE from cal_todos WHERE cal_id = :cal_id"); + + this.mDeleteAllMetaData = db.createStatement("DELETE FROM cal_metadata WHERE cal_id = :cal_id"); + } + + /** + * Ensures all Db statements are properly cleaned up before shutdown by + * calling their finalize() method. + */ + finalize() { + for (let key of Object.keys(this)) { + if (this[key] instanceof Ci.mozIStorageBaseStatement) { + this[key].finalize(); + } + } + for (let stmt of this.mDeleteEventExtras) { + stmt.finalize(); + } + for (let stmt of this.mDeleteTodoExtras) { + stmt.finalize(); + } + } +} |