tinybase icon indicating copy to clipboard operation
tinybase copied to clipboard

Query result during transaction will be blank if there's already a query with a similar "group" defined.

Open willhoney7 opened this issue 6 months ago • 3 comments

Describe the bug

In a pretty specific situation, a query result will return BLANK during a transaction. You can see it in the code below (and in the linked stackblitz).

To reproduce:

  • define a first query with a group keyword.
  • start a transaction
  • define another query (on the same table) with a group keyword (can be a different column!)
  • call getResultTable and see that it's blank
  • finish the transaction
  • call getResultTable and see that it does return a value

See the following code (and linked reproduction).

const store = createMergeableStore().setSchema(
	{
		records: {
			account: { type: 'string' },
			amount: { type: 'number' },
			decimals: { type: 'number' },
		},
	},
	{}
);
store.setTables({
	records: generateDummyData(),
});

const queries = createQueries(store);

queries.setQueryDefinition('budgetTotal', 'records', (keywords) => {
	keywords.select('account');
	keywords.select('amount');
	// if you comment out the group line here, the second query will work correctly.
	keywords.group('amount', 'avg');
});

if (enableTransaction) {
	store.startTransaction();
}

const queryId = `otherQuery`;
queries.setQueryDefinition(queryId, 'records', (keywords) => {
	keywords.select('amount');
	keywords.where('account', '1');
	// or if you remove group here, this query will work correctly.
	// also has issues if you group by a completely different column
	keywords.group('amount', 'sum');
});

console.log('first', JSON.stringify(queries.getResultTable(queryId))); // BLANK!
console.log('second', JSON.stringify(queries.getResultTable(queryId))); // BLANK!

if (enableTransaction) {
	store.finishTransaction();
	console.log(
		'after transaction',
		JSON.stringify(queries.getResultTable(queryId))
	);
}

Your Example Website or App

https://stackblitz.com/edit/vitejs-vite-jec8c4bm?file=src%2Fcounter.ts

Expected behavior

I would expect the query to return correct data, even mid-transaction.

Platform

  • OS: macOS
  • Browser: Brave
  • Version: 6.3

willhoney7 avatar Jul 08 '25 03:07 willhoney7

Off the top of my head, I think this is by design. A query (re-)executes when a transaction completes.

Otherwise, if there was a large number of batch updates wrapped in a single transaction, it would be updating all the reactive results along the way, probably slowing the transaction significantly.

WHat's the use-case where a new query is being configured inside a data-changing transaction?

jamesgpearce avatar Jul 09 '25 13:07 jamesgpearce

@jamesgpearce Hi! Thanks for the reply here.

The thing is that many queries do work when defined in the middle of a transaction. It's just this specific set of circumstances causes the query to be blank (a query already exists and so starting the transaction is pausing the listeners or however that works).

You pose a good question though, I don't know if I actually HAVE to define and run this query within a transaction. I've created some helper methods to basically get a query result at any time (it will define the query first if needed, then call getResultTable). So, sometimes in the middle of a big transaction, I'll want to define and execute a query and get some data which will influence the next steps of the transaction. I think for my use cases, however, I could get the data before the transaction. I can see situations where it could be nice to be able to define+run a query on the in-progress transaction data, but I don't know if this is really a hard requirement. At worst, you could split it into multiple transactions. I think it would be an acceptable limitation to know that you can't define a query within a transaction. It just caught me off guard because my other queries had been working.

So, if this is an easy fix, maybe it's worth it? If not, maybe just a docs update saying you can't define queries in a transaction?

willhoney7 avatar Jul 09 '25 14:07 willhoney7

Documentation is probably the way to go ("results may be possible but full behavior is undefined") though I'll look into why it is working in some cases!

jamesgpearce avatar Jul 09 '25 23:07 jamesgpearce