Skip to content

Commit f0e4296

Browse files
authored
Merge pull request #265 from ml054/v5.0
RDBC-424 Investigate performance of RavenDb node js client
2 parents 98cd0b6 + f3d1363 commit f0e4296

25 files changed

+268
-122
lines changed

src/Documents/Changes/DatabaseChanges.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ import CurrentIndexAndNode from "../../Http/CurrentIndexAndNode";
2020
import { RequestExecutor } from "../../Http/RequestExecutor";
2121
import { DocumentConventions } from "../Conventions/DocumentConventions";
2222
import { ServerNode } from "../../Http/ServerNode";
23-
import { ObjectTypeDescriptor } from "../../Types";
23+
import { ObjectTypeDescriptor, ServerResponse } from "../../Types";
2424
import { UpdateTopologyParameters } from "../../Http/UpdateTopologyParameters";
2525
import { TypeUtil } from "../../Utility/TypeUtil";
2626
import { TimeSeriesChange } from "./TimeSeriesChange";
27-
import { QueryResult } from "../Queries/QueryResult";
2827

2928
export class DatabaseChanges implements IDatabaseChanges {
3029

@@ -436,13 +435,16 @@ export class DatabaseChanges implements IDatabaseChanges {
436435
const value = message.Value;
437436
let transformedValue = ObjectUtil.transformObjectKeys(value, { defaultTransform: "camel" });
438437
if (type === "TimeSeriesChange") {
439-
transformedValue = this._conventions.objectMapper
440-
.fromObjectLiteral<QueryResult>(transformedValue, {
441-
nestedTypes: {
442-
from: "date",
443-
to: "date"
444-
}
445-
});
438+
const dateUtil = this._conventions.dateUtil;
439+
440+
const timeSeriesValue = transformedValue as ServerResponse<TimeSeriesChange>;
441+
442+
const overrides: Partial<TimeSeriesChange> = {
443+
from: dateUtil.parse(timeSeriesValue.from),
444+
to: dateUtil.parse(timeSeriesValue.to)
445+
};
446+
447+
transformedValue = Object.assign(transformedValue, overrides);
446448
}
447449
this._notifySubscribers(type, transformedValue, Array.from(this._counters.values()));
448450
break;

src/Documents/Commands/FacetQueryCommand.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DocumentConventions } from "../Conventions/DocumentConventions";
33
import * as stream from "readable-stream";
44
import { QueryCommand } from "./QueryCommand";
55
import { RavenCommandResponsePipeline } from "../../Http/RavenCommandResponsePipeline";
6+
import { ServerResponse } from "../../Types";
67

78
export class FacetQueryCommand extends QueryCommand {
89

@@ -25,18 +26,18 @@ export class FacetQueryCommand extends QueryCommand {
2526
fromCache: boolean,
2627
bodyCallback?: (body: string) => void): Promise<QueryResult> {
2728

28-
const rawResult = await RavenCommandResponsePipeline.create<QueryResult>()
29+
const rawResult = await RavenCommandResponsePipeline.create<ServerResponse<QueryResult>>()
2930
.collectBody(bodyCallback)
3031
.parseJsonAsync()
3132
.jsonKeysTransform("FacetQuery")
3233
.process(bodyStream);
33-
const queryResult = conventions.objectMapper.fromObjectLiteral<QueryResult>(rawResult, {
34-
typeName: QueryResult.name,
35-
nestedTypes: {
36-
indexTimestamp: "date",
37-
lastQueryTime: "date"
38-
}
39-
}, new Map([[QueryResult.name, QueryResult]]));
34+
35+
const overrides: Partial<QueryResult> = {
36+
indexTimestamp: conventions.dateUtil.parse(rawResult.indexTimestamp),
37+
lastQueryTime: conventions.dateUtil.parse(rawResult.lastQueryTime)
38+
};
39+
40+
const queryResult = Object.assign(new QueryResult(), rawResult, overrides) as QueryResult;
4041

4142
if (fromCache) {
4243
queryResult.durationInMs = -1;

src/Documents/Commands/GetConflictsCommand.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GetConflictsResult } from "./GetConflictsResult";
44
import { ServerNode } from "../../Http/ServerNode";
55
import * as stream from "readable-stream";
66
import { DocumentConventions } from "../Conventions/DocumentConventions";
7+
import { ServerResponse } from "../../Types";
78

89
export class GetConflictsCommand extends RavenCommand<GetConflictsResult> {
910

@@ -35,12 +36,18 @@ export class GetConflictsCommand extends RavenCommand<GetConflictsResult> {
3536
}
3637

3738
let body: string = null;
38-
const results = await this._defaultPipeline(_ => body = _).process(bodyStream);
39-
this.result = this._conventions.objectMapper.fromObjectLiteral(results, {
40-
nestedTypes: {
41-
"results[].lastModified": "date"
42-
}
43-
});
39+
const payload = await this._defaultPipeline<ServerResponse<GetConflictsResult>>(_ => body = _).process(bodyStream);
40+
const dateUtil = this._conventions.dateUtil;
41+
42+
const { results, ...otherProps } = payload;
43+
44+
this.result = {
45+
...otherProps,
46+
results: results.map(r => ({
47+
...r,
48+
lastModified: dateUtil.parse(r.lastModified)
49+
}))
50+
};
4451

4552
return body;
4653
}

src/Documents/Commands/QueryCommand.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { JsonSerializer } from "../../Mapping/Json/Serializer";
99
import * as stream from "readable-stream";
1010
import { RavenCommandResponsePipeline } from "../../Http/RavenCommandResponsePipeline";
1111
import { StringBuilder } from "../../Utility/StringBuilder";
12+
import { ServerResponse } from "../../Types";
13+
import { QueryTimings } from "../Queries/Timings/QueryTimings";
14+
import { StringUtil } from "../../Utility/StringUtil";
1215

1316
export interface QueryCommandOptions {
1417
metadataOnly?: boolean;
@@ -102,19 +105,13 @@ export class QueryCommand extends RavenCommand<QueryResult> {
102105
fromCache: boolean,
103106
bodyCallback?: (body: string) => void): Promise<QueryResult> {
104107

105-
const rawResult = await RavenCommandResponsePipeline.create<QueryResult>()
108+
const rawResult = await RavenCommandResponsePipeline.create<ServerResponse<QueryResult>>()
106109
.collectBody(bodyCallback)
107110
.parseJsonAsync()
108111
.jsonKeysTransform("DocumentQuery", conventions)
109112
.process(bodyStream);
110-
const queryResult = conventions.objectMapper
111-
.fromObjectLiteral<QueryResult>(rawResult, {
112-
typeName: QueryResult.name,
113-
nestedTypes: {
114-
indexTimestamp: "date",
115-
lastQueryTime: "date"
116-
}
117-
}, new Map([[QueryResult.name, QueryResult]]));
113+
114+
const queryResult = QueryCommand._mapToLocalObject(rawResult, conventions);
118115

119116
if (fromCache) {
120117
queryResult.durationInMs = -1;
@@ -127,4 +124,32 @@ export class QueryCommand extends RavenCommand<QueryResult> {
127124

128125
return queryResult;
129126
}
127+
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>) {
141+
if (!timings) {
142+
return undefined;
143+
}
144+
145+
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]);
151+
});
152+
}
153+
return mapped;
154+
}
130155
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export class CounterDetail {
2-
public documentId: string;
3-
public counterName: string;
4-
public totalValue: number;
5-
public etag: number;
6-
public counterValues: { [key: string]: number };
7-
public changeVector: string;
1+
export interface CounterDetail {
2+
documentId: string;
3+
counterName: string;
4+
totalValue: number;
5+
etag?: number;
6+
counterValues?: { [key: string]: number };
7+
changeVector?: string;
88
}

src/Documents/Operations/TimeSeries/GetTimeSeriesOperation.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { DocumentConventions } from "../../Conventions/DocumentConventions";
1313
import { RavenCommand } from "../../../Http/RavenCommand";
1414
import { ServerNode } from "../../../Http/ServerNode";
1515
import { StringBuilder } from "../../../Utility/StringBuilder";
16+
import { ServerResponse } from "../../../Types";
1617

1718
export class GetTimeSeriesOperation implements IOperation<TimeSeriesRangeResult> {
1819
private readonly _docId: string;
@@ -125,7 +126,7 @@ class GetTimeSeriesCommand extends RavenCommand<TimeSeriesRangeResult> {
125126
}
126127

127128
let body: string = null;
128-
const results = await this._defaultPipeline(_ => body = _)
129+
const results = await this._defaultPipeline<ServerResponse<TimeSeriesRangeResult>>(_ => body = _)
129130
.process(bodyStream);
130131

131132
this.result = reviveTimeSeriesRangeResult(results, this._conventions);
@@ -138,13 +139,25 @@ class GetTimeSeriesCommand extends RavenCommand<TimeSeriesRangeResult> {
138139
}
139140
}
140141

141-
export function reviveTimeSeriesRangeResult(result: TimeSeriesRangeResult, conventions: DocumentConventions) {
142-
return Object.assign(new TimeSeriesRangeResult(), conventions.objectMapper.fromObjectLiteral<TimeSeriesRangeResult>(result, {
143-
nestedTypes: {
144-
"from": "date",
145-
"to": "date",
146-
"entries": "TimeSeriesEntry",
147-
"entries[].timestamp": "date"
142+
export function reviveTimeSeriesRangeResult(result: ServerResponse<TimeSeriesRangeResult>, conventions: DocumentConventions): TimeSeriesRangeResult {
143+
const { entries, from, to, ...restProps } = result;
144+
145+
const entryMapper = (rawEntry: ServerResponse<TimeSeriesEntry>) => {
146+
const result = new TimeSeriesEntry();
147+
148+
const entryOverrides: Partial<TimeSeriesEntry> = {
149+
timestamp: conventions.dateUtil.parse(rawEntry.timestamp)
148150
}
149-
}, new Map([[TimeSeriesEntry.name, TimeSeriesEntry]])));
151+
152+
return Object.assign(result, rawEntry, entryOverrides) as TimeSeriesEntry;
153+
}
154+
155+
const overrides: Partial<TimeSeriesRangeResult> = {
156+
...restProps,
157+
to: conventions.dateUtil.parse(result.to),
158+
from: conventions.dateUtil.parse(result.from),
159+
entries: entries.map(entryMapper),
160+
}
161+
162+
return Object.assign(new TimeSeriesRangeResult(), overrides);
150163
}

src/Documents/Operations/TimeSeries/GetTimeSeriesStatisticsOperation.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as stream from "readable-stream";
77
import { RavenCommand } from "../../../Http/RavenCommand";
88
import { ServerNode } from "../../../Http/ServerNode";
99
import { DocumentConventions } from "../../Conventions/DocumentConventions";
10+
import { ServerResponse } from "../../../Types";
1011

1112
export class GetTimeSeriesStatisticsOperation implements IOperation<TimeSeriesStatistics> {
1213
private readonly _documentId: string;
@@ -54,13 +55,23 @@ class GetTimeSeriesStatisticsCommand extends RavenCommand<TimeSeriesStatistics>
5455

5556
async setResponseAsync(bodyStream: stream.Stream, fromCache: boolean): Promise<string> {
5657
let body: string = null;
57-
const results = await this._defaultPipeline(_ => body = _).process(bodyStream);
58-
this.result = this._conventions.objectMapper.fromObjectLiteral(results, {
59-
nestedTypes: {
60-
"timeSeries[].startDate": "date",
61-
"timeSeries[].endDate": "date"
62-
}
63-
});
58+
const results = await this._defaultPipeline<ServerResponse<TimeSeriesStatistics>>(_ => body = _).process(bodyStream);
59+
60+
const { timeSeries, ...restProps } = results;
61+
62+
const dateUtil = this._conventions.dateUtil;
63+
64+
this.result = {
65+
...restProps,
66+
timeSeries: timeSeries.map(t => {
67+
const { startDate, endDate } = t;
68+
return {
69+
...t,
70+
startDate: dateUtil.parse(startDate),
71+
endDate: dateUtil.parse(endDate)
72+
}
73+
})
74+
}
6475

6576
return body;
6677
}

src/Documents/Queries/Facets/AggregationQueryBase.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ export interface FacetResultObject {
1515
[key: string]: FacetResult;
1616
}
1717

18-
const FACET_RESULT_TYPE_INFO = { typeName: FacetResult.name };
19-
const FACET_RESULT_TYPES_MAP = new Map([[FacetResult.name, FacetResult]]);
20-
2118
export abstract class AggregationQueryBase {
2219

2320
private readonly _session: InMemoryDocumentSessionOperations;
@@ -60,8 +57,7 @@ export abstract class AggregationQueryBase {
6057
const results: FacetResultObject = {};
6158
const mapper = new TypesAwareObjectMapper();
6259
for (const result of queryResult.results) {
63-
const facetResult = mapper.fromObjectLiteral<FacetResult>(
64-
result, FACET_RESULT_TYPE_INFO, FACET_RESULT_TYPES_MAP);
60+
const facetResult = Object.assign(new FacetResult(), result);
6561
results[facetResult.name] = facetResult;
6662
}
6763

src/Documents/Session/InMemoryDocumentSessionOperations.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { EntityToJson } from "./EntityToJson";
22
import { IDisposable } from "../../Types/Contracts";
33
import { SessionInfo, ConcurrencyCheckMode, StoreOptions } from "./IDocumentSession";
44
import { IMetadataDictionary } from "./IMetadataDictionary";
5-
import { ObjectTypeDescriptor, ClassConstructor } from "../../Types";
5+
import { ObjectTypeDescriptor, ClassConstructor, ServerResponse } from "../../Types";
66
import {
77
SessionEventsEmitter,
88
SessionBeforeStoreEventArgs,
@@ -835,7 +835,7 @@ export abstract class InMemoryDocumentSessionOperations
835835
}
836836
}
837837

838-
public registerTimeSeries(resultTimeSeries: Record<string, Record<string, TimeSeriesRangeResult[]>>) {
838+
public registerTimeSeries(resultTimeSeries: Record<string, Record<string, ServerResponse<TimeSeriesRangeResult>[]>>) {
839839
if (this.noTracking || !resultTimeSeries) {
840840
return;
841841
}
@@ -1110,7 +1110,7 @@ export abstract class InMemoryDocumentSessionOperations
11101110
ranges.splice(fromRangeIndex + 1, toRangeIndex - fromRangeIndex);
11111111
}
11121112

1113-
private static _parseTimeSeriesRangeResult(json: TimeSeriesRangeResult,
1113+
private static _parseTimeSeriesRangeResult(json: ServerResponse<TimeSeriesRangeResult>,
11141114
id: string,
11151115
databaseName: string,
11161116
conventions: DocumentConventions): TimeSeriesRangeResult {
@@ -1706,7 +1706,7 @@ export abstract class InMemoryDocumentSessionOperations
17061706
dirty = true;
17071707
}
17081708

1709-
documentInfo.metadata[prop] = ObjectUtil.clone(documentInfo.metadataInstance[prop]);
1709+
documentInfo.metadata[prop] = ObjectUtil.deepJsonClone(documentInfo.metadataInstance[prop]);
17101710
}
17111711
}
17121712

src/Documents/Session/Operations/BatchOperation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ export class BatchOperation {
169169

170170
private _applyMetadataModifications(id: string, documentInfo: DocumentInfo): void {
171171
documentInfo.metadataInstance = null;
172-
documentInfo.metadata = ObjectUtil.clone(documentInfo.metadata);
172+
documentInfo.metadata = ObjectUtil.deepLiteralClone(documentInfo.metadata);
173173

174174
documentInfo.metadata["@change-vector"] = documentInfo.changeVector;
175175

176-
const documentCopy = ObjectUtil.clone(documentInfo.document);
176+
const documentCopy = ObjectUtil.deepLiteralClone(documentInfo.document);
177177
documentCopy[CONSTANTS.Documents.Metadata.KEY] = documentInfo.metadata;
178178

179179
documentInfo.document = documentCopy;

0 commit comments

Comments
 (0)