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 <1124037+MarkDuckworth@users.noreply.github.com>
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

Lines changed: 3 additions & 4 deletions
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

Lines changed: 41 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 139 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy