Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SQL and MQL tabular data query #145

Merged
merged 3 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ setup:
format:
dart format --line-length=140 --set-exit-if-changed $$(find . -name "*.dart" -not -path "./lib/src/gen/*" -not -path "**.mocks.dart" -not -path "**/.dart_tool/*")

build_mocks:
dart run build_runner build

test:
flutter test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80D4294CF70F00263BE5 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
19 changes: 19 additions & 0 deletions lib/src/app/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:async/async.dart';
import 'package:collection/collection.dart';
import 'package:fixnum/fixnum.dart';
import 'package:viam_sdk/src/gen/google/protobuf/any.pb.dart';
import 'package:viam_sdk/src/utils.dart';

import '../gen/app/data/v1/data.pbgrpc.dart';
import '../gen/app/datasync/v1/data_sync.pbgrpc.dart' hide CaptureInterval;
Expand Down Expand Up @@ -113,6 +114,24 @@ class DataClient {
return response.data;
}

/// Obtain unified tabular data and metadata, queried with SQL.
Future<List<Map<String, dynamic>>> tabularDataBySql(String organizationId, String query) async {
final request = TabularDataBySQLRequest()
..organizationId = organizationId
..sqlQuery = query;
final response = await _dataClient.tabularDataBySQL(request);
return response.data.map((e) => e.toMap()).toList();
}

/// Obtain unified tabular data and metadata, queried with MQL.
Future<List<Map<String, dynamic>>> tabularDataByMql(String organizationId, String query) async {
final request = TabularDataByMQLRequest()
..organizationId = organizationId
..mqlQuery = query;
final response = await _dataClient.tabularDataByMQL(request);
return response.data.map((e) => e.toMap()).toList();
}

/// Upload an image to Viam's Data Manager
///
/// If no name is provided, the current timestamp will be used as the filename.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extension ValueUtils on Value {
dynamic toPrimitive() {
if (hasBoolValue()) return boolValue;
if (hasListValue()) return listValue.values.map((e) => e.toPrimitive());
if (hasNullValue()) return nullValue;
if (hasNullValue()) return null;
if (hasNumberValue()) return numberValue;
if (hasStringValue()) return stringValue;
if (hasStructValue()) return structValue.fields.map((key, value) => MapEntry(key, value.toPrimitive()));
Expand Down
8 changes: 4 additions & 4 deletions lib/src/viam_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import './viam_sdk_impl.dart';
/// An object to interact with the Viam app
abstract class Viam {
/// Create an authenticated Viam instance with the provided [accessToken]
static Viam withAccessToken(String accessToken) {
return ViamImpl.withAccessToken(accessToken);
static Viam withAccessToken(String accessToken, {String serviceHost = 'app.viam.com', int servicePort = 443}) {
return ViamImpl.withAccessToken(accessToken, serviceHost: serviceHost, servicePort: servicePort);
}

static Future<Viam> withApiKey(String apiKeyId, String apiKey) async {
return ViamImpl.withApiKey(apiKeyId, apiKey);
static Future<Viam> withApiKey(String apiKeyId, String apiKey, {String serviceHost = 'app.viam.com'}) async {
return ViamImpl.withApiKey(apiKeyId, apiKey, serviceHost: serviceHost);
}

/// A client to communicate with Viam's app service
Expand Down
8 changes: 5 additions & 3 deletions lib/src/viam_sdk_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ class ViamImpl implements Viam {
_dataClient = DataClient(DataServiceClient(_clientChannelBase), DataSyncServiceClient(_clientChannelBase));
}

ViamImpl.withAccessToken(String accessToken) : _clientChannelBase = AuthenticatedChannel('app.viam.com', 443, accessToken, false) {
ViamImpl.withAccessToken(String accessToken, {String serviceHost = 'app.viam.com', int servicePort = 443})
: _clientChannelBase = AuthenticatedChannel(serviceHost, servicePort, accessToken, servicePort == 443 ? false : true) {
_appClient = AppClient(AppServiceClient(_clientChannelBase));
_dataClient = DataClient(DataServiceClient(_clientChannelBase), DataSyncServiceClient(_clientChannelBase));
}

static Future<ViamImpl> withApiKey(String apiKeyId, String apiKey) async {
static Future<ViamImpl> withApiKey(String apiKeyId, String apiKey, {String serviceHost = 'app.viam.com'}) async {
final channel = await dial(
'app.viam.com',
serviceHost,
DialOptions()
..authEntity = apiKeyId
..credentials = Credentials.apiKey(apiKey)
..attemptMdns = false
..webRtcOptions = (DialWebRtcOptions()..disable = true),
() => '');
return ViamImpl._withChannel(channel);
Expand Down
39 changes: 37 additions & 2 deletions test/unit_test/app/data_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:viam_sdk/protos/app/data.dart';
import 'package:viam_sdk/protos/app/data_sync.dart' hide CaptureInterval;
import 'package:viam_sdk/src/app/data.dart';
import 'package:viam_sdk/src/media/image.dart';
import 'package:viam_sdk/src/utils.dart';

import '../mocks/mock_response_future.dart';
import '../mocks/service_clients_mocks.mocks.dart';
Expand Down Expand Up @@ -111,7 +112,41 @@ void main() {
when(serviceClient.binaryDataByIDs(any)).thenAnswer((_) => MockResponseFuture.value(BinaryDataByIDsResponse()..data.addAll(data)));

final response = await dataClient.binaryDataByIds(ids);
expect(response, data);
expect(response, equals(data));
});

test('tabularDataBySql', () async {
final List<Map<String, dynamic>> data = [
{
'key1': 1,
'key2': '2',
'key3': [1, 2, 3],
'key4': {'key4sub1': 1}
},
];

when(serviceClient.tabularDataBySQL(any))
.thenAnswer((_) => MockResponseFuture.value(TabularDataBySQLResponse()..data.addAll(data.map((e) => e.toStruct()))));

final response = await dataClient.tabularDataBySql('some_org_id', 'some_query');
expect(response, equals(data));
});

test('tabularDataByMql', () async {
final List<Map<String, dynamic>> data = [
{
'key1': 1,
'key2': '2',
'key3': [1, 2, 3],
'key4': {'key4sub1': 1}
},
];

when(serviceClient.tabularDataByMQL(any))
.thenAnswer((_) => MockResponseFuture.value(TabularDataByMQLResponse()..data.addAll(data.map((e) => e.toStruct()))));

final response = await dataClient.tabularDataByMql('some_org_id', 'some_query');
expect(response, equals(data));
});
});

Expand Down Expand Up @@ -141,7 +176,7 @@ void main() {
expect(syncServiceClient.metadata, expected);

await dataClient.uploadFile('/dev/null', 'partId', fileName: 'otherName');
expect(syncServiceClient.metadata?.fileName, 'otherName');
expect(syncServiceClient.metadata?.fileName, equals('otherName'));
});
});
});
Expand Down
60 changes: 60 additions & 0 deletions test/unit_test/mocks/service_clients_mocks.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2825,6 +2825,66 @@ class MockDataServiceClient extends _i1.Mock implements _i12.DataServiceClient {
),
) as _i4.ResponseFuture<_i13.TabularDataByFilterResponse>);

