@@ -14,6 +14,7 @@ import predefinedSelections, {
1414import { DEFAULT_RETURN_NODE } from "./parseQuery" ;
1515import { DiscourseNode } from "./getDiscourseNodes" ;
1616import { DiscourseRelation } from "./getDiscourseRelations" ;
17+ import type { json } from "./getBlockProps" ;
1718import nanoid from "nanoid" ;
1819
1920export type QueryArgs = {
@@ -315,6 +316,29 @@ export const fireQuerySync = (args: FireQueryArgs): QueryResult[] => {
315316 } ) ) ;
316317} ;
317318
319+ const PROP_NAME_RE = / : [ a - z A - Z 0 - 9 _ - ] + \/ [ a - z A - Z 0 - 9 _ - ] + \b / g;
320+ const PULL_RE = / \( p u l l [ ^ ) ] + \) / g;
321+
322+ const renamePropsInResult = (
323+ result : json | null ,
324+ mapping : Record < string , string > ,
325+ ) : json | null => {
326+ const rename = ( x : json | null ) : json | null => {
327+ if ( Array . isArray ( x ) ) return x . map ( rename ) ;
328+ if ( x === null || x === undefined ) return x ;
329+ if ( typeof x === "object" ) {
330+ return Object . fromEntries (
331+ Object . entries ( x as object ) . map ( ( [ k , v ] ) => [
332+ mapping [ k ] || k ,
333+ rename ( v ) ,
334+ ] ) ,
335+ ) ;
336+ }
337+ return x ;
338+ } ;
339+ return rename ( result ) ;
340+ } ;
341+
318342const fireQuery : FireQuery = async ( _args ) => {
319343 const { isCustomEnabled, customNode, local, ...args } = _args ;
320344
@@ -349,11 +373,46 @@ const fireQuery: FireQuery = async (_args) => {
349373 }
350374
351375 let queryResults : unknown [ ] [ ] = [ ] ;
376+ // NOTE: The slow path (async.q with property remapping) is intentionally disabled
377+ // but preserved for potential future use pending comprehensive query testing.
378+ // We have seen some errors in (fast) backend queries, but not so far in local fast ones.
379+ const preferSlow = false ;
352380 if ( local ) {
353- queryResults = await window . roamAlphaAPI . data . async . fast . q (
354- query ,
355- ...inputs ,
356- ) ;
381+ let useSlow = preferSlow ;
382+ let propNamesSub : Record < string , string > | undefined ;
383+ if ( preferSlow ) {
384+ // keeping this code in case it turns out the fast results are more fragile than the slow ones
385+ // TODO: Remove when we have a more comprehensive test suite.
386+ const pulls = [ ...query . matchAll ( PULL_RE ) ] . map ( ( r ) => r [ 0 ] ) ;
387+ if ( pulls . length > 0 ) {
388+ // pull in base async query (vs fast or backend) returns non-namespaced names,
389+ // so there are a few possibilities of conflict,
390+ // namely: {log,version,window}/id; {graph,user}/settings; {block,user}/uid; {create,edit}/time
391+ // So look for collisions in property names in pull part of query.
392+ const propNames = new Set (
393+ [ ...pulls . join ( " " ) . matchAll ( PROP_NAME_RE ) ] . map ( ( m ) => m [ 0 ] ) ,
394+ ) ;
395+ propNamesSub = Object . fromEntries (
396+ [ ...propNames ] . map ( ( n ) => [ n . split ( "/" ) [ 1 ] , n ] ) ,
397+ ) ;
398+ useSlow = Object . keys ( propNamesSub ) . length === propNames . size ;
399+ }
400+ }
401+ if ( useSlow ) {
402+ // no name conflict, safe to use async query
403+ // BUT it returns non-namespaced names, so substitute prop names back
404+ queryResults = await window . roamAlphaAPI . data . async . q ( query , ...inputs ) ;
405+ if ( propNamesSub !== undefined )
406+ queryResults = renamePropsInResult (
407+ queryResults as json ,
408+ propNamesSub ,
409+ ) as unknown [ ] [ ] ;
410+ } else {
411+ queryResults = await window . roamAlphaAPI . data . async . fast . q (
412+ query ,
413+ ...inputs ,
414+ ) ;
415+ }
357416 } else {
358417 queryResults = await window . roamAlphaAPI . data . backend . q ( query , ...inputs ) ;
359418 }
0 commit comments