Skip to content

Commit 508ba66

Browse files
authored
Merge branch 'main' into yvonne/timestamp-expressions
2 parents a34eab9 + 5395e29 commit 508ba66

31 files changed

Lines changed: 461 additions & 38 deletions

File tree

.DS_Store

6 KB
Binary file not shown.

.release-please-manifest.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@
108108
"packages/google-cloud-geminidataanalytics": "0.6.0",
109109
"packages/google-cloud-gkebackup": "2.2.1",
110110
"packages/google-cloud-gkeconnect-gateway": "5.2.1",
111-
"packages/google-cloud-gkehub": "6.3.1",
111+
"packages/google-cloud-gkehub": "6.4.0",
112112
"packages/google-cloud-gkemulticloud": "2.3.0",
113113
"packages/google-cloud-gkerecommender": "0.1.0",
114114
"packages/google-cloud-gsuiteaddons": "2.2.1",
115115
"packages/google-cloud-hypercomputecluster": "0.2.0",
116-
"packages/google-cloud-iap": "4.3.1",
116+
"packages/google-cloud-iap": "4.4.0",
117117
"packages/google-cloud-ids": "4.2.1",
118118
"packages/google-cloud-iot": "5.2.1",
119119
"packages/google-cloud-kms": "5.4.0",
@@ -167,7 +167,7 @@
167167
"packages/google-cloud-securesourcemanager": "0.8.1",
168168
"packages/google-cloud-security-privateca": "7.0.1",
169169
"packages/google-cloud-security-publicca": "2.2.1",
170-
"packages/google-cloud-securitycenter": "9.2.1",
170+
"packages/google-cloud-securitycenter": "9.3.0",
171171
"packages/google-cloud-securitycentermanagement": "0.7.1",
172172
"packages/google-cloud-servicedirectory": "6.1.1",
173173
"packages/google-cloud-servicehealth": "0.7.1",
@@ -183,7 +183,7 @@
183183
"packages/google-cloud-texttospeech": "6.4.0",
184184
"packages/google-cloud-tpu": "4.1.1",
185185
"packages/google-cloud-translate": "9.3.0",
186-
"packages/google-cloud-vectorsearch": "0.4.0",
186+
"packages/google-cloud-vectorsearch": "0.5.0",
187187
"packages/google-cloud-video-livestream": "2.2.1",
188188
"packages/google-cloud-video-stitcher": "3.2.1",
189189
"packages/google-cloud-video-transcoder": "4.4.1",
@@ -212,13 +212,13 @@
212212
"packages/google-maps-fleetengine": "0.8.1",
213213
"packages/google-maps-fleetengine-delivery": "0.6.1",
214214
"packages/google-maps-mapsplatformdatasets": "3.1.1",
215-
"packages/google-maps-places": "2.3.0",
215+
"packages/google-maps-places": "2.4.0",
216216
"packages/google-maps-routeoptimization": "0.6.0",
217-
"packages/google-maps-routing": "2.1.1",
217+
"packages/google-maps-routing": "2.2.0",
218218
"packages/google-maps-solar": "0.5.1",
219219
"packages/google-marketingplatform-admin": "0.4.0",
220220
"packages/google-monitoring-dashboard": "4.1.1",
221-
"packages/google-privacy-dlp": "6.5.0",
221+
"packages/google-privacy-dlp": "6.6.0",
222222
"packages/google-shopping-css": "0.11.0",
223223
"packages/google-shopping-merchant-accounts": "3.2.0",
224224
"packages/google-shopping-merchant-conversions": "0.7.1",

