Skip to content

Commit 9fe44b8

Browse files
committed
src, test: allow specifying options.table to createSession
1 parent c049c41 commit 9fe44b8

File tree

2 files changed

+138
-62
lines changed

2 files changed

+138
-62
lines changed

src/node_sqlite.cc

+28-3
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,35 @@ void DatabaseSync::Exec(const FunctionCallbackInfo<Value>& args) {
223223
}
224224

225225
void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
226+
std::string table;
227+
228+
Environment* env = Environment::GetCurrent(args);
229+
if (args.Length() > 0) {
230+
if (!args[0]->IsObject()) {
231+
node::THROW_ERR_INVALID_ARG_TYPE(
232+
env->isolate(), "The \"options\" argument must be an object.");
233+
return;
234+
}
235+
236+
Local<Object> options = args[0].As<Object>();
237+
238+
Local<String> table_key = String::NewFromUtf8(env->isolate(), "table", v8::NewStringType::kNormal).ToLocalChecked();
239+
if (options->HasOwnProperty(env->context(), table_key).FromJust()) {
240+
Local<Value> table_value = options->Get(env->context(), table_key).ToLocalChecked();
241+
242+
if (table_value->IsString()) {
243+
String::Utf8Value str(env->isolate(), table_value);
244+
table = std::string(*str);
245+
} else {
246+
node::THROW_ERR_INVALID_ARG_TYPE(
247+
env->isolate(), "The \"options.table\" argument must be a string.");
248+
return;
249+
}
250+
}
251+
}
252+
226253
DatabaseSync* db;
227254
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
228-
Environment* env = Environment::GetCurrent(args);
229255
THROW_AND_RETURN_ON_BAD_STATE(
230256
env, db->connection_ == nullptr, "database is not open");
231257

@@ -235,8 +261,7 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
235261
CHECK_ERROR_OR_THROW(env->isolate(), db->connection_, r, SQLITE_OK, void());
236262
db->sessions_.insert(pSession);
237263

238-
// TODO(louwers): allow specifying table name
239-
r = sqlite3session_attach(pSession, nullptr);
264+
r = sqlite3session_attach(pSession, table == "" ? nullptr : table.c_str());
240265
CHECK_ERROR_OR_THROW(env->isolate(), db->connection_, r, SQLITE_OK, void());
241266

242267

test/parallel/test-sqlite.js

+110-59
Original file line numberDiff line numberDiff line change
@@ -757,68 +757,119 @@ test('PRAGMAs are supported', (t) => {
757757
);
758758
});
759759

