@cratis/arc 20.66.0 → 20.66.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/queries/ObservableQueryFor.js +3 -7
- package/dist/cjs/queries/ObservableQueryFor.js.map +1 -1
- package/dist/cjs/queries/QueryResult.js +5 -17
- package/dist/cjs/queries/QueryResult.js.map +1 -1
- package/dist/cjs/queries/deserializeQueryModel.js +62 -0
- package/dist/cjs/queries/deserializeQueryModel.js.map +1 -0
- package/dist/cjs/queries/index.js +4 -0
- package/dist/cjs/queries/index.js.map +1 -1
- package/dist/esm/queries/ObservableQueryFor.d.ts.map +1 -1
- package/dist/esm/queries/ObservableQueryFor.js +3 -7
- package/dist/esm/queries/ObservableQueryFor.js.map +1 -1
- package/dist/esm/queries/QueryResult.d.ts.map +1 -1
- package/dist/esm/queries/QueryResult.js +5 -17
- package/dist/esm/queries/QueryResult.js.map +1 -1
- package/dist/esm/queries/deserializeQueryModel.d.ts +5 -0
- package/dist/esm/queries/deserializeQueryModel.d.ts.map +1 -0
- package/dist/esm/queries/deserializeQueryModel.js +58 -0
- package/dist/esm/queries/deserializeQueryModel.js.map +1 -0
- package/dist/esm/queries/for_ObservableQueryFor/when_receiving_a_result/and_the_model_type_is_a_primitive_collection.d.ts +2 -0
- package/dist/esm/queries/for_ObservableQueryFor/when_receiving_a_result/and_the_model_type_is_a_primitive_collection.d.ts.map +1 -0
- package/dist/esm/queries/for_ObservableQueryFor/when_receiving_a_result/and_the_model_type_is_a_primitive_collection.js +49 -0
- package/dist/esm/queries/for_ObservableQueryFor/when_receiving_a_result/and_the_model_type_is_a_primitive_collection.js.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_models.d.ts +2 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_models.d.ts.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_models.js +16 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_models.js.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_numbers.d.ts +2 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_numbers.d.ts.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_numbers.js +7 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_numbers.js.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_strings.d.ts +2 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_strings.d.ts.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_strings.js +7 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_strings.js.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_non_array_as_a_collection.d.ts +2 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_non_array_as_a_collection.d.ts.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_non_array_as_a_collection.js +6 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_non_array_as_a_collection.js.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_single_string.d.ts +2 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_single_string.d.ts.map +1 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_single_string.js +7 -0
- package/dist/esm/queries/for_deserializeQueryModel/when_deserializing_a_single_string.js.map +1 -0
- package/dist/esm/queries/index.d.ts +1 -0
- package/dist/esm/queries/index.d.ts.map +1 -1
- package/dist/esm/queries/index.js +1 -0
- package/dist/esm/queries/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/queries/ObservableQueryFor.ts +3 -7
- package/queries/QueryResult.ts +8 -26
- package/queries/deserializeQueryModel.ts +66 -0
- package/queries/for_ObservableQueryFor/when_receiving_a_result/and_the_model_type_is_a_primitive_collection.ts +71 -0
- package/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_models.ts +17 -0
- package/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_numbers.ts +12 -0
- package/queries/for_deserializeQueryModel/when_deserializing_a_collection_of_strings.ts +12 -0
- package/queries/for_deserializeQueryModel/when_deserializing_a_non_array_as_a_collection.ts +11 -0
- package/queries/for_deserializeQueryModel/when_deserializing_a_single_string.ts +12 -0
- package/queries/index.ts +1 -0
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import { IObservableQueryConnection } from './IObservableQueryConnection';
|
|
|
9
9
|
import { NullObservableQueryConnection } from './NullObservableQueryConnection';
|
|
10
10
|
import { createObservableQueryConnection } from './ObservableQueryConnectionFactory';
|
|
11
11
|
import { Constructor } from '@cratis/fundamentals';
|
|
12
|
-
import {
|
|
12
|
+
import { deserializeQueryModel, deserializeQueryModels } from './deserializeQueryModel';
|
|
13
13
|
import { QueryResult } from './QueryResult';
|
|
14
14
|
import { Sorting } from './Sorting';
|
|
15
15
|
import { Paging } from './Paging';
|
|
@@ -219,13 +219,9 @@ export abstract class ObservableQueryFor<TDataType, TParameters = object> implem
|
|
|
219
219
|
|
|
220
220
|
private deserializeResult(result: any): void {
|
|
221
221
|
if (this.enumerable) {
|
|
222
|
-
|
|
223
|
-
result.data = JsonSerializer.deserializeArrayFromInstance(this.modelType, result.data);
|
|
224
|
-
} else {
|
|
225
|
-
result.data = [];
|
|
226
|
-
}
|
|
222
|
+
result.data = deserializeQueryModels(this.modelType, result.data);
|
|
227
223
|
} else if (result.data) {
|
|
228
|
-
result.data =
|
|
224
|
+
result.data = deserializeQueryModel(this.modelType, result.data);
|
|
229
225
|
}
|
|
230
226
|
}
|
|
231
227
|
}
|
package/queries/QueryResult.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
-
import { Constructor
|
|
4
|
+
import { Constructor } from '@cratis/fundamentals';
|
|
5
5
|
import { ValidationResult } from '../validation/ValidationResult';
|
|
6
6
|
import { IQueryResult } from './IQueryResult';
|
|
7
7
|
import { PagingInfo } from './PagingInfo';
|
|
8
8
|
import { ChangeSet } from './ChangeSet';
|
|
9
|
+
import { deserializeQueryModel, deserializeQueryModels } from './deserializeQueryModel';
|
|
9
10
|
|
|
10
11
|
type ServerQueryResult = {
|
|
11
12
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
@@ -162,37 +163,18 @@ export class QueryResult<TDataType = object> implements IQueryResult<TDataType>
|
|
|
162
163
|
this.paging.totalPages = result.paging.totalPages;
|
|
163
164
|
|
|
164
165
|
if (result.data) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (Array.isArray(result.data)) {
|
|
169
|
-
data = isPrimitive
|
|
170
|
-
? Array.from(result.data)
|
|
171
|
-
: JsonSerializer.deserializeArrayFromInstance(instanceType, data);
|
|
172
|
-
} else {
|
|
173
|
-
data = [];
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
data = isPrimitive ? data : JsonSerializer.deserializeFromInstance(instanceType, data);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
this.data = data as TDataType;
|
|
166
|
+
this.data = (enumerable
|
|
167
|
+
? deserializeQueryModels(instanceType, result.data)
|
|
168
|
+
: deserializeQueryModel(instanceType, result.data)) as TDataType;
|
|
180
169
|
} else {
|
|
181
170
|
this.data = (enumerable ? [] : null) as TDataType;
|
|
182
171
|
}
|
|
183
172
|
|
|
184
173
|
if (enumerable && result.changeSet) {
|
|
185
|
-
const isPrimitive = instanceType === String || instanceType === Number || instanceType === Boolean;
|
|
186
174
|
this.changeSet = {
|
|
187
|
-
added:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
replaced: isPrimitive
|
|
191
|
-
? Array.from(result.changeSet.replaced ?? [])
|
|
192
|
-
: JsonSerializer.deserializeArrayFromInstance(instanceType, result.changeSet.replaced ?? []),
|
|
193
|
-
removed: isPrimitive
|
|
194
|
-
? Array.from(result.changeSet.removed ?? [])
|
|
195
|
-
: JsonSerializer.deserializeArrayFromInstance(instanceType, result.changeSet.removed ?? []),
|
|
175
|
+
added: deserializeQueryModels(instanceType, result.changeSet.added ?? []),
|
|
176
|
+
replaced: deserializeQueryModels(instanceType, result.changeSet.replaced ?? []),
|
|
177
|
+
removed: deserializeQueryModels(instanceType, result.changeSet.removed ?? []),
|
|
196
178
|
} as ChangeSet<unknown>;
|
|
197
179
|
}
|
|
198
180
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor, JsonSerializer } from '@cratis/fundamentals';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* ⚠️ deserializeQueryModel / deserializeQueryModels are for use WITHIN this package only.
|
|
8
|
+
*
|
|
9
|
+
* JsonSerializer's converter registry is module state, and a consumer package can easily resolve a
|
|
10
|
+
* different physical copy of @cratis/fundamentals than this one. Calling these from another package
|
|
11
|
+
* therefore looks up Guid/Date/concept converters in the wrong registry and silently degrades those
|
|
12
|
+
* values to plain deserialization. Other packages should use isPrimitiveModelType - which compares
|
|
13
|
+
* against the JavaScript globals and is safe across copies - and deserialize through their own
|
|
14
|
+
* JsonSerializer.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Determines whether a model type is a JavaScript primitive wrapper rather than a real model.
|
|
19
|
+
*
|
|
20
|
+
* A query whose backend returns a primitive collection - `IEnumerable<string>`, `IEnumerable<int>` -
|
|
21
|
+
* generates a proxy with `String`, `Number` or `Boolean` as its model type.
|
|
22
|
+
* @param {Constructor} modelType The model type the query describes itself with.
|
|
23
|
+
* @returns {boolean} True when the type is a primitive wrapper.
|
|
24
|
+
*/
|
|
25
|
+
export function isPrimitiveModelType(modelType: Constructor | null | undefined): boolean {
|
|
26
|
+
return modelType === String || modelType === Number || modelType === Boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Deserializes a single query payload into its model type, passing primitives through untouched.
|
|
31
|
+
*
|
|
32
|
+
* {@link JsonSerializer.deserializeFromInstance} is destructive for primitive wrapper types: it
|
|
33
|
+
* constructs `new String()` and copies declared fields onto it, which for a primitive means the
|
|
34
|
+
* value is discarded and an empty wrapper object is produced. Primitives therefore need to bypass
|
|
35
|
+
* deserialization entirely - they already arrive in their final shape.
|
|
36
|
+
* @param {Constructor} modelType The model type to deserialize into.
|
|
37
|
+
* @param {unknown} data The payload to deserialize.
|
|
38
|
+
* @returns {TDataType} The deserialized instance, or the payload unchanged for primitive types.
|
|
39
|
+
*/
|
|
40
|
+
export function deserializeQueryModel<TDataType>(modelType: Constructor | null | undefined, data: unknown): TDataType {
|
|
41
|
+
if (!modelType || modelType === Object || isPrimitiveModelType(modelType)) {
|
|
42
|
+
return data as TDataType;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return JsonSerializer.deserializeFromInstance(modelType, data) as TDataType;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Deserializes a query payload collection into its model type, passing primitives through untouched.
|
|
50
|
+
*
|
|
51
|
+
* See {@link deserializeQueryModel} for why primitive model types must bypass deserialization.
|
|
52
|
+
* @param {Constructor} modelType The instance type of the items to deserialize into.
|
|
53
|
+
* @param {unknown} data The payload to deserialize. A non-array payload yields an empty collection.
|
|
54
|
+
* @returns {TDataType[]} The deserialized items, or the items unchanged for primitive types.
|
|
55
|
+
*/
|
|
56
|
+
export function deserializeQueryModels<TDataType>(modelType: Constructor | null | undefined, data: unknown): TDataType[] {
|
|
57
|
+
if (!Array.isArray(data)) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!modelType || modelType === Object || isPrimitiveModelType(modelType)) {
|
|
62
|
+
return Array.from(data) as TDataType[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return JsonSerializer.deserializeArrayFromInstance(modelType, data) as TDataType[];
|
|
66
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import * as sinon from 'sinon';
|
|
5
|
+
import { an_observable_query_for } from '../given/an_observable_query_for';
|
|
6
|
+
import { given } from '../../../given';
|
|
7
|
+
import { Globals } from '../../../Globals';
|
|
8
|
+
import { EventSourceFactory } from '../../../EventSourceFactory';
|
|
9
|
+
import { QueryResult } from '../../QueryResult';
|
|
10
|
+
import { QueryTransportMethod } from '../../QueryTransportMethod';
|
|
11
|
+
import { ObservableQuerySubscription } from '../../ObservableQuerySubscription';
|
|
12
|
+
|
|
13
|
+
interface FakeEventSource {
|
|
14
|
+
onmessage: ((event: MessageEvent) => void) | null;
|
|
15
|
+
onerror: (() => void) | null;
|
|
16
|
+
close: sinon.SinonStub;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('and the model type is a primitive collection', given(an_observable_query_for, context => {
|
|
20
|
+
let subscription: ObservableQuerySubscription<string[]>;
|
|
21
|
+
let fakeEventSource: FakeEventSource;
|
|
22
|
+
let received: QueryResult<string[]>[];
|
|
23
|
+
let originalQueryDirectMode: boolean;
|
|
24
|
+
let originalTransportMethod: QueryTransportMethod;
|
|
25
|
+
let originalFactory: EventSourceFactory | undefined;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
originalQueryDirectMode = Globals.queryDirectMode;
|
|
29
|
+
originalTransportMethod = Globals.queryTransportMethod;
|
|
30
|
+
originalFactory = Globals.eventSourceFactory;
|
|
31
|
+
|
|
32
|
+
Globals.queryDirectMode = true;
|
|
33
|
+
Globals.queryTransportMethod = QueryTransportMethod.ServerSentEvents;
|
|
34
|
+
|
|
35
|
+
fakeEventSource = { onmessage: null, onerror: null, close: sinon.stub() };
|
|
36
|
+
Globals.eventSourceFactory = (() => fakeEventSource) as unknown as EventSourceFactory;
|
|
37
|
+
|
|
38
|
+
context.enumerableQuery.setOrigin('https://example.com');
|
|
39
|
+
|
|
40
|
+
received = [];
|
|
41
|
+
subscription = context.enumerableQuery.subscribe(
|
|
42
|
+
result => received.push(result),
|
|
43
|
+
{ category: 'test-category' });
|
|
44
|
+
|
|
45
|
+
fakeEventSource.onmessage!({
|
|
46
|
+
data: JSON.stringify({
|
|
47
|
+
data: ['first', 'second'],
|
|
48
|
+
isSuccess: true,
|
|
49
|
+
isAuthorized: true,
|
|
50
|
+
isValid: true,
|
|
51
|
+
hasExceptions: false,
|
|
52
|
+
validationResults: [],
|
|
53
|
+
exceptionMessages: [],
|
|
54
|
+
exceptionStackTrace: '',
|
|
55
|
+
paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 }
|
|
56
|
+
})
|
|
57
|
+
} as MessageEvent);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
subscription?.unsubscribe();
|
|
62
|
+
Globals.queryDirectMode = originalQueryDirectMode;
|
|
63
|
+
Globals.queryTransportMethod = originalTransportMethod;
|
|
64
|
+
Globals.eventSourceFactory = originalFactory;
|
|
65
|
+
sinon.restore();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should deliver the result to the subscriber', () => received.length.should.equal(1));
|
|
69
|
+
it('should keep every item a primitive string', () => received[0].data.every(_ => typeof _ === 'string').should.be.true);
|
|
70
|
+
it('should keep the values intact', () => received[0].data.should.deep.equal(['first', 'second']));
|
|
71
|
+
}));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor, field } from '@cratis/fundamentals';
|
|
5
|
+
import { deserializeQueryModels } from '../deserializeQueryModel';
|
|
6
|
+
|
|
7
|
+
class Item {
|
|
8
|
+
@field(String)
|
|
9
|
+
name!: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('when deserializing a collection of models', () => {
|
|
13
|
+
const result = deserializeQueryModels<Item>(Item as Constructor, [{ name: 'first' }, { name: 'second' }]);
|
|
14
|
+
|
|
15
|
+
it('should produce instances of the model type', () => result.every(_ => _ instanceof Item).should.be.true);
|
|
16
|
+
it('should carry the values over', () => result.map(_ => _.name).should.deep.equal(['first', 'second']));
|
|
17
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import { deserializeQueryModels } from '../deserializeQueryModel';
|
|
6
|
+
|
|
7
|
+
describe('when deserializing a collection of numbers', () => {
|
|
8
|
+
const result = deserializeQueryModels<number>(Number as Constructor, [42, 43]);
|
|
9
|
+
|
|
10
|
+
it('should keep every item a primitive number', () => result.every(_ => typeof _ === 'number').should.be.true);
|
|
11
|
+
it('should keep the values intact', () => result.should.deep.equal([42, 43]));
|
|
12
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import { deserializeQueryModels } from '../deserializeQueryModel';
|
|
6
|
+
|
|
7
|
+
describe('when deserializing a collection of strings', () => {
|
|
8
|
+
const result = deserializeQueryModels<string>(String as Constructor, ['first', 'second']);
|
|
9
|
+
|
|
10
|
+
it('should keep every item a primitive string', () => result.every(_ => typeof _ === 'string').should.be.true);
|
|
11
|
+
it('should keep the values intact', () => result.should.deep.equal(['first', 'second']));
|
|
12
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import { deserializeQueryModels } from '../deserializeQueryModel';
|
|
6
|
+
|
|
7
|
+
describe('when deserializing a non array as a collection', () => {
|
|
8
|
+
const result = deserializeQueryModels<string>(String as Constructor, null);
|
|
9
|
+
|
|
10
|
+
it('should produce an empty collection', () => result.should.be.empty);
|
|
11
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import { deserializeQueryModel } from '../deserializeQueryModel';
|
|
6
|
+
|
|
7
|
+
describe('when deserializing a single string', () => {
|
|
8
|
+
const result = deserializeQueryModel<string>(String as Constructor, 'the value');
|
|
9
|
+
|
|
10
|
+
it('should keep it a primitive string', () => (typeof result).should.equal('string'));
|
|
11
|
+
it('should keep the value intact', () => result.should.equal('the value'));
|
|
12
|
+
});
|
package/queries/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ export * from './WebSocketMessage';
|
|
|
36
36
|
export * from './QueryTransportMethod';
|
|
37
37
|
export * from './QueryInstanceCache';
|
|
38
38
|
export * from './reconcileQueryData';
|
|
39
|
+
export * from './deserializeQueryModel';
|
|
39
40
|
export * from './IQueryProvider';
|
|
40
41
|
export * from './QueryProvider';
|
|
41
42
|
export * from './QueryValidator';
|