| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | describe("Zotero.DB", function() { | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 	var tmpTable = "tmpDBTest"; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-05-05 02:35:04 -04:00
										 |  |  | 	before(function* () { | 
					
						
							|  |  |  | 		this.timeout(5000); | 
					
						
							|  |  |  | 		Zotero.debug("Waiting for DB activity to settle"); | 
					
						
							|  |  |  | 		yield Zotero.DB.waitForTransaction(); | 
					
						
							|  |  |  | 		yield Zotero.Promise.delay(1000); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 	beforeEach(function* () { | 
					
						
							| 
									
										
										
										
											2015-05-05 02:35:04 -04:00
										 |  |  | 		yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 		yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)"); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 	after(function* () { | 
					
						
							| 
									
										
										
										
											2015-05-05 02:35:04 -04:00
										 |  |  | 		yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-05-28 15:38:39 -04:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	describe("#queryAsync()", function () { | 
					
						
							|  |  |  | 		var tmpTable; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		before(function* () { | 
					
						
							|  |  |  | 			tmpTable = "tmp_queryAsync"; | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("CREATE TEMPORARY TABLE " + tmpTable + " (a, b)"); | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1, 2)"); | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (3, 4)"); | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (5, NULL)"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		after(function* () { | 
					
						
							|  |  |  | 			if (tmpTable) { | 
					
						
							|  |  |  | 				yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if no parameters are passed for a query with placeholders", function* () { | 
					
						
							|  |  |  | 			var e = yield getPromiseError(Zotero.DB.queryAsync("SELECT itemID FROM items WHERE itemID=?")); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.include(e.message, "for query containing placeholders"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if too few parameters are passed", function* () { | 
					
						
							|  |  |  | 			var e = yield getPromiseError(Zotero.DB.queryAsync("SELECT itemID FROM items WHERE itemID=? OR itemID=?", [1])); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.include(e.message, "Incorrect number of parameters provided for query"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if too many parameters are passed", function* () { | 
					
						
							|  |  |  | 			var e = yield getPromiseError(Zotero.DB.queryAsync("SELECT itemID FROM items WHERE itemID=?", [1, 2])); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.include(e.message, "Incorrect number of parameters provided for query"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if too many parameters are passed for numbered placeholders", function* () { | 
					
						
							|  |  |  | 			var e = yield getPromiseError(Zotero.DB.queryAsync("SELECT itemID FROM items WHERE itemID=?1 OR itemID=?1", [1, 2])); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.include(e.message, "Incorrect number of parameters provided for query"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept a single placeholder given as a value", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=?", 2); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept a single placeholder given as an array", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=?", [2]); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept multiple placeholders", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=? OR b=?", [2, 4]); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 2); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[1].a, 3); | 
					
						
							| 
									
										
										
										
											2022-02-17 01:41:52 -05:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept combination of numbered and unnumbered placeholders", async function () { | 
					
						
							|  |  |  | 			var rows = await Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE (a=?1 OR b=?1) OR b=?", [2, 4]); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 2); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[1].a, 3); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2015-05-28 15:38:39 -04:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept a single placeholder within parentheses", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b IN (?)", 2); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should accept multiple placeholders within parentheses", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b IN (?, ?)", [2, 4]); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 2); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[1].a, 3); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should replace =? with IS NULL if NULL is passed as a value", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=?", null); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 5); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should replace =? with IS NULL if NULL is passed in an array", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=?", [null]); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 5); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should replace ? with NULL for placeholders within parentheses in INSERT statements", function* () { | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("CREATE TEMPORARY TABLE tmp_srqwnfpwpinss (a, b)"); | 
					
						
							|  |  |  | 			// Replace ", ?"
 | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO tmp_srqwnfpwpinss (a, b) VALUES (?, ?)", [1, null]); | 
					
						
							|  |  |  | 			assert.equal( | 
					
						
							|  |  |  | 				(yield Zotero.DB.valueQueryAsync("SELECT a FROM tmp_srqwnfpwpinss WHERE b IS NULL")), | 
					
						
							|  |  |  | 				1 | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			// Replace "(?"
 | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("DELETE FROM tmp_srqwnfpwpinss"); | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO tmp_srqwnfpwpinss (a, b) VALUES (?, ?)", [null, 2]); | 
					
						
							|  |  |  | 			assert.equal( | 
					
						
							|  |  |  | 				(yield Zotero.DB.valueQueryAsync("SELECT b FROM tmp_srqwnfpwpinss WHERE a IS NULL")), | 
					
						
							|  |  |  | 				2 | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync("DROP TABLE tmp_srqwnfpwpinss"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if NULL is passed for placeholder within parentheses in a SELECT statement", function* () { | 
					
						
							|  |  |  | 			var e = yield getPromiseError(Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b IN (?)", null)); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.include(e.message, "NULL cannot be used for parenthesized placeholders in SELECT queries"); | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should handle numbered parameters", function* () { | 
					
						
							|  |  |  | 			var rows = yield Zotero.DB.queryAsync("SELECT a FROM " + tmpTable + " WHERE b=?1 " | 
					
						
							|  |  |  | 				+ "UNION SELECT b FROM " + tmpTable + " WHERE b=?1", 2); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 2); | 
					
						
							|  |  |  | 			assert.equal(rows[0].a, 1); | 
					
						
							|  |  |  | 			assert.equal(rows[1].a, 2); | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2016-03-28 17:47:25 -04:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		it("should throw an error if onRow throws an error", function* () { | 
					
						
							|  |  |  | 			var i = 0; | 
					
						
							|  |  |  | 			var e = Zotero.DB.queryAsync( | 
					
						
							|  |  |  | 				"SELECT * FROM " + tmpTable, | 
					
						
							|  |  |  | 				false, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					onRow: function (row) { | 
					
						
							|  |  |  | 						if (i > 0) { | 
					
						
							|  |  |  | 							throw new Error("Failed"); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						i++; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			e = yield getPromiseError(e) | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.equal(e.message, "Failed"); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2019-08-27 05:58:49 -04:00
										 |  |  | 		it("should stop gracefully if onRow calls cancel()", function* () { | 
					
						
							| 
									
										
										
										
											2016-03-28 17:47:25 -04:00
										 |  |  | 			var i = 0; | 
					
						
							|  |  |  | 			var rows = []; | 
					
						
							|  |  |  | 			yield Zotero.DB.queryAsync( | 
					
						
							|  |  |  | 				"SELECT * FROM " + tmpTable, | 
					
						
							|  |  |  | 				false, | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2019-08-27 05:58:49 -04:00
										 |  |  | 					onRow: function (row, cancel) { | 
					
						
							| 
									
										
										
										
											2016-03-28 17:47:25 -04:00
										 |  |  | 						if (i > 0) { | 
					
						
							| 
									
										
										
										
											2019-08-27 05:58:49 -04:00
										 |  |  | 							cancel(); | 
					
						
							|  |  |  | 							return; | 
					
						
							| 
									
										
										
										
											2016-03-28 17:47:25 -04:00
										 |  |  | 						} | 
					
						
							|  |  |  | 						rows.push(row.getResultByIndex(0)); | 
					
						
							|  |  |  | 						i++; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			assert.lengthOf(rows, 1); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2015-05-28 15:38:39 -04:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 	describe("#executeTransaction()", function () { | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 		it("should serialize concurrent transactions", Zotero.Promise.coroutine(function* () { | 
					
						
							| 
									
										
										
										
											2015-05-01 16:54:35 -04:00
										 |  |  | 			var resolve1, resolve2, reject1, reject2; | 
					
						
							|  |  |  | 			var promise1 = new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 				resolve1 = resolve; | 
					
						
							|  |  |  | 				reject1 = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			var promise2 = new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 				resolve2 = resolve; | 
					
						
							|  |  |  | 				reject2 = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			Zotero.DB.executeTransaction(function* () { | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				yield Zotero.Promise.delay(250); | 
					
						
							|  |  |  | 				var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable); | 
					
						
							|  |  |  | 				assert.equal(num, 0); | 
					
						
							| 
									
										
										
										
											2015-05-01 16:54:35 -04:00
										 |  |  | 				yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)"); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				assert.ok(Zotero.DB.inTransaction()); | 
					
						
							| 
									
										
										
										
											2015-05-01 16:54:35 -04:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			.then(resolve1) | 
					
						
							|  |  |  | 			.catch(reject1); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 				var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable); | 
					
						
							|  |  |  | 				assert.equal(num, 1); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				yield Zotero.Promise.delay(500); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 				yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)"); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				assert.ok(Zotero.DB.inTransaction()); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			.then(resolve2) | 
					
						
							|  |  |  | 			.catch(reject2); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			yield Zotero.Promise.all([promise1, promise2]); | 
					
						
							|  |  |  | 		})); | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 		it("should serialize queued transactions", function* () { | 
					
						
							|  |  |  | 			var resolve1, resolve2, reject1, reject2, resolve3, reject3; | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			var promise1 = new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 				resolve1 = resolve; | 
					
						
							|  |  |  | 				reject1 = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			var promise2 = new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 				resolve2 = resolve; | 
					
						
							|  |  |  | 				reject2 = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 			var promise3 = new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 				resolve3 = resolve; | 
					
						
							|  |  |  | 				reject3 = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 			// Start a transaction and have it delay
 | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 				yield Zotero.Promise.delay(100); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable); | 
					
						
							|  |  |  | 				assert.equal(num, 0); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 				yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)"); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				assert.ok(Zotero.DB.inTransaction()); | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			.then(resolve1) | 
					
						
							|  |  |  | 			.catch(reject1); | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 			// Start two more transactions, which should wait on the first
 | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 				var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable); | 
					
						
							|  |  |  | 				assert.equal(num, 1); | 
					
						
							|  |  |  | 				yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)"); | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				assert.ok(Zotero.DB.inTransaction()); | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 			.then(resolve2) | 
					
						
							|  |  |  | 			.catch(reject2); | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 			Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 				var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable); | 
					
						
							|  |  |  | 				assert.equal(num, 2); | 
					
						
							|  |  |  | 				yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (3)"); | 
					
						
							|  |  |  | 				// But make sure the second queued transaction doesn't start at the same time,
 | 
					
						
							|  |  |  | 				// such that the first queued transaction gets closed while the second is still
 | 
					
						
							|  |  |  | 				// running
 | 
					
						
							|  |  |  | 				assert.ok(Zotero.DB.inTransaction()); | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.then(resolve3) | 
					
						
							|  |  |  | 			.catch(reject3); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			yield Zotero.Promise.all([promise1, promise2, promise3]); | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2015-05-03 03:17:53 -04:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 		it("should roll back on error", function* () { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 			yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)"); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 			try { | 
					
						
							|  |  |  | 				yield Zotero.DB.executeTransaction(function* () { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 					yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)"); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 					throw 'Aborting transaction -- ignore'; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			catch (e) { | 
					
						
							|  |  |  | 				if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 			var count = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable + ""); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 			assert.equal(count, 1); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			var conn = yield Zotero.DB._getConnectionAsync(); | 
					
						
							|  |  |  | 			assert.isFalse(conn.transactionInProgress); | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 			yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should run onRollback callbacks", function* () { | 
					
						
							|  |  |  | 			var callbackRan = false; | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				yield Zotero.DB.executeTransaction( | 
					
						
							|  |  |  | 					function* () { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 						yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)"); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 						throw 'Aborting transaction -- ignore'; | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						onRollback: function () { | 
					
						
							|  |  |  | 							callbackRan = true; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			catch (e) { | 
					
						
							|  |  |  | 				if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			assert.ok(callbackRan); | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:45:45 -04:00
										 |  |  | 			yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 		it("should time out on nested transactions", function* () { | 
					
						
							|  |  |  | 			var e; | 
					
						
							|  |  |  | 			yield Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 				e = yield getPromiseError( | 
					
						
							|  |  |  | 					Zotero.DB.executeTransaction(function* () {}).timeout(250) | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			assert.ok(e); | 
					
						
							|  |  |  | 			assert.equal(e.name, "TimeoutError"); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should run onRollback callbacks for timed-out nested transactions", function* () { | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 			var callback1Ran = false; | 
					
						
							|  |  |  | 			var callback2Ran = false; | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				yield Zotero.DB.executeTransaction(function* () { | 
					
						
							|  |  |  | 					yield Zotero.DB.executeTransaction( | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 						function* () {}, | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 							waitTimeout: 100, | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 							onRollback: function () { | 
					
						
							|  |  |  | 								callback1Ran = true; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 					) | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					onRollback: function () { | 
					
						
							|  |  |  | 						callback2Ran = true; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			catch (e) { | 
					
						
							| 
									
										
										
										
											2015-05-10 04:20:47 -04:00
										 |  |  | 				if (e.name != "TimeoutError") throw e; | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			assert.ok(callback1Ran); | 
					
						
							|  |  |  | 			assert.ok(callback2Ran); | 
					
						
							| 
									
										
										
										
											2015-04-26 17:49:25 -04:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2020-11-15 03:26:34 -05:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	describe("#columnExists()", function () { | 
					
						
							|  |  |  | 		it("should return true if a column exists", async function () { | 
					
						
							|  |  |  | 			assert.isTrue(await Zotero.DB.columnExists('items', 'itemID')); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should return false if a column doesn't exists", async function () { | 
					
						
							|  |  |  | 			assert.isFalse(await Zotero.DB.columnExists('items', 'foo')); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should return false if a table doesn't exists", async function () { | 
					
						
							|  |  |  | 			assert.isFalse(await Zotero.DB.columnExists('foo', 'itemID')); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2020-11-16 18:01:16 -05:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	describe("#indexExists()", function () { | 
					
						
							|  |  |  | 		it("should return true if an index exists", async function () { | 
					
						
							|  |  |  | 			assert.isTrue(await Zotero.DB.indexExists('items_synced')); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		it("should return false if an index doesn't exists", async function () { | 
					
						
							|  |  |  | 			assert.isFalse(await Zotero.DB.indexExists('foo')); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	describe("#parseSQLFile", function () { | 
					
						
							|  |  |  | 		it("should extract tables and indexes from userdata SQL file", async function () { | 
					
						
							|  |  |  | 			var sql = Zotero.File.getResource(`resource://zotero/schema/userdata.sql`); | 
					
						
							|  |  |  | 			var statements = await Zotero.DB.parseSQLFile(sql); | 
					
						
							|  |  |  | 			assert.isTrue(statements.some(x => x.startsWith('CREATE TABLE items'))); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2015-04-25 02:11:09 -04:00
										 |  |  | }); |