syncbase/exec: Expose support for parameterized queries.
Allow Syncbase to accept parameterized queries, with '?' placeholders
in the where clause.
MultiPart: 5/5
Change-Id: Ic6f7d608c3d8433ec415e2a42c73c359069b5536
diff --git a/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart b/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart
index 26479a5..cecd4a2 100644
--- a/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart
+++ b/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart
@@ -3383,10 +3383,11 @@
class _SyncbaseDbExecParams extends bindings.Struct {
static const List<bindings.StructDataHeader> kVersions = const [
- const bindings.StructDataHeader(32, 0)
+ const bindings.StructDataHeader(40, 0)
];
String name = null;
String query = null;
+ List<List<int>> parameters = null;
Object stream = null;
_SyncbaseDbExecParams() : super(kVersions.last.size);
@@ -3434,7 +3435,19 @@
}
if (mainDataHeader.version >= 0) {
- result.stream = decoder0.decodeServiceInterface(24, false, ExecStreamProxy.newFromEndpoint);
+ var decoder1 = decoder0.decodePointer(24, false);
+ {
+ var si1 = decoder1.decodeDataHeaderForPointerArray(bindings.kUnspecifiedArrayLength);
+ result.parameters = new List<List<int>>(si1.numElements);
+ for (int i1 = 0; i1 < si1.numElements; ++i1) {
+
+ result.parameters[i1] = decoder1.decodeUint8Array(bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i1, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+ }
+ }
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.stream = decoder0.decodeServiceInterface(32, false, ExecStreamProxy.newFromEndpoint);
}
return result;
}
@@ -3446,13 +3459,24 @@
encoder0.encodeString(query, 16, false);
- encoder0.encodeInterface(stream, 24, false);
+ if (parameters == null) {
+ encoder0.encodeNullPointer(24, false);
+ } else {
+ var encoder1 = encoder0.encodePointerArray(parameters.length, 24, bindings.kUnspecifiedArrayLength);
+ for (int i0 = 0; i0 < parameters.length; ++i0) {
+
+ encoder1.encodeUint8Array(parameters[i0], bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i0, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+ }
+ }
+
+ encoder0.encodeInterface(stream, 32, false);
}
String toString() {
return "_SyncbaseDbExecParams("
"name: $name" ", "
"query: $query" ", "
+ "parameters: $parameters" ", "
"stream: $stream" ")";
}
@@ -9161,7 +9185,7 @@
dynamic dbCreate(String name,Perms perms,[Function responseFactory = null]);
dynamic dbDestroy(String name,[Function responseFactory = null]);
dynamic dbExists(String name,[Function responseFactory = null]);
- dynamic dbExec(String name,String query,Object stream,[Function responseFactory = null]);
+ dynamic dbExec(String name,String query,List<List<int>> parameters,Object stream,[Function responseFactory = null]);
dynamic dbBeginBatch(String name,BatchOptions bo,[Function responseFactory = null]);
dynamic dbCommit(String name,[Function responseFactory = null]);
dynamic dbAbort(String name,[Function responseFactory = null]);
@@ -10225,10 +10249,11 @@
-1,
bindings.MessageHeader.kMessageExpectsResponse);
}
- dynamic dbExec(String name,String query,Object stream,[Function responseFactory = null]) {
+ dynamic dbExec(String name,String query,List<List<int>> parameters,Object stream,[Function responseFactory = null]) {
var params = new _SyncbaseDbExecParams();
params.name = name;
params.query = query;
+ params.parameters = parameters;
params.stream = stream;
return _proxyImpl.sendMessageWithRequestId(
params,
@@ -11146,7 +11171,7 @@
case _Syncbase_dbExecName:
var params = _SyncbaseDbExecParams.deserialize(
message.payload);
- var response = _impl.dbExec(params.name,params.query,params.stream,_SyncbaseDbExecResponseParamsFactory);
+ var response = _impl.dbExec(params.name,params.query,params.parameters,params.stream,_SyncbaseDbExecResponseParamsFactory);
if (response is Future) {
return response.then((response) {
if (response != null) {
diff --git a/lib/src/nosql/abstract_database.dart b/lib/src/nosql/abstract_database.dart
index e2d7680..d56456b 100644
--- a/lib/src/nosql/abstract_database.dart
+++ b/lib/src/nosql/abstract_database.dart
@@ -22,7 +22,7 @@
}
// Executes a syncQL query.
- Stream<mojom.Result> exec(String query) {
+ Stream<mojom.Result> exec(String query, [List<List<int>> params = const []]) {
StreamController<mojom.Result> sc = new StreamController();
mojom.ExecStreamStub stub = new mojom.ExecStreamStub.unbound();
@@ -31,7 +31,7 @@
_ctx.unclosedStubsManager.register(stub);
// Call dbExec asynchronously.
- _ctx.syncbase.dbExec(fullName, query, stub).then((v) {
+ _ctx.syncbase.dbExec(fullName, query, params, stub).then((v) {
// TODO(nlacasse): Same question regarding throwing behavior as TableScan.
if (isError(v.err)) throw v.err;
});
diff --git a/mojom/syncbase.mojom b/mojom/syncbase.mojom
index 5c7c136..359e252 100644
--- a/mojom/syncbase.mojom
+++ b/mojom/syncbase.mojom
@@ -129,7 +129,7 @@
DbCreate(string name, Perms perms) => (Error err);
DbDestroy(string name) => (Error err);
DbExists(string name) => (Error err, bool exists);
- DbExec(string name, string query, ExecStream stream) => (Error err);
+ DbExec(string name, string query, array<array<uint8>> parameters, ExecStream stream) => (Error err);
DbBeginBatch(string name, BatchOptions? bo) => (Error err, string batch_suffix);
DbCommit(string name) => (Error err);
DbAbort(string name) => (Error err);
diff --git a/test/integration/syncbase_database_test.dart b/test/integration/syncbase_database_test.dart
index 7aef437..519abf9 100644
--- a/test/integration/syncbase_database_test.dart
+++ b/test/integration/syncbase_database_test.dart
@@ -217,5 +217,36 @@
expect(decodeStrs(results[2].values), equals(['yyz', 'Toronto']));
});
+ test('parameterized exec', () async {
+ var app = c.app(utils.uniqueName('app'));
+ await app.create(utils.emptyPerms());
+ var db = app.noSqlDatabase(utils.uniqueName('db'));
+ await db.create(utils.emptyPerms());
+ var table = db.table('airports');
+ await table.create(utils.emptyPerms());
+
+ await table.put('jfk', UTF8.encode('New York'));
+ await table.put('lga', UTF8.encode('New York'));
+ await table.put('ord', UTF8.encode('Chicago'));
+ await table.put('sfo', UTF8.encode('San Francisco'));
+
+ // TODO(ivanpi): Once VDL types are in, add parameterized key comparison
+ // and non-string parameters in where clause.
+ var query = 'select k as code, v as cityname from airports where v = ? or v = ?';
+ var resultStream = db.exec(query, [UTF8.encode('Chicago'), UTF8.encode('New York')]);
+
+ var results = await resultStream.toList();
+ // Expect column headers plus three rows.
+ expect(results.length, 4);
+
+ // Check column headers.
+ expect(decodeStrs(results[0].values), equals(['code', 'cityname']));
+
+ // Check rows.
+ expect(decodeStrs(results[1].values), equals(['jfk', 'New York']));
+ expect(decodeStrs(results[2].values), equals(['lga', 'New York']));
+ expect(decodeStrs(results[3].values), equals(['ord', 'Chicago']));
+ });
+
// TODO(nlacasse): Test database.get/setPermissions.
}