Skip to content

Commit 9a45ec8

Browse files
ehsannasgcf-owl-bot[bot]MarkDuckworth
authored
feat: Query Profile (#2014)
* Add QueryMode protos. * WIP: Query profiling APIs. * Use generic type. * WIP WIP. * WIP WIP WIP. * Update integration tests. * clean up. * lint. * Fix: Do not re-use _stream(). * Address more feedback. * introduce QueryPlan class to make it possible to add node-level info in future. * fix lint errors. * Revert host setting. * undo manual proto updates. * Update the public APIs to v2. * Reuse existing _stream methods. * Introduce ExplainMetrics and PlanSummary. * Update tests. * Manually import query profile protos. * WIP: Update impl and tests with new protos. * WIP (2): Update impl and tests with new protos. * WIP (3): Update impl and tests with new protos. * WIP (4): Update impl and tests with new protos. * Add test for explainStream. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Remove bytesReturned from the API. * minor improvements. * minor improvements. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * improve documentation. * Fix unit test failure. * minor improvements. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * explain options should be optional. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Address feedback. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com> Co-authored-by: Mark Duckworth <[email protected]>
1 parent c65cef0 commit 9a45ec8

File tree

9 files changed

+997
-57
lines changed

9 files changed

+997
-57
lines changed

dev/src/aggregate.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
/**
2-
* @license
3-
* Copyright 2023 Google LLC
1+
/*!
2+
* Copyright 2023 Google LLC. All Rights Reserved.
43
*
54
* Licensed under the Apache License, Version 2.0 (the "License");
65
* you may not use this file except in compliance with the License.
76
* You may obtain a copy of the License at
87
*
9-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
109
*
1110
* Unless required by applicable law or agreed to in writing, software
1211
* distributed under the License is distributed on an "AS IS" BASIS,

dev/src/convert.ts

+41
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,47 @@ export function detectValueType(proto: ProtobufJsValue): string {
161161
return detectedValues[0];
162162
}
163163

164+
/**
165+
* Detects the value kind from a Proto3 JSON `google.protobuf.Value` proto.
166+
*
167+
* @private
168+
* @internal
169+
* @param proto The `firestore.v1.Value` proto.
170+
* @return The string value for 'valueType'.
171+
*/
172+
export function detectGoogleProtobufValueType(
173+
proto: google.protobuf.IValue
174+
): string {
175+
const detectedValues: string[] = [];
176+
177+
if (proto.nullValue !== undefined) {
178+
detectedValues.push('nullValue');
179+
}
180+
if (proto.numberValue !== undefined) {
181+
detectedValues.push('numberValue');
182+
}
183+
if (proto.stringValue !== undefined) {
184+
detectedValues.push('stringValue');
185+
}
186+
if (proto.boolValue !== undefined) {
187+
detectedValues.push('boolValue');
188+
}
189+
if (proto.structValue !== undefined) {
190+
detectedValues.push('structValue');
191+
}
192+
if (proto.listValue !== undefined) {
193+
detectedValues.push('listValue');
194+
}
195+
196+
if (detectedValues.length !== 1) {
197+
throw new Error(
198+
`Unable to infer type value from '${JSON.stringify(proto)}'.`
199+
);
200+
}
201+
202+
return detectedValues[0];
203+
}
204+
164205
/**
165206
* Converts a `firestore.v1.Value` in Proto3 JSON encoding into the
166207
* Protobuf JS format expected by this client.

dev/src/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ export type {
114114
AggregateSpec,
115115
AggregateType,
116116
} from './aggregate';
117+
export type {
118+
PlanSummary,
119+
ExecutionStats,
120+
ExplainMetrics,
121+
ExplainResults,
122+
} from './query-profile';
117123

118124
const libVersion = require('../../package.json').version;
119125
setLibVersion(libVersion);

dev/src/query-profile.ts

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*!
2+
* Copyright 2024 Google LLC. All Rights Reserved.
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+
* http://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+
import * as firestore from '@google-cloud/firestore';
18+
import {google} from '../protos/firestore_v1_proto_api';
19+
import {Serializer} from './serializer';
20+
import IPlanSummary = google.firestore.v1.IPlanSummary;
21+
import IExecutionStats = google.firestore.v1.IExecutionStats;
22+
import IExplainMetrics = google.firestore.v1.IExplainMetrics;
23+
24+
/**
25+
* PlanSummary contains information about the planning stage of a query.
26+
*
27+
* @class PlanSummary
28+
*/
29+
export class PlanSummary implements firestore.PlanSummary {
30+
/**
31+
* @private
32+
* @internal
33+
*/
34+
constructor(readonly indexesUsed: Record<string, unknown>[]) {}
35+
36+
/**
37+
* @private
38+
* @internal
39+
*/
40+
static _fromProto(
41+
plan: IPlanSummary | null | undefined,
42+
serializer: Serializer
43+
): PlanSummary {
44+
const indexes: Record<string, unknown>[] = [];
45+
if (plan && plan.indexesUsed) {
46+
for (const index of plan.indexesUsed) {
47+
indexes.push(serializer.decodeGoogleProtobufStruct(index));
48+
}
49+
}
50+
return new PlanSummary(indexes);
51+
}
52+
}
53+
54+
/**
55+
* ExecutionStats contains information about the execution of a query.
56+
*
57+
* @class ExecutionStats
58+
*/
59+
export class ExecutionStats implements firestore.ExecutionStats {
60+
/**
61+
* @private
62+
* @internal
63+
*/
64+
constructor(
65+
readonly resultsReturned: number,
66+
readonly executionDuration: firestore.Duration,
67+
readonly readOperations: number,
68+
readonly debugStats: Record<string, unknown>
69+
) {}
70+
71+
/**
72+
* @private
73+
* @internal
74+
*/
75+
static _fromProto(
76+
stats: IExecutionStats | null | undefined,
77+
serializer: Serializer
78+
): ExecutionStats | null {
79+
if (stats) {
80+
return new ExecutionStats(
81+
Number(stats.resultsReturned),
82+
{
83+
seconds: Number(stats.executionDuration?.seconds),
84+
nanoseconds: Number(stats.executionDuration?.nanos),
85+
},
86+
Number(stats.readOperations),
87+
serializer.decodeGoogleProtobufStruct(stats.debugStats)
88+
);
89+
}
90+
return null;
91+
}
92+
}
93+
94+
/**
95+
* ExplainMetrics contains information about planning and execution of a query.
96+
*
97+
* @class ExplainMetrics
98+
*/
99+
export class ExplainMetrics implements firestore.ExplainMetrics {
100+
/**
101+
* @private
102+
* @internal
103+
*/
104+
constructor(
105+
readonly planSummary: PlanSummary,
106+
readonly executionStats: ExecutionStats | null
107+
) {}
108+
109+
/**
110+
* @private
111+
* @internal
112+
*/
113+
static _fromProto(
114+
metrics: IExplainMetrics,
115+
serializer: Serializer
116+
): ExplainMetrics {
117+
return new ExplainMetrics(
118+
PlanSummary._fromProto(metrics.planSummary, serializer),
119+
ExecutionStats._fromProto(metrics.executionStats, serializer)
120+
);
121+
}
122+
}
123+
124+
/**
125+
* ExplainResults contains information about planning, execution, and results
126+
* of a query.
127+
*
128+
* @class ExplainResults
129+
*/
130+
export class ExplainResults<T> implements firestore.ExplainResults<T> {
131+
/**
132+
* @private
133+
* @internal
134+
*/
135+
constructor(
136+
readonly metrics: ExplainMetrics,
137+
readonly snapshot: T | null
138+
) {}
139+
}

0 commit comments

Comments
 (0)