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

RSDK-4439 - add more data methods #165

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1eebcdc
add binarydata request functions
purplenicole730 Sep 21, 2023
d2d7570
ease call of binary ids
purplenicole730 Sep 21, 2023
299a859
test basic createfilter
purplenicole730 Sep 22, 2023
7c0cf75
test createfilter with options
purplenicole730 Sep 25, 2023
7aefe70
test tabulardatabyfilter
purplenicole730 Sep 25, 2023
7c626f1
clean up
purplenicole730 Sep 25, 2023
7885c1d
add small sanity check
purplenicole730 Sep 25, 2023
fcd805d
limit variable redefinitions
purplenicole730 Sep 25, 2023
9592654
test binarydatabyfilter
purplenicole730 Sep 25, 2023
420cc40
make format lint
purplenicole730 Sep 25, 2023
d8be961
add binarydatabyid test
purplenicole730 Sep 26, 2023
147a121
respond differently for filtered tests
purplenicole730 Sep 26, 2023
067d212
clean up tests
purplenicole730 Sep 26, 2023
6b1e864
test filtered binary data
purplenicole730 Sep 26, 2023
5e2c71d
test calling binarydata with only one id
purplenicole730 Sep 26, 2023
25bab08
clean up tests
purplenicole730 Sep 26, 2023
d39868b
add extra filter
purplenicole730 Sep 26, 2023
65f1f68
add filters
purplenicole730 Sep 26, 2023
ba012c7
use createfilter for filters
purplenicole730 Sep 26, 2023
d157411
remove unnecessary parts in viam client
purplenicole730 Sep 26, 2023
dc781a3
add viam client test
purplenicole730 Sep 27, 2023
7c407ae
undo small change
purplenicole730 Sep 27, 2023
6d81231
use map function instead of for loop
purplenicole730 Sep 27, 2023
4ecfbc7
rename expected filter
purplenicole730 Sep 27, 2023
2b67ff6
Merge branch 'RSDK-4439-add-more-data-methods' of github.com:purpleni…
purplenicole730 Sep 27, 2023
3c6573e
undo changes in example
purplenicole730 Sep 27, 2023
d2e1f99
rename expected request
purplenicole730 Sep 27, 2023
d1c1dee
create data requests outside of for loops
purplenicole730 Sep 27, 2023
6d44e09
make format
purplenicole730 Sep 27, 2023
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
2 changes: 1 addition & 1 deletion examples/connect-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

263 changes: 263 additions & 0 deletions src/app/data-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import { FakeTransportBuilder } from '@improbable-eng/grpc-web-fake-transport';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { Struct } from 'google-protobuf/google/protobuf/struct_pb';
import {
beforeEach,
describe,
expect,
type SpyInstance,
test,
vi,
} from 'vitest';
import {
BinaryData,
BinaryDataByFilterRequest,
BinaryDataByFilterResponse,
BinaryDataByIDsRequest,
BinaryID,
CaptureInterval,
DataRequest,
Filter,
TabularData,
TabularDataByFilterRequest,
TabularDataByFilterResponse,
TagsFilter,
} from '../gen/app/data/v1/data_pb';
import { DataServiceClient } from '../gen/app/data/v1/data_pb_service';
vi.mock('../gen/app/data/v1/data_pb_service');
import { DataClient } from './data-client';

