Skip to content

Commit

Permalink
Proto Conversion - Add support for arrays (#1866)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfontanarosa committed Jun 20, 2024
1 parent 9ddc74d commit c248e1f
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 9 deletions.
20 changes: 19 additions & 1 deletion lib/src/firestore-to-proto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {GroundProtos} from '@ground/proto';
import {toMessage} from './firestore-to-proto';
import {Constructor} from 'protobufjs';

const {Job, Role, Style, Survey, Task} = GroundProtos.google.ground.v1beta1;
const {Coordinates, Job, LinearRing, Role, Style, Survey, Task} =
GroundProtos.google.ground.v1beta1;

describe('toMessage()', () => {
[
Expand All @@ -42,6 +43,23 @@ describe('toMessage()', () => {
style: new Style({color: '#112233'}),
}),
},
{
desc: 'converts repeated message',
input: {
'1': [
{'1': 5, '2': 7},
{'1': 12, '2': 23},
{'1': 9, '2': 2},
],
},
expected: new LinearRing({
coordinates: [
new Coordinates({latitude: 5, longitude: 7}),
new Coordinates({latitude: 12, longitude: 23}),
new Coordinates({latitude: 9, longitude: 2}),
],
}),
},
{
desc: 'converts map<string, enum>',
input: {
Expand Down
15 changes: 10 additions & 5 deletions lib/src/firestore-to-proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ function toMessageValue(
firestoreValue: any
): any | Error | null {
if (!descriptor.fields) return null;
const fields = descriptor.fields[fieldName];
const fieldType = fields?.type;
if (fields.keyType) {
if (fields.keyType !== 'string')
return Error(`${fields.keyType} map keys not supported`);
const field = descriptor.fields[fieldName];
const fieldType = field?.type;
if (field.keyType) {
if (field.keyType !== 'string')
return Error(`${field.keyType} map keys not supported`);
// TODO: Check that firestoreValue is an object.
return toMapValue(messageTypePath, fieldType, firestoreValue);
} else if (field?.rule === 'repeated') {
if (!Array.isArray(firestoreValue))
return Error(`Expected array, but got ${firestoreValue}`);
return firestoreValue.map(v => toFieldValue(messageTypePath, fieldType, v));
} else {
return toFieldValue(messageTypePath, fieldType, firestoreValue);
}
Expand Down Expand Up @@ -108,6 +112,7 @@ function toFieldValue(
case 'int32':
case 'int64':
case 'bool':
case 'double':
return firestoreValue;
default:
return toMessageOrEnumValue(messageTypePath, fieldType, firestoreValue);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/message-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface FieldDescriptor {
keyType?: string; // Used for proto map<>
type: string;
id: number;
rule?: 'repeated';
}

export interface MessageDescriptor {
Expand Down Expand Up @@ -59,7 +60,7 @@ export class MessageRegistry {
// Gets URL of nested type in the format "/ClassA.ClassB.ClassC".
const typeUrl = constructor.getTypeUrl('');
if (typeUrl?.substr(0, 1) !== '/') {
console.error("Invalid type URL returned by protojs class:", typeUrl);
console.error('Invalid type URL returned by protojs class:', typeUrl);
return null;
}
// Remove preceding "/" and split path along ".";
Expand Down
20 changes: 19 additions & 1 deletion lib/src/proto-to-firestore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import {GroundProtos} from '@ground/proto';
import {toDocumentData} from './proto-to-firestore';

const {Job, Role, Style, Survey, Task} = GroundProtos.google.ground.v1beta1;
const {Job, Role, Style, Survey, Task, LinearRing, Coordinates} =
GroundProtos.google.ground.v1beta1;

describe('toDocumentData()', () => {
[
Expand All @@ -32,6 +33,23 @@ describe('toDocumentData()', () => {
'3': 'Survey desc',
},
},
{
desc: 'converts repeated message',
input: new LinearRing({
coordinates: [
new Coordinates({latitude: 5, longitude: 7}),
new Coordinates({latitude: 12, longitude: 23}),
new Coordinates({latitude: 9, longitude: 2}),
],
}),
expected: {
'1': [
{'1': 5, '2': 7},
{'1': 12, '2': 23},
{'1': 9, '2': 2},
],
},
},
{
desc: 'converts nested message',
input: new Job({
Expand Down
10 changes: 9 additions & 1 deletion lib/src/proto-to-firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,21 @@ function toDocumentFieldValue(
}
}

function toObjectValue(fieldType: string, value: any) {
if (Array.isArray(value)) {
return value.map(v => toValue(fieldType, v));
} else {
return toDocumentData(value);
}
}

function toValue(fieldType: string, value: any): DocumentFieldValue | null {
switch (typeof value) {
case 'string':
case 'number': // This handles proto enums as well.
return value;
case 'object':
return toDocumentData(value);
return toObjectValue(fieldType, value);
default:
console.debug(`Unsupported proto field type ${typeof value}`);
return null;
Expand Down

0 comments on commit c248e1f

Please sign in to comment.