aboutsummaryrefslogtreecommitdiff
path: root/test/bun.js/sqlite.test.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
commit729d445b6885f69dd2c6355f38707bd42851c791 (patch)
treef87a7c408929ea3f57bbb7ace380cf869da83c0e /test/bun.js/sqlite.test.js
parent25f820c6bf1d8ec6d444ef579cc036b8c0607b75 (diff)
downloadbun-729d445b6885f69dd2c6355f38707bd42851c791.tar.gz
bun-729d445b6885f69dd2c6355f38707bd42851c791.tar.zst
bun-729d445b6885f69dd2c6355f38707bd42851c791.zip
change the directory structurejarred/rename
Diffstat (limited to 'test/bun.js/sqlite.test.js')
-rw-r--r--test/bun.js/sqlite.test.js430
1 files changed, 430 insertions, 0 deletions
diff --git a/test/bun.js/sqlite.test.js b/test/bun.js/sqlite.test.js
new file mode 100644
index 000000000..2250f97f0
--- /dev/null
+++ b/test/bun.js/sqlite.test.js
@@ -0,0 +1,430 @@
+import { expect, it } from "bun:test";
+import { Database, constants } from "bun:sqlite";
+
+var encode = (text) => Buffer.from(text);
+
+it("Database.open", () => {
+ // in a folder which doesn't exist
+ try {
+ Database.open(
+ "/this/database/does/not/exist.sqlite",
+ constants.SQLITE_OPEN_READWRITE
+ );
+ throw new Error("Expected an error to be thrown");
+ } catch (error) {
+ expect(error.message).toBe("unable to open database file");
+ }
+
+ // in a file which doesn't exist
+ try {
+ Database.open(
+ `/tmp/database-${Math.random()}.sqlite`,
+ constants.SQLITE_OPEN_READWRITE
+ );
+ throw new Error("Expected an error to be thrown");
+ } catch (error) {
+ expect(error.message).toBe("unable to open database file");
+ }
+
+ // in a file which doesn't exist
+ try {
+ Database.open(`/tmp/database-${Math.random()}.sqlite`, { readonly: true });
+ throw new Error("Expected an error to be thrown");
+ } catch (error) {
+ expect(error.message).toBe("unable to open database file");
+ }
+
+ // in a file which doesn't exist
+ try {
+ Database.open(`/tmp/database-${Math.random()}.sqlite`, { readwrite: true });
+ throw new Error("Expected an error to be thrown");
+ } catch (error) {
+ expect(error.message).toBe("unable to open database file");
+ }
+
+ // create works
+ {
+ var db = Database.open(`/tmp/database-${Math.random()}.sqlite`, {
+ create: true,
+ });
+ db.close();
+ }
+
+ // this should not throw
+ // it creates an in-memory db
+ new Database().close();
+});
+
+it("creates", () => {
+ const db = Database.open(":memory:");
+ db.exec(
+ "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, created TEXT, deci FLOAT, blobby BLOB)"
+ );
+ const stmt = db.prepare(
+ "INSERT INTO test (name, value, deci, created, blobby) VALUES (?, ?, ?, ?, ?)"
+ );
+
+ stmt.run([
+ "foo",
+ 1,
+ Math.fround(1.111),
+ new Date(1995, 12, 19).toISOString(),
+ encode("Hello World"),
+ ]);
+ stmt.run([
+ "bar",
+ 2,
+ Math.fround(2.222),
+ new Date(1995, 12, 19).toISOString(),
+ encode("Hello World"),
+ ]);
+ stmt.run([
+ "baz",
+ 3,
+ Math.fround(3.333),
+ new Date(1995, 12, 19).toISOString(),
+ encode("Hello World"),
+ ]);
+
+ stmt.finalize();
+
+ const stmt2 = db.prepare("SELECT * FROM test");
+ expect(JSON.stringify(stmt2.get())).toBe(
+ JSON.stringify({
+ id: 1,
+ name: "foo",
+ value: 1,
+ created: new Date(1995, 12, 19).toISOString(),
+ deci: Math.fround(1.111),
+ blobby: encode("Hello World"),
+ })
+ );
+
+ expect(JSON.stringify(stmt2.all())).toBe(
+ JSON.stringify([
+ {
+ id: 1,
+ name: "foo",
+ value: 1,
+ created: new Date(1995, 12, 19).toISOString(),
+ deci: Math.fround(1.111),
+ blobby: encode("Hello World"),
+ },
+ {
+ id: 2,
+ name: "bar",
+ value: 2,
+ created: new Date(1995, 12, 19).toISOString(),
+ deci: Math.fround(2.222),
+ blobby: encode("Hello World"),
+ },
+ {
+ id: 3,
+ name: "baz",
+ value: 3,
+ created: new Date(1995, 12, 19).toISOString(),
+ deci: Math.fround(3.333),
+ blobby: encode("Hello World"),
+ },
+ ])
+ );
+ expect(stmt2.run()).toBe(undefined);
+
+ // not necessary to run but it's a good practice
+ stmt2.finalize();
+});
+
+it("typechecks", () => {
+ const db = Database.open(":memory:");
+ db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)");
+ db.exec('INSERT INTO test (name) VALUES ("Hello")');
+ db.exec('INSERT INTO test (name) VALUES ("World")');
+
+ const q = db.prepare("SELECT * FROM test WHERE (name = ?)");
+
+ var expectfail = (val) => {
+ try {
+ q.run([val]);
+ throw new Error("Expected error");
+ } catch (e) {
+ expect(e.message !== "Expected error").toBe(true);
+ expect(e.name).toBe("TypeError");
+ }
+
+ try {
+ q.all([val]);
+ throw new Error("Expected error");
+ } catch (e) {
+ expect(e.message !== "Expected error").toBe(true);
+ expect(e.name).toBe("TypeError");
+ }
+
+ try {
+ q.get([val]);
+ throw new Error("Expected error");
+ } catch (e) {
+ expect(e.message !== "Expected error").toBe(true);
+ expect(e.name).toBe("TypeError");
+ }
+ };
+
+ expectfail(Symbol("oh hai"));
+ expectfail(new Date());
+ expectfail(class Foo {});
+ expectfail(() => class Foo {});
+ expectfail(new RangeError("what"));
+ expectfail(new Map());
+ expectfail(new Map([["foo", "bar"]]));
+ expectfail(new Set());
+ expectfail(new Set([1, 2, 3]));
+});
+
+it("db.query supports TypedArray", () => {
+ const db = Database.open(":memory:");
+
+ db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, blobby BLOB)");
+
+ const stmt = db.prepare("INSERT INTO test (blobby) VALUES (?)");
+ stmt.run([encode("Hello World")]);
+ stmt.finalize();
+
+ const stmt2 = db.prepare("SELECT * FROM test");
+ expect(JSON.stringify(stmt2.get())).toBe(
+ JSON.stringify({
+ id: 1,
+ blobby: encode("Hello World"),
+ })
+ );
+
+ const stmt3 = db.prepare("SELECT * FROM test WHERE (blobby = ?)");
+
+ expect(JSON.stringify(stmt3.get([encode("Hello World")]))).toBe(
+ JSON.stringify({
+ id: 1,
+ blobby: encode("Hello World"),
+ })
+ );
+
+ expect(
+ JSON.stringify(
+ db
+ .query("SELECT * FROM test WHERE (blobby = ?)")
+ .get([encode("Hello World")])
+ )
+ ).toBe(
+ JSON.stringify({
+ id: 1,
+ blobby: encode("Hello World"),
+ })
+ );
+
+ expect(stmt3.get([encode("Hello World NOT")])).toBe(null);
+});
+
+it("supports serialize/deserialize", () => {
+ const db = Database.open(":memory:");
+ db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)");
+ db.exec('INSERT INTO test (name) VALUES ("Hello")');
+ db.exec('INSERT INTO test (name) VALUES ("World")');
+
+ const input = db.serialize();
+ const db2 = new Database(input);
+
+ const stmt = db2.prepare("SELECT * FROM test");
+ expect(JSON.stringify(stmt.get())).toBe(
+ JSON.stringify({
+ id: 1,
+ name: "Hello",
+ })
+ );
+
+ expect(JSON.stringify(stmt.all())).toBe(
+ JSON.stringify([
+ {
+ id: 1,
+ name: "Hello",
+ },
+ {
+ id: 2,
+ name: "World",
+ },
+ ])
+ );
+ db2.exec("insert into test (name) values ('foo')");
+ expect(JSON.stringify(stmt.all())).toBe(
+ JSON.stringify([
+ {
+ id: 1,
+ name: "Hello",
+ },
+ {
+ id: 2,
+ name: "World",
+ },
+ {
+ id: 3,
+ name: "foo",
+ },
+ ])
+ );
+
+ const db3 = new Database(input, { readonly: true });
+ try {
+ db3.exec("insert into test (name) values ('foo')");
+ throw new Error("Expected error");
+ } catch (e) {
+ expect(e.message).toBe("attempt to write a readonly database");
+ }
+});
+
+it("db.query()", () => {
+ const db = Database.open(":memory:");
+ db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)");
+
+ expect(db[Symbol.for("Bun.Database.cache.count")]).toBe(0);
+
+ var q = db.query("SELECT * FROM test WHERE name = ?");
+ expect(q.get("Hello") === null).toBe(true);
+
+ db.exec('INSERT INTO test (name) VALUES ("Hello")');
+ db.exec('INSERT INTO test (name) VALUES ("World")');
+
+ var rows = db.query("SELECT * FROM test WHERE name = ?").all(["Hello"]);
+
+ expect(JSON.stringify(rows)).toBe(JSON.stringify([{ id: 1, name: "Hello" }]));
+
+ rows = db.query("SELECT * FROM test WHERE name = ?").all(["World"]);
+
+ // if this fails, it means the query caching failed to update
+ expect(JSON.stringify(rows)).toBe(JSON.stringify([{ id: 2, name: "World" }]));
+
+ rows = db.query("SELECT * FROM test WHERE name = ?").all(["Hello"]);
+ expect(JSON.stringify(rows)).toBe(JSON.stringify([{ id: 1, name: "Hello" }]));
+
+ // check that the query is cached
+ expect(db[Symbol.for("Bun.Database.cache.count")]).toBe(1);
+
+ db.clearQueryCache();
+
+ // check clearing the cache decremented the counter
+ expect(db[Symbol.for("Bun.Database.cache.count")]).toBe(0);
+
+ q.finalize();
+ try {
+ // check clearing the cache decremented the counter
+
+ q.all(["Hello"]);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ expect(e.message !== "Should have thrown").toBe(true);
+ }
+
+ // check that invalid queries are not cached
+ // and invalid queries throw
+ try {
+ db.query("SELECT * FROM BACON", ["Hello"]).all();
+ throw new Error("Should have thrown");
+ } catch (e) {
+ expect(e.message !== "Should have thrown").toBe(true);
+ expect(db[Symbol.for("Bun.Database.cache.count")]).toBe(0);
+ }
+
+ // check that it supports multiple arguments
+ expect(
+ JSON.stringify(
+ db
+ .query("SELECT * FROM test where (name = ? OR name = ?)")
+ .all(["Hello", "Fooooo"])
+ )
+ ).toBe(JSON.stringify([{ id: 1, name: "Hello" }]));
+ expect(
+ JSON.stringify(
+ db
+ .query("SELECT * FROM test where (name = ? OR name = ?)")
+ .all("Hello", "Fooooo")
+ )
+ ).toBe(JSON.stringify([{ id: 1, name: "Hello" }]));
+
+ // throws if insufficeint arguments
+ try {
+ db.query("SELECT * FROM test where (name = ? OR name = ?)").all("Hello");
+ } catch (e) {
+ expect(e.message).toBe("Expected 2 values, got 1");
+ }
+
+ // named parameters
+ expect(
+ JSON.stringify(
+ db
+ .query("SELECT * FROM test where (name = $hello OR name = $goodbye)")
+ .all({
+ $hello: "Hello",
+ $goodbye: "Fooooo",
+ })
+ )
+ ).toBe(JSON.stringify([{ id: 1, name: "Hello" }]));
+
+ db.close();
+
+ // Check that a closed database doesn't crash
+ // and does throw an error when trying to run a query
+ try {
+ db.query("SELECT * FROM test WHERE name = ?").all(["Hello"]);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ expect(e.message !== "Should have thrown").toBe(true);
+ }
+
+ // check that we can call close multiple times
+ // it should not throw so that your code doesn't break
+ db.close();
+ db.close();
+ db.close();
+});
+
+it("db.transaction()", () => {
+ const db = Database.open(":memory:");
+
+ db.exec(
+ "CREATE TABLE cats (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER)"
+ );
+
+ const insert = db.prepare(
+ "INSERT INTO cats (name, age) VALUES (@name, @age)"
+ );
+
+ expect(db.inTransaction).toBe(false);
+ const insertMany = db.transaction((cats) => {
+ expect(db.inTransaction).toBe(true);
+ try {
+ for (const cat of cats) insert.run(cat);
+ } catch (exception) {
+ throw exception;
+ }
+ });
+
+ try {
+ insertMany([
+ { "@name": "Joey", "@age": 2 },
+ { "@name": "Sally", "@age": 4 },
+ { "@name": "Junior", "@age": 1 },
+ { "@name": "Sally", "@age": 4 },
+ ]);
+ throw new Error("Should have thrown");
+ } catch (exception) {
+ expect(exception.message).toBe("constraint failed");
+ }
+
+ expect(db.inTransaction).toBe(false);
+ expect(db.query("SELECT * FROM cats").all().length).toBe(0);
+
+ expect(db.inTransaction).toBe(false);
+ insertMany([
+ { "@name": "Joey", "@age": 2 },
+ { "@name": "Sally", "@age": 4 },
+ { "@name": "Junior", "@age": 1 },
+ ]);
+ expect(db.inTransaction).toBe(false);
+ expect(db.query("SELECT * FROM cats").all().length).toBe(3);
+ expect(db.inTransaction).toBe(false);
+});