const subject = () =>
new DataClient('fakeServiceHost', {
transport: new FakeTransportBuilder().build(),
});
describe('DataClient tests', () => {
describe('tabularDataByFilter tests', () => {
let methodSpy: SpyInstance;
const tabData1 = new TabularData();
const tabData2 = new TabularData();
tabData1.setData(Struct.fromJavaScript({ key: 'value1' }));
tabData2.setData(Struct.fromJavaScript({ key: 'value2' }));
const tabDataResponse = new TabularDataByFilterResponse();
tabDataResponse.setDataList([tabData1, tabData2]);

beforeEach(() => {
methodSpy = vi
.spyOn(DataServiceClient.prototype, 'tabularDataByFilter')
// @ts-expect-error compiler is matching incorrect function signature
.mockImplementationOnce((_req: TabularDataByFilterRequest, _md, cb) => {
cb(null, tabDataResponse);
})
// @ts-expect-error compiler is matching incorrect function signature
.mockImplementation((_req, _md, cb) => {
cb(null, {
getDataList: () => [],
});
});
});

test('get tabular data', async () => {
const promise = await subject().tabularDataByFilter();
expect(promise.length).toEqual(2);
const [data1, data2] = promise;
expect(data1).toMatchObject(tabData1.toObject());
expect(data2).toMatchObject(tabData2.toObject());
});

test('get filtered tabular data', async () => {
const filter = subject().createFilter({
componentName: 'testComponentName',
componentType: 'testComponentType',
});

const dataReq = new DataRequest();
dataReq.setFilter(filter);
dataReq.setLimit(100);
dataReq.setLast('');
const expectedRequest = new TabularDataByFilterRequest();
expectedRequest.setDataRequest(dataReq);
expectedRequest.setCountOnly(false);

await subject().tabularDataByFilter(filter);
expect(methodSpy).toHaveBeenCalledWith(
expectedRequest,
expect.anything(),
expect.anything()
);
});
});

const bin1 = 'binary1';
const bin2 = 'binary2';
const binData1 = new BinaryData();
binData1.setBinary(bin1);
const binData2 = new BinaryData();
binData2.setBinary(bin2);
const binDataResponse = new BinaryDataByFilterResponse();
binDataResponse.setDataList([binData1, binData2]);

describe('binaryDataByFilter tests', () => {
let methodSpy: SpyInstance;
beforeEach(() => {
methodSpy = vi
.spyOn(DataServiceClient.prototype, 'binaryDataByFilter')
// @ts-expect-error compiler is matching incorrect function signature
.mockImplementationOnce((_req: BinaryDataByFilterRequest, _md, cb) => {
cb(null, binDataResponse);
})
// @ts-expect-error compiler is matching incorrect function signature
.mockImplementation((_req, _md, cb) => {
cb(null, {
getDataList: () => [],
});
});
});
test('get binary data', async () => {
const promise = await subject().binaryDataByFilter();
expect(promise.length).toEqual(2);
expect(promise[0]?.binary).toEqual(bin1);
expect(promise[1]?.binary).toEqual(bin2);
});

test('get filtered binary data', async () => {
const filter = subject().createFilter({
componentName: 'testComponentName',
componentType: 'testComponentType',
});

const dataReq = new DataRequest();
dataReq.setFilter(filter);
dataReq.setLimit(100);
dataReq.setLast('');
const expectedRequest = new BinaryDataByFilterRequest();
expectedRequest.setDataRequest(dataReq);
expectedRequest.setCountOnly(false);

await subject().binaryDataByFilter(filter);
expect(methodSpy).toHaveBeenCalledWith(
expectedRequest,
expect.anything(),
expect.anything()
);
});
});

describe('binaryDataById tests', () => {
let methodSpy: SpyInstance;
beforeEach(() => {
methodSpy = vi
.spyOn(DataServiceClient.prototype, 'binaryDataByIDs')
// @ts-expect-error compiler is matching incorrect function signature
.mockImplementation((_req: BinaryDataByIDsRequest, _md, cb) => {
cb(null, binDataResponse);
});
});

const binaryId1 = new BinaryID();
binaryId1.setFileId('testFileId1');
binaryId1.setOrganizationId('testOrgId');
binaryId1.setLocationId('testLocationId');
const binaryId2 = new BinaryID();
binaryId2.setFileId('testFileId1');
binaryId2.setOrganizationId('testOrgId');
binaryId2.setLocationId('testLocationId');

test('get binary data by ids', async () => {
const promise = await subject().binaryDataByIds([
binaryId1.toObject(),
binaryId2.toObject(),
]);
expect(promise.length).toEqual(2);
expect(promise[0]?.binary).toEqual(bin1);
expect(promise[1]?.binary).toEqual(bin2);
});

test('get binary data by id', async () => {
const expectedRequest = new BinaryDataByIDsRequest();
expectedRequest.setBinaryIdsList([binaryId1]);
expectedRequest.setIncludeBinary(true);

await subject().binaryDataByIds([binaryId1.toObject()]);
expect(methodSpy).toHaveBeenCalledWith(
expectedRequest,
expect.anything(),
expect.anything()
);
});
});

describe('createFilter tests', () => {
test('create empty filter', () => {
const testFilter = subject().createFilter({});
expect(testFilter).toEqual(new Filter());
});

test('create filter', () => {
const opts = { componentName: 'camera' };
const testFilter = subject().createFilter(opts);

const expectedFilter = new Filter();
expectedFilter.setComponentName('camera');

expect(testFilter).toEqual(expectedFilter);
});

test('create filter with all options', () => {
const componentName = 'testComponentName';
const componentType = 'testComponentType';
const method = 'testMethod';
const robotName = 'testRobotName';
const robotId = 'testRobotId';
const partName = 'testPartName';
const partId = 'testPartId';
const locationsIdsList = ['testLocationId1', 'testLocationId2'];
const organizationIdsList = ['testOrgId1', 'testOrgId2'];
const mimeTypeList = ['testMimeType1', 'testMimeType2'];
const bboxLabelsList = ['testBboxLabel1', 'testBboxLabel2'];
const startTime = new Date(1, 1, 1, 1, 1, 1);
const endTime = new Date(2, 2, 2, 2, 2, 2);
const interval = new CaptureInterval();
interval.setStart(Timestamp.fromDate(startTime));
interval.setEnd(Timestamp.fromDate(endTime));
maximpertsov marked this conversation as resolved.
Show resolved Hide resolved
const tagsList = ['testTag1', 'testTag2'];
const tagsFilter = new TagsFilter();
tagsFilter.setTagsList(tagsList);
maximpertsov marked this conversation as resolved.
Show resolved Hide resolved

const opts = {
componentName,
componentType,
method,
robotName,
robotId,
partName,
partId,
locationIdsList: locationsIdsList,
organizationIdsList,
mimeTypeList,
bboxLabelsList,
startTime,
endTime,
tags: tagsList,
};
const testFilter = subject().createFilter(opts);
expect(testFilter.getComponentType()).toEqual('testComponentType');

const expectedFilter = new Filter();
expectedFilter.setComponentName(componentName);
expectedFilter.setComponentType(componentType);
expectedFilter.setMethod(method);
expectedFilter.setRobotName(robotName);
expectedFilter.setRobotId(robotId);
expectedFilter.setPartName(partName);
expectedFilter.setPartId(partId);
expectedFilter.setLocationIdsList(locationsIdsList);
expectedFilter.setOrganizationIdsList(organizationIdsList);
expectedFilter.setMimeTypeList(mimeTypeList);
expectedFilter.setBboxLabelsList(bboxLabelsList);
expectedFilter.setInterval(interval);
expectedFilter.setTagsFilter(tagsFilter);

expect(testFilter).toEqual(expectedFilter);
});
});
});
72 changes: 63 additions & 9 deletions src/app/data-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import pb from '../gen/app/data/v1/data_pb';
import { DataServiceClient } from '../gen/app/data/v1/data_pb_service';
import { promisify } from '../utils';

