@@ -12,6 +12,12 @@ import { StringBuilder } from "../../Utility/StringBuilder";
1212import { ServerResponse } from "../../Types" ;
1313import { QueryTimings } from "../Queries/Timings/QueryTimings" ;
1414import { StringUtil } from "../../Utility/StringUtil" ;
15+ import { CounterDetail } from "../Operations/Counters/CounterDetail" ;
16+ import { CompareExchangeResultItem } from "../Operations/CompareExchange/CompareExchangeValueResultParser" ;
17+ import { TimeSeriesRangeResult } from "../Operations/TimeSeries/TimeSeriesRangeResult" ;
18+ import { TimeSeriesEntry } from "../Session/TimeSeries/TimeSeriesEntry" ;
19+ import { readToEnd , stringToReadable } from "../../Utility/StreamUtil" ;
20+ import { ObjectUtil } from "../../Utility/ObjectUtil" ;
1521
1622export interface QueryCommandOptions {
1723 metadataOnly ?: boolean ;
@@ -105,13 +111,21 @@ export class QueryCommand extends RavenCommand<QueryResult> {
105111 fromCache : boolean ,
106112 bodyCallback ?: ( body : string ) => void ) : Promise < QueryResult > {
107113
108- const rawResult = await RavenCommandResponsePipeline . create < ServerResponse < QueryResult > > ( )
109- . collectBody ( bodyCallback )
110- . parseJsonAsync ( )
111- . jsonKeysTransform ( "DocumentQuery" , conventions )
112- . process ( bodyStream ) ;
114+ const body = await readToEnd ( bodyStream ) ;
115+ bodyCallback ?.( body ) ;
116+
117+ let parsedJson : any ;
118+ if ( body . length > conventions . syncJsonParseLimit ) {
119+ const bodyStreamCopy = stringToReadable ( body ) ;
120+ // response is quite big - fallback to async (slower) parsing to avoid blocking event loop
121+ parsedJson = await RavenCommandResponsePipeline . create < ServerResponse < QueryResult > > ( )
122+ . parseJsonAsync ( )
123+ . process ( bodyStreamCopy ) ;
124+ } else {
125+ parsedJson = JSON . parse ( body ) ;
126+ }
113127
114- const queryResult = QueryCommand . _mapToLocalObject ( rawResult , conventions ) ;
128+ const queryResult = QueryCommand . _mapToLocalObject ( parsedJson , conventions ) ;
115129
116130 if ( fromCache ) {
117131 queryResult . durationInMs = - 1 ;
@@ -125,31 +139,57 @@ export class QueryCommand extends RavenCommand<QueryResult> {
125139 return queryResult ;
126140 }
127141
128- private static _mapToLocalObject ( json : ServerResponse < QueryResult > , conventions : DocumentConventions ) : QueryResult {
129- const { indexTimestamp, lastQueryTime, timings, ...otherProps } = json ;
130-
131- const overrides : Partial < QueryResult > = {
132- indexTimestamp : conventions . dateUtil . parse ( indexTimestamp ) ,
133- lastQueryTime : conventions . dateUtil . parse ( lastQueryTime ) ,
134- timings : QueryCommand . _mapTimingsToLocalObject ( timings )
135- } ;
136-
137- return Object . assign ( new QueryResult ( ) , otherProps , overrides ) ;
138- }
139-
140- private static _mapTimingsToLocalObject ( timings : ServerResponse < QueryTimings > ) {
142+ //TODO: use ServerCasing<QueryTimings> instead of any, after upgrading to TS 4.2
143+ private static _mapTimingsToLocalObject ( timings : any ) {
141144 if ( ! timings ) {
142145 return undefined ;
143146 }
144147
145148 const mapped = new QueryTimings ( ) ;
146- mapped . durationInMs = timings . durationInMs ;
147- mapped . timings = timings . timings ? { } : undefined ;
148- if ( timings . timings ) {
149- Object . keys ( timings . timings ) . forEach ( time => {
150- mapped . timings [ StringUtil . uncapitalize ( time ) ] = QueryCommand . _mapTimingsToLocalObject ( timings . timings [ time ] ) ;
149+ mapped . durationInMs = timings . DurationInMs ;
150+ mapped . timings = timings . Timings ? { } : undefined ;
151+ if ( timings . Timings ) {
152+ Object . keys ( timings . Timings ) . forEach ( time => {
153+ mapped . timings [ StringUtil . uncapitalize ( time ) ] = QueryCommand . _mapTimingsToLocalObject ( timings . Timings [ time ] ) ;
151154 } ) ;
152155 }
153156 return mapped ;
154157 }
158+
159+
160+ //TODO: use ServerCasing<ServerResponse<QueryResult>> instead of any, after upgrading to TS 4.2
161+ private static _mapToLocalObject ( json : any , conventions : DocumentConventions ) : QueryResult {
162+ const mappedIncludes : Record < string , any > = { } ;
163+ if ( json . Includes ) {
164+ for ( const [ key , value ] of Object . entries ( json . Includes ) ) {
165+ mappedIncludes [ key ] = ObjectUtil . transformDocumentKeys ( value , conventions ) ;
166+ }
167+ }
168+
169+ const props : Omit < QueryResult , "scoreExplanations" | "cappedMaxResults" | "createSnapshot" | "resultSize" > = {
170+ results : json . Results . map ( x => ObjectUtil . transformDocumentKeys ( x , conventions ) ) ,
171+ includes : mappedIncludes ,
172+ indexName : json . IndexName ,
173+ indexTimestamp : conventions . dateUtil . parse ( json . IndexTimestamp ) ,
174+ includedPaths : json . IncludedPaths ,
175+ isStale : json . IsStale ,
176+ skippedResults : json . SkippedResults ,
177+ totalResults : json . TotalResults ,
178+ highlightings : json . Highlightings ,
179+ explanations : json . Explanations ,
180+ timingsInMs : json . TimingsInMs ,
181+ lastQueryTime : conventions . dateUtil . parse ( json . LastQueryTime ) ,
182+ durationInMs : json . DurationInMs ,
183+ resultEtag : json . ResultEtag ,
184+ nodeTag : json . NodeTag ,
185+ counterIncludes : ObjectUtil . mapCounterIncludesToLocalObject ( json . CounterIncludes ) ,
186+ includedCounterNames : json . IncludedCounterNames ,
187+ timeSeriesIncludes : ObjectUtil . mapTimeSeriesIncludesToLocalObject ( json . TimeSeriesIncludes ) ,
188+ compareExchangeValueIncludes : ObjectUtil . mapCompareExchangeToLocalObject ( json . CompareExchangeValueIncludes ) ,
189+ timeSeriesFields : json . TimeSeriesFields ,
190+ timings : QueryCommand . _mapTimingsToLocalObject ( json . Timings )
191+ }
192+
193+ return Object . assign ( new QueryResult ( ) , props ) ;
194+ }
155195}
0 commit comments