Skip to content

Commit dc39f06

Browse files
committed
resolve comments
1 parent 189085e commit dc39f06

File tree

4 files changed

+79
-139
lines changed

4 files changed

+79
-139
lines changed

packages/firestore/src/lite-api/aggregate.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,21 @@
1616
*/
1717

1818
import { invokeRunAggregationQueryRpc } from '../remote/datastore';
19+
import { hardAssert } from '../util/assert';
1920
import { cast } from '../util/input_validation';
2021
import { getDatastore } from './components';
2122
import { Firestore } from './database';
22-
import { DocumentData, Query, queryEqual } from './reference';
23+
import { Query, queryEqual } from './reference';
2324
import { LiteUserDataWriter } from './reference_impl';
2425

2526
/**
26-
* A {@code AggregateQuery} computes some aggregation statistics from the result set of a base
27-
* {@link Query}.
28-
*
29-
* <p><b>Subclassing Note</b>: Cloud Firestore classes are not meant to be subclassed except for use
30-
* in test mocks. Subclassing is not supported in production code and new SDK releases may break
31-
* code that does so.
27+
* A `AggregateQuery` computes some aggregation statistics from the result set of
28+
* a base `Query`.
3229
*/
3330
export class AggregateQuery {
3431
readonly type = 'AggregateQuery';
3532
/**
36-
* The query on which you called {@link countQuery} in order to get this
37-
* `AggregateQuery`.
33+
* The query on which you called `countQuery` in order to get this `AggregateQuery`.
3834
* Query type is set to unknown to avoid error caused by query type converter.
3935
* might change it back to T after testing if the error do exist or not
4036
*/
@@ -44,15 +40,10 @@ export class AggregateQuery {
4440
constructor(query: Query<unknown>) {
4541
this.query = query;
4642
}
47-
4843
}
4944

5045
/**
51-
* A {@code AggregateQuerySnapshot} contains results of a {@link AggregateQuery}.
52-
*
53-
* <p><b>Subclassing Note</b>: Cloud Firestore classes are not meant to be subclassed except for use
54-
* in test mocks. Subclassing is not supported in production code and new SDK releases may break
55-
* code that does so.
46+
* A `AggregateQuerySnapshot` contains results of a `AggregateQuery`.
5647
*/
5748
export class AggregateQuerySnapshot {
5849
readonly type = 'AggregateQuerySnapshot';
@@ -73,15 +64,12 @@ export class AggregateQuerySnapshot {
7364
}
7465

7566
/**
76-
* Creates an {@link AggregateQuery} counting the number of documents matching this query.
67+
* Creates an `AggregateQuery` counting the number of documents matching this query.
7768
*
78-
* @return An {@link AggregateQuery} object that can be used to count the number of documents in
69+
* @return An `AggregateQuery` object that can be used to count the number of documents in
7970
* the result set of this query.
8071
*/
8172
export function countQuery(query: Query<unknown>): AggregateQuery {
82-
/**
83-
* TODO(mila): add the "count" aggregateField to the params after the AggregateQuery is updated.
84-
*/
8573
return new AggregateQuery(query);
8674
}
8775

@@ -95,24 +83,18 @@ export function getAggregateFromServerDirect(
9583
return invokeRunAggregationQueryRpc(datastore, aggregateQuery).then(
9684
result => {
9785
const aggregationFields = new Map<string, any>();
98-
/**
99-
* while getting aggregation fields from server direct, it should have only
100-
* one RunAggregationQueryResponse returned.
101-
* But we used streaming rpc here, so we will have an array of
102-
* (one, or possibly more) RunAggregationQueryResponse. For this specific
103-
* function, we get the first RunAggregationQueryResponse only.
104-
*/
86+
10587
for (const [key, value] of Object.entries(result[0])) {
10688
aggregationFields.set(key, userDataWriter.convertValue(value));
10789
}
90+
const countField = aggregationFields.get('count_alias');
91+
92+
hardAssert(
93+
countField !== undefined && typeof countField === 'number',
94+
'Count aggeragte field is invalid. countField:' + countField
95+
);
10896
return Promise.resolve(
109-
new AggregateQuerySnapshot(
110-
aggregateQuery,
111-
//return the count value , or null if count is undfined
112-
aggregationFields.has('count_alias')
113-
? aggregationFields.get('count_alias')
114-
: null
115-
)
97+
new AggregateQuerySnapshot(aggregateQuery, countField!)
11698
);
11799
}
118100
);

packages/firestore/src/remote/datastore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export async function invokeRunAggregationQueryRpc(
254254
});
255255
return (
256256
response
257-
// Omit RunQueryResponses that only contain readTimes.
257+
// Omit RunAggregationQueryResponse that only contain readTimes.
258258
.filter(proto => !!proto.result && !!proto.result.aggregateFields)
259259
.map(proto => proto.result!.aggregateFields!)
260260
);

packages/firestore/src/remote/serializer.ts

Lines changed: 11 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ import {
7777
OrderDirection as ProtoOrderDirection,
7878
Precondition as ProtoPrecondition,
7979
QueryTarget as ProtoQueryTarget,
80+
RunAggregationQueryRequest as ProtoRunAggregationQueryRequest,
8081
Status as ProtoStatus,
8182
Target as ProtoTarget,
8283
TargetChangeTargetChangeType as ProtoTargetChangeTargetChangeType,
8384
Timestamp as ProtoTimestamp,
8485
Write as ProtoWrite,
85-
WriteResult as ProtoWriteResult,
86-
RunAggregationQueryRequest as ProtoRunAggregationQueryRequest
86+
WriteResult as ProtoWriteResult
8787
} from '../protos/firestore_proto_api';
8888
import { debugAssert, fail, hardAssert } from '../util/assert';
8989
import { ByteString } from '../util/byte_string';
@@ -857,62 +857,20 @@ export function toRunAggregationQueryRequest(
857857
serializer: JsonProtoSerializer,
858858
target: Target
859859
): ProtoRunAggregationQueryRequest {
860-
// Dissect the path into parent, collectionId, and optional key filter.
861-
const result: ProtoRunAggregationQueryRequest = {
860+
const queryTarget = toQueryTarget(serializer, target);
861+
862+
return {
862863
structuredAggregationQuery: {
863864
aggregations: [
864-
//TODO: dynamically add the aggregate fields in future development
865865
{
866-
count: {
867-
},
868-
alias:"count_alias"
869-
},
866+
count: {},
867+
alias: 'count_alias'
868+
}
870869
],
871-
structuredQuery: {}
872-
}
870+
structuredQuery: queryTarget.structuredQuery
871+
},
872+
parent: queryTarget.parent
873873
};
874-
const path = target.path;
875-
if (target.collectionGroup !== null) {
876-
debugAssert(
877-
path.length % 2 === 0,
878-
'Collection Group queries should be within a document path or root.'
879-
);
880-
result.parent = toQueryPath(serializer, path);
881-
result.structuredAggregationQuery!.structuredQuery!.from = [
882-
{
883-
collectionId: target.collectionGroup,
884-
allDescendants: true
885-
}
886-
];
887-
} else {
888-
debugAssert(
889-
path.length % 2 !== 0,
890-
'Document queries with filters are not supported.'
891-
);
892-
result.parent = toQueryPath(serializer, path.popLast());
893-
result.structuredAggregationQuery!.structuredQuery!.from = [
894-
{ collectionId: path.lastSegment() }
895-
];
896-
}
897-
898-
const where = toFilter(target.filters);
899-
if (where) {
900-
result.structuredAggregationQuery!.structuredQuery!.where = where;
901-
}
902-
/** QUESTION: in count query, do we need to add OrderBy? Number of
903-
* documents shouldn't be impacted by how the documents are ordered.
904-
*/
905-
const orderBy = toOrder(target.orderBy);
906-
if (orderBy) {
907-
result.structuredAggregationQuery!.structuredQuery!.orderBy = orderBy;
908-
}
909-
910-
const limit = toInt32Proto(serializer, target.limit);
911-
if (limit !== null) {
912-
result.structuredAggregationQuery!.structuredQuery!.limit = limit;
913-
}
914-
915-
return result;
916874
}
917875

918876
export function convertQueryTargetToQuery(target: ProtoQueryTarget): Query {

packages/firestore/test/lite/integration.test.ts

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,118 +2069,118 @@ describe('countQuery()', () => {
20692069
{ key: 'c', value: 'Cooper' }
20702070
];
20712071

2072-
it('empty collection count equals to 0', () => {
2072+
it.only('AggregateQuery and AggregateQuerySnapshot inherits the original query', () => {
20732073
return withTestCollection(async coll => {
2074-
const countQuery_ = countQuery(query(coll));
2074+
const query_ = query(coll);
2075+
2076+
const countQuery_ = countQuery(query_);
20752077
expect(countQuery_.type).to.equal('AggregateQuery');
2078+
expect(countQuery_.query).to.equal(query_);
2079+
2080+
const snapshot = await getAggregateFromServerDirect(countQuery_);
2081+
expect(snapshot.query.query).to.equal(query_);
2082+
});
2083+
});
2084+
2085+
it.only('empty collection count equals to 0', () => {
2086+
return withTestCollection(async coll => {
2087+
const countQuery_ = countQuery(query(coll));
20762088

20772089
const snapshot = await getAggregateFromServerDirect(countQuery_);
20782090
expect(snapshot.getCount()).to.equal(0);
20792091
});
20802092
});
20812093

2082-
it('test collection count equals to 6', () => {
2094+
it.only('test collection count equals to 6', () => {
20832095
return withTestCollectionAndInitialData(testDocs, async collection => {
20842096
const countQuery_ = countQuery(query(collection));
20852097
const snapshot = await getAggregateFromServerDirect(countQuery_);
20862098
expect(snapshot.getCount()).to.equal(6);
20872099
});
20882100
});
20892101

2090-
it('test collection count with filter', () => {
2102+
it.only('test collection count with filter', () => {
20912103
return withTestCollectionAndInitialData(testDocs, async collection => {
20922104
const query_ = query(collection, where('key', '==', 'a'));
2093-
20942105
const countQuery_ = countQuery(query_);
20952106
const snapshot = await getAggregateFromServerDirect(countQuery_);
20962107
expect(snapshot.getCount()).to.equal(2);
20972108
});
20982109
});
20992110

2100-
it('test collection count with filter effected by small limit', () => {
2101-
// limit that is less that the actual count would work like count up_to.
2111+
it.only('test collection count with filter and a small limit size', () => {
21022112
return withTestCollectionAndInitialData(testDocs, async collection => {
21032113
const query_ = query(collection, where('key', '==', 'a'), limit(1));
2104-
21052114
const countQuery_ = countQuery(query_);
21062115
const snapshot = await getAggregateFromServerDirect(countQuery_);
21072116
expect(snapshot.getCount()).to.equal(1);
21082117
});
21092118
});
21102119

2111-
it('test collection count with filter not effected by large limit', () => {
2112-
//limit that is larger than actual count wouldn't impact the return value
2120+
it.only('test collection count with filter and a large limit size', () => {
21132121
return withTestCollectionAndInitialData(testDocs, async collection => {
21142122
const query_ = query(collection, where('key', '==', 'a'), limit(3));
2115-
21162123
const countQuery_ = countQuery(query_);
21172124
const snapshot = await getAggregateFromServerDirect(countQuery_);
21182125
expect(snapshot.getCount()).to.equal(2);
21192126
});
21202127
});
21212128

2122-
it('test collection count with converter on query', () => {
2123-
//testing out the converter impact on the AggregateQuery type
2129+
it.only('test collection count with converter on query', () => {
21242130
return withTestCollectionAndInitialData(testDocs, async collection => {
21252131
const query_ = query(collection, where('key', '==', 'a')).withConverter(
21262132
converter
21272133
);
2128-
21292134
const countQuery_ = countQuery(query_);
21302135
const snapshot = await getAggregateFromServerDirect(countQuery_);
21312136
expect(snapshot.getCount()).to.equal(2);
21322137
});
21332138
});
21342139

2135-
it('test collection count with converter on collection', () => {
2136-
//testing out the converter impact on the AggregateQuery type
2140+
it.only('aggregateQueryEqual returns true on same queries', () => {
21372141
return withTestCollectionAndInitialData(testDocs, async collection => {
2138-
const ref = collection.withConverter(converter);
2139-
const query_ = query(ref, where('key', '==', 'a'));
2140-
2141-
const countQuery_ = countQuery(query_);
2142-
const snapshot = await getAggregateFromServerDirect(countQuery_);
2143-
expect(snapshot.getCount()).to.equal(2);
2142+
const query1 = query(collection, where('key', '==', 'a'));
2143+
const query2 = query(collection, where('key', '==', 'a'));
2144+
const countQuery1 = countQuery(query1);
2145+
const countQuery2 = countQuery(query2);
2146+
expect(aggregateQueryEqual(countQuery1, countQuery2)).to.be.true;
21442147
});
21452148
});
21462149

2147-
it('aggregateQueryEqual returns true on same queries', () => {
2150+
it.only('aggregateQueryEqual returns false on different queries', () => {
21482151
return withTestCollectionAndInitialData(testDocs, async collection => {
2149-
const query_1 = query(collection, where('key', '==', 'a'));
2150-
const query_2 = query(collection, where('key', '==', 'a'));
2151-
2152-
const countQuery_1 = countQuery(query_1);
2153-
const countQuery_2 = countQuery(query_2);
2154-
expect(aggregateQueryEqual(countQuery_1, countQuery_2)).to.be.true;
2152+
const query1 = query(collection, where('key', '==', 'a'));
2153+
const query2 = query(collection, where('key', '!=', 'a'));
2154+
const countQuery1 = countQuery(query1);
2155+
const countQuery2 = countQuery(query2);
2156+
expect(aggregateQueryEqual(countQuery1, countQuery2)).to.be.false;
21552157
});
21562158
});
2157-
2158-
it('aggregateQueryEqual returns false on different queries', () => {
2159-
return withTestCollectionAndInitialData(testDocs, async collection => {
2160-
const query_1 = query(collection, where('key', '==', 'a'));
2161-
const query_2 = query(collection, where('key', '!=', 'a'));
21622159

2163-
const countQuery_1 = countQuery(query_1);
2164-
const countQuery_2 = countQuery(query_2);
2165-
expect(aggregateQueryEqual(countQuery_1, countQuery_2)).to.be.false;
2160+
it.only('aggregateQuerySnapshotEqual returns true on same queries', () => {
2161+
return withTestCollectionAndInitialData(testDocs, async collection => {
2162+
const query1 = query(collection, where('key', '==', 'a'));
2163+
const query2 = query(collection, where('key', '==', 'a'));
2164+
const countQuery1A = countQuery(query1);
2165+
const countQuery1B = countQuery(query1);
2166+
const countQuery2 = countQuery(query2);
2167+
const snapshot1A = await getAggregateFromServerDirect(countQuery1A);
2168+
const snapshot1B = await getAggregateFromServerDirect(countQuery1B);
2169+
const snapshot2 = await getAggregateFromServerDirect(countQuery2);
2170+
expect(aggregateQuerySnapshotEqual(snapshot1A, snapshot1B)).to.be.true;
2171+
expect(aggregateQuerySnapshotEqual(snapshot1A, snapshot2)).to.be.true;
21662172
});
21672173
});
21682174

2169-
it('aggregateQuerySnapshotEqual returns true on same queries', () => {
2175+
it.only('aggregateQuerySnapshotEqual returns false on different queries', () => {
21702176
return withTestCollectionAndInitialData(testDocs, async collection => {
2171-
const query_original = query(collection, where('key', '==', 'a'));
2172-
const query_copy = query(collection, where('key', '==', 'a'));
2173-
2174-
const countQuery_original_1 = countQuery(query_original);
2175-
const countQuery_original_2 = countQuery(query_original);
2176-
const countQuery_copy = countQuery(query_copy);
2177-
2178-
const snapshot_original_1 = await getAggregateFromServerDirect(countQuery_original_1);
2179-
const snapshot_original_2 = await getAggregateFromServerDirect(countQuery_original_2);
2180-
const snapshot_copy = await getAggregateFromServerDirect(countQuery_copy);
2181-
2182-
expect(aggregateQuerySnapshotEqual(snapshot_original_1, snapshot_original_2)).to.be.true;
2183-
expect(aggregateQuerySnapshotEqual(snapshot_original_1, snapshot_copy)).to.be.true;
2177+
const query1 = query(collection, where('key', '==', 'a'));
2178+
const query2 = query(collection, where('key', '==', 'b'));
2179+
const countQuery1 = countQuery(query1);
2180+
const countQuery2 = countQuery(query2);
2181+
const snapshot1 = await getAggregateFromServerDirect(countQuery1);
2182+
const snapshot2 = await getAggregateFromServerDirect(countQuery2);
2183+
expect(aggregateQuerySnapshotEqual(snapshot1, snapshot2)).to.be.false;
21842184
});
21852185
});
21862186
});

0 commit comments

Comments
 (0)