@override
_i4.ResponseFuture<_i13.TabularDataBySQLResponse> tabularDataBySQL(
_i13.TabularDataBySQLRequest? request, {
_i3.CallOptions? options,
}) =>
(super.noSuchMethod(
Invocation.method(
#tabularDataBySQL,
[request],
{#options: options},
),
returnValue: _FakeResponseFuture_2<_i13.TabularDataBySQLResponse>(
this,
Invocation.method(
#tabularDataBySQL,
[request],
{#options: options},
),
),
returnValueForMissingStub:
_FakeResponseFuture_2<_i13.TabularDataBySQLResponse>(
this,
Invocation.method(
#tabularDataBySQL,
[request],
{#options: options},
),
),
) as _i4.ResponseFuture<_i13.TabularDataBySQLResponse>);

@override
_i4.ResponseFuture<_i13.TabularDataByMQLResponse> tabularDataByMQL(
_i13.TabularDataByMQLRequest? request, {
_i3.CallOptions? options,
}) =>
(super.noSuchMethod(
Invocation.method(
#tabularDataByMQL,
[request],
{#options: options},
),
returnValue: _FakeResponseFuture_2<_i13.TabularDataByMQLResponse>(
this,
Invocation.method(
#tabularDataByMQL,
[request],
{#options: options},
),
),
returnValueForMissingStub:
_FakeResponseFuture_2<_i13.TabularDataByMQLResponse>(
this,
Invocation.method(
#tabularDataByMQL,
[request],
{#options: options},
),
),
) as _i4.ResponseFuture<_i13.TabularDataByMQLResponse>);

@override
_i4.ResponseFuture<_i13.BinaryDataByFilterResponse> binaryDataByFilter(
_i13.BinaryDataByFilterRequest? request, {
Expand Down
2 changes: 1 addition & 1 deletion test/unit_test/utils/utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void main() {
group('ValueUtils toPrimitive', () {
test('null', () {
final nullValue = Value()..nullValue = NullValue.NULL_VALUE;
expect(nullValue.toPrimitive(), NullValue.NULL_VALUE);
expect(nullValue.toPrimitive(), null);
});

test('num', () {
Expand Down