Skip to content

Commit fab5ef6

Browse files
Read Submissions from Firestore using new proto-based format (#1918)
Co-authored-by: Sufyan Abbasi <[email protected]>
1 parent e4903ba commit fab5ef6

17 files changed

+481
-312
lines changed

functions/src/common/datastore.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import * as functions from 'firebase-functions';
1818
import {firestore} from 'firebase-admin';
1919
import {DocumentData, GeoPoint, QuerySnapshot} from 'firebase-admin/firestore';
20+
import {FieldNumbers} from '@ground/lib/dist/proto-field-numbers';
2021

2122
/**
2223
*
@@ -119,7 +120,7 @@ export class Datastore {
119120
fetchSubmissionsByJobId(surveyId: string, jobId: string) {
120121
return this.db_
121122
.collection(submissions(surveyId))
122-
.where('jobId', '==', jobId)
123+
.where(FieldNumbers.Submission.job_id, '==', jobId)
123124
.get();
124125
}
125126

@@ -133,7 +134,7 @@ export class Datastore {
133134
): Promise<QuerySnapshot<DocumentData, DocumentData>> {
134135
return this.db_
135136
.collection(lois(surveyId))
136-
.where('jobId', '==', jobId)
137+
.where(FieldNumbers.LocationOfInterest.job_id, '==', jobId)
137138
.get();
138139
}
139140

@@ -150,7 +151,11 @@ export class Datastore {
150151
loiId: string
151152
): Promise<number> {
152153
const submissionsRef = this.db_.collection(submissions(surveyId));
153-
const submissionsForLoiQuery = submissionsRef.where('loiId', '==', loiId);
154+
const submissionsForLoiQuery = submissionsRef.where(
155+
FieldNumbers.Submission.loi_id,
156+
'==',
157+
loiId
158+
);
154159
const snapshot = await submissionsForLoiQuery.count().get();
155160
return snapshot.data().count;
156161
}

functions/src/on-write-submission.spec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import * as functions from './index';
2525
import {loi} from './common/datastore';
2626
import {Firestore} from 'firebase-admin/firestore';
2727
import {resetDatastore} from './common/context';
28+
import {FieldNumbers} from '@ground/lib';
2829

2930
const test = require('firebase-functions-test')();
3031

@@ -62,7 +63,7 @@ describe('onWriteSubmission()', () => {
6263
.and.returnValue({
6364
where: jasmine
6465
.createSpy('where')
65-
.withArgs('loiId', '==', loiId)
66+
.withArgs(FieldNumbers.Submission.loi_id, '==', loiId)
6667
.and.returnValue(newCountQuery(count)),
6768
} as any);
6869
}

lib/src/firestore-to-proto.ts

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ function toFieldValue(
118118
case 'bool':
119119
case 'double':
120120
return firestoreValue;
121+
case '.google.protobuf.Timestamp':
122+
return toMessageOrEnumValue(['google', 'protobuf'], 'Timestamp', firestoreValue);
121123
default:
122124
return toMessageOrEnumValue(messageTypePath, fieldType, firestoreValue);
123125
}

lib/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
export {toDocumentData} from './proto-to-firestore';
1818
export {toMessage} from './firestore-to-proto';
1919
export {deleteEmpty, isEmpty} from './obj-util';
20+
export {FieldNumbers} from './proto-field-numbers';

lib/src/proto-field-numbers.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright 2024 The Ground Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export const FieldNumbers = {
18+
LocationOfInterest: {
19+
job_id: '2',
20+
owner_id: '5',
21+
source: '9'
22+
},
23+
Submission: {
24+
loi_id: '2',
25+
job_id: '4',
26+
owner_id: '5'
27+
},
28+
Survey: {
29+
acl: '4',
30+
owner_id: '5'
31+
}
32+
};

package-lock.json

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build-all-and-test": "npm run build-all && npm run test",
1313
"watch": "npm run build -- --watch",
1414
"start": "npm run build && ng serve -c $npm_config_config",
15-
"build-and-start": "npm run build && npm run start",
15+
"build-and-start": "npm run build && npm run start",
1616
"build-all-and-start": "npm run build-all && npm run start",
1717
"pretest": "./pretest.sh",
1818
"test": "ng test",
@@ -50,6 +50,7 @@
5050
"functions": "^1.0.9",
5151
"hammerjs": "^2.0.8",
5252
"immutable": "^4.3.6",
53+
"long": "^5.2.3",
5354
"ngx-autosize-input": "^17",
5455
"ngx-color": "^9.0.0",
5556
"rxjs": "^7.5.7",

web/src/app/converters/firebase-data-converter.spec.ts

-130
Original file line numberDiff line numberDiff line change
@@ -14,141 +14,11 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {Timestamp} from '@angular/fire/firestore';
18-
import {List, Map} from 'immutable';
19-
20-
import {Job} from 'app/models/job.model';
2117
import {Role} from 'app/models/role.model';
22-
import {Submission} from 'app/models/submission/submission.model';
23-
import {
24-
Cardinality,
25-
MultipleChoice,
26-
} from 'app/models/task/multiple-choice.model';
27-
import {Option} from 'app/models/task/option.model';
28-
import {Task, TaskType} from 'app/models/task/task.model';
2918

3019
import {FirebaseDataConverter} from './firebase-data-converter';
3120

32-
class MockFirebaseData {
33-
static submission001 = {
34-
created: {
35-
clientTimestamp: undefined,
36-
serverTimestamp: undefined,
37-
user: {
38-
displayName: 'Creator',
39-
40-
id: 'creator001',
41-
},
42-
},
43-
lastModified: {
44-
clientTimestamp: undefined,
45-
serverTimestamp: undefined,
46-
user: {
47-
displayName: 'Modifier',
48-
49-
id: 'modifier001',
50-
},
51-
},
52-
loiId: 'loi001',
53-
jobId: 'job001',
54-
data: {
55-
task001: 'text result',
56-
task002: ['option001', 'option002'],
57-
task003: 123,
58-
task004: new Timestamp(1641533340, 0),
59-
task005: new Timestamp(1641534444, 0),
60-
},
61-
};
62-
}
63-
64-
class MockModel {
65-
static task001: Task = new Task(
66-
'task001',
67-
TaskType.TEXT,
68-
'Text Field',
69-
/*required=*/ true,
70-
0
71-
);
72-
73-
static task002: Task = new Task(
74-
'task002',
75-
TaskType.MULTIPLE_CHOICE,
76-
'Multiple Select',
77-
/*required=*/ true,
78-
1,
79-
new MultipleChoice(
80-
Cardinality.SELECT_MULTIPLE,
81-
List([
82-
new Option(
83-
'option001',
84-
'code001',
85-
'option 1',
86-
/* index= */
87-
0
88-
),
89-
new Option(
90-
'option002',
91-
'code002',
92-
'option 2',
93-
/* index= */
94-
0
95-
),
96-
])
97-
)
98-
);
99-
100-
static task003: Task = new Task(
101-
'task003',
102-
TaskType.NUMBER,
103-
'How many sloths are there?',
104-
/*required=*/ true,
105-
2
106-
);
107-
108-
static task004: Task = new Task(
109-
'task004',
110-
TaskType.DATE,
111-
'What is the current date?',
112-
/*required=*/ true,
113-
2
114-
);
115-
116-
static task005: Task = new Task(
117-
'task005',
118-
TaskType.TIME,
119-
'What time is it?',
120-
/*required=*/ true,
121-
2
122-
);
123-
124-
static job001: Job = new Job(
125-
/* id= */ 'job001',
126-
/* index= */ 0,
127-
'#ffffff',
128-
'Test job',
129-
Map({
130-
task001: MockModel.task001,
131-
task002: MockModel.task002,
132-
task003: MockModel.task003,
133-
task004: MockModel.task004,
134-
task005: MockModel.task005,
135-
})
136-
);
137-
}
138-
13921
describe('FirebaseDataConverter', () => {
140-
it('Submission converts back and forth without loosing data.', () => {
141-
expect(
142-
FirebaseDataConverter.submissionToJS(
143-
FirebaseDataConverter.toSubmission(
144-
MockModel.job001,
145-
'submission001',
146-
MockFirebaseData.submission001
147-
) as Submission
148-
)
149-
).toEqual(MockFirebaseData.submission001);
150-
});
151-
15222
describe('toRole()', () => {
15323
it('converts enums to strings', () => {
15424
expect(FirebaseDataConverter.toRoleId(Role.OWNER)).toEqual('OWNER');

0 commit comments

Comments
 (0)