760-
test('creating and applying a changeset', (t) => {
761-
const createDatabase = () => {
762-
const database = new DatabaseSync(':memory:');
763-
database.exec(`
760+
suite('session extension', () => {
761+
test('creating and applying a changeset', (t) => {
762+
const createDataTableSql = `
764763
CREATE TABLE data(
765764
key INTEGER PRIMARY KEY,
766765
value TEXT
767-
) STRICT
768-
`);
769-
return database;
770-
};
771-
772-
const databaseFrom = createDatabase();
773-
const session = databaseFrom.createSession();
774-
775-
const select = 'SELECT * FROM data ORDER BY key';
776-
777-
const insert = databaseFrom.prepare('INSERT INTO data (key, value) VALUES (?, ?)');
778-
insert.run(1, 'hello');
779-
insert.run(2, 'world');
780-
781-
const databaseTo = createDatabase();
782-
783-
databaseTo.applyChangeset(session.changeset());
784-
t.assert.deepStrictEqual(
785-
databaseFrom.prepare(select).all(),
786-
databaseTo.prepare(select).all()
787-
);
788-
});
789-
790-
test('trying to create session when database is closed results in exception', (t) => {
791-
const database = new DatabaseSync(':memory:');
792-
database.close();
793-
t.assert.throws(() => {
794-
database.createSession();
795-
}, {
796-
name: 'Error',
797-
message: 'database is not open',
766+
) STRICT`;
767+
768+
const createDatabase = () => {
769+
const database = new DatabaseSync(':memory:');
770+
database.exec(createDataTableSql);
771+
return database;
772+
};
773+
774+
const databaseFrom = createDatabase();
775+
const session = databaseFrom.createSession();
776+
777+
const select = 'SELECT * FROM data ORDER BY key';
778+
779+
const insert = databaseFrom.prepare('INSERT INTO data (key, value) VALUES (?, ?)');
780+
insert.run(1, 'hello');
781+
insert.run(2, 'world');
782+
783+
const databaseTo = createDatabase();
784+
785+
databaseTo.applyChangeset(session.changeset());
786+
t.assert.deepStrictEqual(
787+
databaseFrom.prepare(select).all(),
788+
databaseTo.prepare(select).all()
789+
);
798790
});
799-
});
800-
801-
test('trying to create changeset when database is closed results in exception', (t) => {
802-
const database = new DatabaseSync(':memory:');
803-
const session = database.createSession();
804-
database.close();
805-
t.assert.throws(() => {
806-
session.changeset();
807-
}, {
808-
name: 'Error',
809-
message: 'database is not open',
791+
792+
test('trying to create session when database is closed results in exception', (t) => {
793+
const database = new DatabaseSync(':memory:');
794+
database.close();
795+
t.assert.throws(() => {
796+
database.createSession();
797+
}, {
798+
name: 'Error',
799+
message: 'database is not open',
800+
});
810801
});
811-
});
812-
813-
test('trying to apply a changeset when database is closed results in exception', (t) => {
814-
const database = new DatabaseSync(':memory:');
815-
const session = database.createSession();
816-
const changeset = session.changeset();
817-
database.close();
818-
t.assert.throws(() => {
819-
database.applyChangeset(changeset);
820-
}, {
821-
name: 'Error',
822-
message: 'database is not open',
802+
803+
test('trying to create changeset when database is closed results in exception', (t) => {
804+
const database = new DatabaseSync(':memory:');
805+
const session = database.createSession();
806+
database.close();
807+
t.assert.throws(() => {
808+
session.changeset();
809+
}, {
810+
name: 'Error',
811+
message: 'database is not open',
812+
});
813+
});
814+
815+
test('trying to apply a changeset when database is closed results in exception', (t) => {
816+
const database = new DatabaseSync(':memory:');
817+
const session = database.createSession();
818+
const changeset = session.changeset();
819+
database.close();
820+
t.assert.throws(() => {
821+
database.applyChangeset(changeset);
822+
}, {
823+
name: 'Error',
824+
message: 'database is not open',
825+
});
823826
});
824-
});
827+
828+
test('set table with wrong type when creating session', (t) => {
829+
const database = new DatabaseSync(':memory:');
830+
t.assert.throws(() => {
831+
database.createSession({
832+
table: true
833+
});
834+
}, {
835+
name: 'TypeError',
836+
message: 'The "table" property must be a string.'
837+
});
838+
});
839+
840+
test('setting options.table causes only one table to be tracked', (t) => {
841+
const database1 = new DatabaseSync(':memory:');
842+
const database2 = new DatabaseSync(':memory:');
843+
844+
const createData1TableSql = `CREATE TABLE data1 (
845+
key INTEGER PRIMARY KEY,
846+
value TEXT
847+
) STRICT
848+
`;
849+
const createData2TableSql = `CREATE TABLE data2 (
850+
key INTEGER PRIMARY KEY,
851+
value TEXT
852+
) STRICT
853+
`;
854+
database1.exec(createData1TableSql);
855+
database1.exec(createData2TableSql);
856+
database2.exec(createData1TableSql);
857+
database2.exec(createData2TableSql);
858+
859+
const session = database1.createSession({
860+
table: 'data1'
861+
});
862+
const insert1 = database1.prepare('INSERT INTO data1 (key, value) VALUES (?, ?)');
863+
insert1.run(1, 'hello');
864+
insert1.run(2, 'world');
865+
const insert2 = database1.prepare('INSERT INTO data2 (key, value) VALUES (?, ?)');
866+
insert2.run(1, 'hello');
867+
insert2.run(2, 'world');
868+
const select1 = 'SELECT * FROM data1 ORDER BY key';
869+
const select2 = 'SELECT * FROM data2 ORDER BY key';
870+
database2.applyChangeset(session.changeset());
871+
t.assert.deepStrictEqual(database1.prepare(select1).all(), database2.prepare(select1).all()); // data1 table should be equal
872+
t.assert.deepStrictEqual(database2.prepare(select2).all(), []); // data2 should be empty in database2
873+
t.assert.strictEqual(database1.prepare(select2).all().length, 2); // data1 should have values in database1
874+
});
875+
});

0 commit comments

Comments
 (0)