changelog.json

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,125 @@
11
{
22
"repository": "googleapis/google-cloud-node",
33
"entries": [
4+
{
5+
"changes": [
6+
{
7+
"type": "feat",
8+
"sha": "1f6f8cc33f811631b58007cc0645b476e65f8e26",
9+
"message": "[dlp] added support for detecting key-value pairs in document metadata",
10+
"issues": [
11+
"7822"
12+
]
13+
}
14+
],
15+
"version": "6.6.0",
16+
"language": "JAVASCRIPT",
17+
"artifactName": "@google-cloud/dlp",
18+
"id": "10ea7e1e-bd9a-4379-a56b-a0c47b841d58",
19+
"createTime": "2026-03-19T18:18:35.904Z"
20+
},
21+
{
22+
"changes": [
23+
{
24+
"type": "feat",
25+
"sha": "b906b3ac62ee0513392d62defc7d168966c989f3",
26+
"message": "[routing] add a new Waypoint source to accept a token that identifies a Navigation Point obtained from the `SearchDestinations` method of the Geocoding API",
27+
"issues": [
28+
"7531"
29+
]
30+
}
31+
],
32+
"version": "2.2.0",
33+
"language": "JAVASCRIPT",
34+
"artifactName": "@googlemaps/routing",
35+
"id": "44c3e2c6-1106-454f-9530-892c47bf1f87",
36+
"createTime": "2026-03-19T18:18:35.883Z"
37+
},
38+
{
39+
"changes": [
40+
{
41+
"type": "feat",
42+
"sha": "bbaf91884b006918b1235edb483e5ac7ed09442b",
43+
"message": "[places] add a new business status `FUTURE_OPENING` for places,",
44+
"issues": [
45+
"7821"
46+
]
47+
}
48+
],
49+
"version": "2.4.0",
50+
"language": "JAVASCRIPT",
51+
"artifactName": "@googlemaps/places",
52+
"id": "56058c47-372c-46c4-b917-379aee9ccc75",
53+
"createTime": "2026-03-19T18:18:35.850Z"
54+
},
55+
{
56+
"changes": [
57+
{
58+
"type": "feat",
59+
"sha": "451de89cdd525b8aac424fc30ead047246ec521b",
60+
"message": "[vectorsearch] Mark Vector Search v1 API as GA",
61+
"issues": [
62+
"7610"
63+
]
64+
}
65+
],
66+
"version": "0.5.0",
67+
"language": "JAVASCRIPT",
68+
"artifactName": "@google-cloud/vectorsearch",
69+
"id": "744c0026-d1d8-4b0a-a76c-48c0247a8f4b",
70+
"createTime": "2026-03-19T18:18:35.823Z"
71+
},
72+
{
73+
"changes": [
74+
{
75+
"type": "feat",
76+
"sha": "694f8f92608fc1b4afbf7c71ecce90341fea5908",
77+
"message": "[securitycenter] Support Chokepoint and external exposure in findings Proto",
78+
"issues": [
79+
"7638"
80+
]
81+
}
82+
],
83+
"version": "9.3.0",
84+
"language": "JAVASCRIPT",
85+
"artifactName": "@google-cloud/security-center",
86+
"id": "67f7ff53-1786-4e92-9319-99b9f6f32744",
87+
"createTime": "2026-03-19T18:18:35.792Z"
88+
},
89+
{
90+
"changes": [
91+
{
92+
"type": "feat",
93+
"sha": "0012a46efa30c86cf8a88a88d3c4077bbbfe670c",
94+
"message": "[iap] add oauth fields for IapSettings",
95+
"issues": [
96+
"7613"
97+
]
98+
}
99+
],
100+
"version": "4.4.0",
101+
"language": "JAVASCRIPT",
102+
"artifactName": "@google-cloud/iap",
103+
"id": "bfbf2189-c8db-4d8e-b124-8d9af2b8c663",
104+
"createTime": "2026-03-19T18:18:35.759Z"
105+
},
106+
{
107+
"changes": [
108+
{
109+
"type": "feat",
110+
"sha": "9de14388ef6e9919bb75de88d63cecb1c9a9a629",
111+
"message": "[gkehub] A new field `kubernetes_api_server_version` is added to message `.google.cloud.gkehub.configmanagement.v1beta.MembershipState`",
112+
"issues": [
113+
"7534"
114+
]
115+
}
116+
],
117+
"version": "6.4.0",
118+
"language": "JAVASCRIPT",
119+
"artifactName": "@google-cloud/gke-hub",
120+
"id": "8da5cdb7-0d1e-4af6-ab15-3887074c8a71",
121+
"createTime": "2026-03-19T18:18:35.725Z"
122+
},
4123
{
5124
"changes": [
6125
{
@@ -68999,5 +69118,5 @@
6899969118
"createTime": "2023-01-28T04:18:24.718Z"
6900069119
}
6900169120
],
69002-
"updateTime": "2026-03-18T20:59:46.364Z"
69121+
"updateTime": "2026-03-19T18:18:35.904Z"
6900369122
}

handwritten/firestore/dev/src/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,13 @@ export class Firestore implements firestore.Firestore {
783783
validateBoolean('settings.ssl', settings.ssl);
784784
}
785785

786+
if (settings.alwaysUseImplicitOrderBy !== undefined) {
787+
validateBoolean(
788+
'settings.alwaysUseImplicitOrderBy',
789+
settings.alwaysUseImplicitOrderBy,
790+
);
791+
}
792+
786793
if (settings.maxIdleChannels !== undefined) {
787794
validateInteger('settings.maxIdleChannels', settings.maxIdleChannels, {
788795
minValue: 0,
@@ -845,6 +852,14 @@ export class Firestore implements firestore.Firestore {
845852
return this._databaseId || DEFAULT_DATABASE_ID;
846853
}
847854

855+
/**
856+
* Whether to always use implicit order by clauses.
857+
* @internal
858+
*/
859+
get alwaysUseImplicitOrderBy(): boolean {
860+
return this._settings.alwaysUseImplicitOrderBy ?? false;
861+
}
862+
848863
/**
849864
* Returns the root path of the database. Validates that
850865
* `initializeIfNeeded()` was called before.

handwritten/firestore/dev/src/reference/query.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,7 @@ export class Query<
14751475
toProto(
14761476
transactionOrReadTime?: Uint8Array | Timestamp | api.ITransactionOptions,
14771477
explainOptions?: firestore.ExplainOptions,
1478+
forceImplicitOrderBy?: boolean,
14781479
): api.IRunQueryRequest {
14791480
const projectId = this.firestore.projectId;
14801481
const databaseId = this.firestore.databaseId;
@@ -1483,18 +1484,18 @@ export class Query<
14831484
databaseId,
14841485
);
14851486

1486-
const structuredQuery = this.toStructuredQuery();
1487+
const structuredQuery = this.toStructuredQuery(forceImplicitOrderBy);
14871488

14881489
// For limitToLast queries, the structured query has to be translated to a version with
14891490
// reversed ordered, and flipped startAt/endAt to work properly.
14901491
if (this._queryOptions.limitType === LimitType.Last) {
1491-
if (!this._queryOptions.hasFieldOrders()) {
1492-
throw new Error(
1493-
'limitToLast() queries require specifying at least one orderBy() clause.',
1494-
);
1495-
}
1492+
const forceImplicit =
1493+
forceImplicitOrderBy || this._firestore.alwaysUseImplicitOrderBy;
1494+
const fieldOrders = forceImplicit
1495+
? this.createImplicitOrderBy()
1496+
: this._queryOptions.fieldOrders;
14961497

1497-
structuredQuery.orderBy = this._queryOptions.fieldOrders!.map(order => {
1498+
structuredQuery.orderBy = fieldOrders.map(order => {
14981499
// Flip the orderBy directions since we want the last results
14991500
const dir =
15001501
order.direction === 'DESCENDING' ? 'ASCENDING' : 'DESCENDING';
@@ -1564,7 +1565,9 @@ export class Query<
15641565
return bundledQuery;
15651566
}
15661567

1567-
private toStructuredQuery(): api.IStructuredQuery {
1568+
private toStructuredQuery(
1569+
forceImplicitOrderBy?: boolean,
1570+
): api.IStructuredQuery {
15681571
const structuredQuery: api.IStructuredQuery = {
15691572
from: [{}],
15701573
};
@@ -1586,9 +1589,19 @@ export class Query<
15861589
).toProto();
15871590
}
15881591

1589-
if (this._queryOptions.hasFieldOrders()) {
1590-
structuredQuery.orderBy = this._queryOptions.fieldOrders.map(o =>
1591-
o.toProto(),
1592+
// orders
1593+
const forceImplicit =
1594+
forceImplicitOrderBy || this._firestore.alwaysUseImplicitOrderBy;
1595+
let fieldOrders = this._queryOptions.fieldOrders;
1596+
if (forceImplicit) {
1597+
fieldOrders = this.createImplicitOrderBy();
1598+
}
1599+
1600+
if (fieldOrders.length > 0) {
1601+
structuredQuery.orderBy = fieldOrders.map(o => o.toProto());
1602+
} else if (this._queryOptions.limitType === LimitType.Last) {
1603+
throw new Error(
1604+
'limitToLast() queries require specifying at least one orderBy() clause.',
15921605
);
15931606
}
15941607

handwritten/firestore/dev/src/watch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ export class QueryWatch<
941941
}
942942

943943
getTarget(resumeToken?: Uint8Array): google.firestore.v1.ITarget {
944-
const query = this.query.toProto();
944+
const query = this.query.toProto(undefined, undefined, true);
945945
return {query, targetId: WATCH_TARGET_ID, resumeToken};
946946
}
947947
}

handwritten/firestore/dev/system-test/query.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,5 +2291,55 @@ describe.skipClassic('Query and Pipeline Compare - Enterprise DB', () => {
22912291
expectDocs(await compareQueryAndPipeline(query), 'doc2', 'doc3', 'doc4');
22922292
expectDocs(await queryWithCursor.get(), 'doc2', 'doc3', 'doc4');
22932293
});
2294+
2295+
it('alwaysUseImplicitOrderBy returns same results', async () => {
2296+
const collection = getTestRoot();
2297+
const docs = {
2298+
doc01: {sort: 1},
2299+
doc02: {sort: 2},
2300+
doc03: {sort: 3},
2301+
doc04: {sort: 4},
2302+
doc05: {sort: 5},
2303+
doc06: {sort: 6},
2304+
doc07: {sort: 7},
2305+
doc08: {sort: 8},
2306+
doc09: {sort: 9},
2307+
doc10: {sort: 10},
2308+
};
2309+
2310+
for (const [id, data] of Object.entries(docs)) {
2311+
await collection.doc(id).set(data);
2312+
}
2313+
2314+
const expectedOrder = [
2315+
'doc02',
2316+
'doc03',
2317+
'doc04',
2318+
'doc05',
2319+
'doc06',
2320+
'doc07',
2321+
'doc08',
2322+
'doc09',
2323+
'doc10',
2324+
];
2325+
2326+
// TODO: This test should run against both standard and enterprise
2327+
// and verify the results respectively
2328+
// const originalQuery = collection.where('sort', '>', 1);
2329+
// const originalSnapshot = await originalQuery.get();
2330+
// const originalResult = originalSnapshot.docs.map(d => d.id);
2331+
2332+
const modifiedFirestore = new Firestore({
2333+
...firestore.settings,
2334+
alwaysUseImplicitOrderBy: true,
2335+
});
2336+
const modifiedCollection = modifiedFirestore.collection(collection.id);
2337+
const query = modifiedCollection.where('sort', '>', 1);
2338+
const snapshot = await query.get();
2339+
const result = snapshot.docs.map(d => d.id);
2340+
2341+
// since alwaysUseImplicitOrderBy is true, we expect strict ordering.
2342+
expect(result).to.deep.equal(expectedOrder);
2343+
});
22942344
});
22952345
});

0 commit comments

Comments
 (0)