Skip to content

Commit 263804b

Browse files
authored
fix: Make aggregation query requests run properly inside a transaction (#1166)
* Add a test that ensures the read is txn read When doing a readOnly transaction, the code should do reads from a consistent snapshot so that if a write is done mid-transaction then that doesn’t affect the read value. * Code change that lets test pass This code change ensures transactions that run aggregate queries actually make the request as an aggregate query. * Add a test to verify run query results Verify run query results at a particular time so that we know what data we are working with for the rest of the aggregate query tests. * linting fix
1 parent a946c12 commit 263804b

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

src/request.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,12 @@ class DatastoreRequest {
10001000
reqOpts.transaction = this.id;
10011001
}
10021002

1003-
if (isTransaction && (method === 'lookup' || method === 'runQuery')) {
1003+
if (
1004+
isTransaction &&
1005+
(method === 'lookup' ||
1006+
method === 'runQuery' ||
1007+
method === 'runAggregationQuery')
1008+
) {
10041009
if (reqOpts.readOptions && reqOpts.readOptions.readConsistency) {
10051010
throw new Error(
10061011
'Read consistency cannot be specified in a transaction.'

system-test/datastore.ts

+45-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {readFileSync} from 'fs';
1717
import * as path from 'path';
1818
import {after, before, describe, it} from 'mocha';
1919
import * as yaml from 'js-yaml';
20-
import {Datastore, DatastoreOptions, Index} from '../src';
20+
import {Datastore, DatastoreOptions, Index, Transaction} from '../src';
2121
import {google} from '../protos/protos';
2222
import {Storage} from '@google-cloud/storage';
2323
import {AggregateField} from '../src/aggregate';
@@ -1857,6 +1857,16 @@ async.each(
18571857
});
18581858

18591859
describe('aggregate query within a transaction', async () => {
1860+
it('should run a query and return the results', async () => {
1861+
// Add a test here to verify what the data is at this time.
1862+
// This will be a valuable reference for tests in this describe block.
1863+
const query = datastore.createQuery('Company');
1864+
const [results] = await datastore.runQuery(query);
1865+
assert.deepStrictEqual(
1866+
results.map(result => result.rating),
1867+
[100, 100]
1868+
);
1869+
});
18601870
it('should aggregate query within a count transaction', async () => {
18611871
const transaction = datastore.transaction();
18621872
await transaction.run();
@@ -1914,6 +1924,40 @@ async.each(
19141924
assert.deepStrictEqual(result, [{'average rating': 100}]);
19151925
await transaction.commit();
19161926
});
1927+
it('readOnly transaction should see consistent snapshot of database', async () => {
1928+
async function getResults(transaction: Transaction) {
1929+
const query = transaction.createQuery('Company');
1930+
const aggregateQuery = transaction
1931+
.createAggregationQuery(query)
1932+
.count('total');
1933+
let result;
1934+
try {
1935+
[result] = await aggregateQuery.run();
1936+
} catch (e) {
1937+
await transaction.rollback();
1938+
assert.fail(
1939+
'The aggregation query run should have been successful'
1940+
);
1941+
}
1942+
return result;
1943+
}
1944+
const key = datastore.key(['Company', 'Google']);
1945+
const transaction = datastore.transaction({readOnly: true});
1946+
await transaction.run();
1947+
const results = await getResults(transaction);
1948+
assert.deepStrictEqual(results, [{total: 2}]);
1949+
await datastore.save([
1950+
{
1951+
key,
1952+
data: {
1953+
rating: 100,
1954+
},
1955+
},
1956+
]);
1957+
const resultsAgain = await getResults(transaction);
1958+
assert.deepStrictEqual(resultsAgain, [{total: 2}]);
1959+
await transaction.commit();
1960+
});
19171961
});
19181962

19191963
it('should read in a readOnly transaction', async () => {

0 commit comments

Comments
 (0)