export type BinaryID = pb.BinaryID.AsObject;

export type FilterOptions = Partial<pb.Filter.AsObject> & {
endTime?: Date;
startTime?: Date;
Expand All @@ -25,20 +27,16 @@ export class DataClient {
this.service = new DataServiceClient(serviceHost, grpcOptions);
}

async tabularDataByFilter(filter: pb.Filter | undefined) {
async tabularDataByFilter(filter?: pb.Filter) {
const { service } = this;

let last = '';
const dataArray: TabularData[] = [];
const dataReq = new pb.DataRequest();
dataReq.setFilter(filter ?? new pb.Filter());
dataReq.setLimit(100);

for (;;) {
const dataReq = new pb.DataRequest();
if (filter) {
dataReq.setFilter(filter);
} else {
dataReq.setFilter(new pb.Filter());
}
dataReq.setLimit(100);
dataReq.setLast(last);

const req = new pb.TabularDataByFilterRequest();
Expand Down Expand Up @@ -67,6 +65,62 @@ export class DataClient {
return dataArray;
}

async binaryDataByFilter(filter?: pb.Filter) {
const { service } = this;

let last = '';
const dataArray: pb.BinaryData.AsObject[] = [];
const dataReq = new pb.DataRequest();
dataReq.setFilter(filter ?? new pb.Filter());
dataReq.setLimit(100);

for (;;) {
dataReq.setLast(last);

const req = new pb.BinaryDataByFilterRequest();
req.setDataRequest(dataReq);
req.setCountOnly(false);

// eslint-disable-next-line no-await-in-loop
const response = await promisify<
pb.BinaryDataByFilterRequest,
pb.BinaryDataByFilterResponse
>(service.binaryDataByFilter.bind(service), req);
const dataList = response.getDataList();
if (!dataList || dataList.length === 0) {
break;
}
dataArray.push(...dataList.map((data) => data.toObject()));
last = response.getLast();
}

return dataArray;
}

async binaryDataByIds(ids: BinaryID[]) {
const { service } = this;

const binaryIds: pb.BinaryID[] = ids.map(
({ fileId, organizationId, locationId }) => {
const binaryId = new pb.BinaryID();
binaryId.setFileId(fileId);
binaryId.setOrganizationId(organizationId);
binaryId.setLocationId(locationId);
return binaryId;
}
);

const req = new pb.BinaryDataByIDsRequest();
req.setBinaryIdsList(binaryIds);
req.setIncludeBinary(true);

const response = await promisify<
pb.BinaryDataByIDsRequest,
pb.BinaryDataByIDsResponse
>(service.binaryDataByIDs.bind(service), req);
return response.toObject().dataList;
}

// eslint-disable-next-line class-methods-use-this
createFilter(options: FilterOptions): pb.Filter {
const filter = new pb.Filter();
Expand Down Expand Up @@ -118,8 +172,8 @@ export class DataClient {
const tagsFilter = new pb.TagsFilter();
if (options.tags) {
tagsFilter.setTagsList(options.tags);
filter.setTagsFilter(tagsFilter);
}
filter.setTagsFilter(tagsFilter);

return filter;
}
Expand Down
Loading