Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const compileCriteria = (() => {

return formatter(
serializePropName(fieldName),
serializeValue(value, protocolVersion),
serializeValue(value, protocolVersion, fieldTypes?.[fieldName]),
);
};

Expand Down Expand Up @@ -277,7 +277,7 @@ const createODataQueryAdapter = (queryOptions) => {
jsonp: queryOptions.jsonp,
withCredentials: queryOptions.withCredentials,
countOnly: _countQuery,
deserializeDates: queryOptions.deserializeDates,
processDatesAsUtc: queryOptions.processDatesAsUtc,
fieldTypes: queryOptions.fieldTypes,
isPaged: isFinite(_take),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class RequestDispatcher {
// @ts-expect-error
this._withCredentials = options.withCredentials;
// @ts-expect-error
this._deserializeDates = options.deserializeDates;
this._processDatesAsUtc = options.processDatesAsUtc ?? options.deserializeDates ?? false;
// @ts-expect-error
this._filterToLower = options.filterToLower;
}
Expand All @@ -40,7 +40,7 @@ export default class RequestDispatcher {
// @ts-expect-error
withCredentials: this._withCredentials,
// @ts-expect-error
deserializeDates: this._deserializeDates,
processDatesAsUtc: this._processDatesAsUtc,
},
);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/devextreme/js/__internal/data/odata/m_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const ODataStore = Store.inherit({
withCredentials: this._requestDispatcher._withCredentials,
expand: loadOptions?.expand,
requireTotalCount: loadOptions?.requireTotalCount,
deserializeDates: this._requestDispatcher._deserializeDates,
processDatesAsUtc: this._requestDispatcher._processDatesAsUtc,
fieldTypes: this._fieldTypes,
};

Expand Down
29 changes: 18 additions & 11 deletions packages/devextreme/js/__internal/data/odata/m_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,15 @@ const ajaxOptionsForRequest = (protocolVersion, request, options = {}) => {

export const sendRequest = (protocolVersion, request, options) => {
const {
deserializeDates, fieldTypes, countOnly, isPaged,
processDatesAsUtc, fieldTypes, countOnly, isPaged,
} = options;
// @ts-expect-error
const d = new Deferred();
const ajaxOptions = ajaxOptionsForRequest(protocolVersion, request, options);

ajax.sendRequest(ajaxOptions).always((obj, textStatus) => {
const transformOptions = {
deserializeDates,
processDatesAsUtc,
fieldTypes,
};
const tuple = interpretJsonFormat(obj, textStatus, transformOptions, ajaxOptions);
Expand Down Expand Up @@ -387,14 +387,14 @@ const transformTypes = (obj, options = {}) => {
transformTypes(obj[key], options);
} else if (typeof value === 'string') {
// @ts-expect-error
const { fieldTypes, deserializeDates } = options;
const { fieldTypes, processDatesAsUtc } = options;
const canBeGuid = !fieldTypes || fieldTypes[key] !== 'String';

if (canBeGuid && GUID_REGEX.test(value)) {
obj[key] = new Guid(value);
}

if (deserializeDates !== false) {
if (processDatesAsUtc !== false) {
if (VERBOSE_DATE_REGEX.exec(value)) {
// @ts-expect-error
const date = new Date(Number(RegExp.$1) + RegExp.$2 * 60 * 1000);
Expand All @@ -415,20 +415,20 @@ export const serializePropName = (propName) => (propName instanceof EdmLiteral
? propName.valueOf()
: propName.replace(/\./g, '/'));

const serializeValueV4 = (value) => {
const serializeValueV4 = (value, fieldType) => {
if (value instanceof Date) {
return formatISO8601(value, false, false);
}
if (value instanceof Guid) {
return value.valueOf();
}
if (Array.isArray(value)) {
return `[${value.map((item) => serializeValueV4(item)).join(',')}]`;
return `[${value.map((item) => serializeValueV4(item, fieldType)).join(',')}]`;
}
return serializeValueV2(value);
return serializeValueV2(value, fieldType);
};

const serializeValueV2 = (value) => {
const serializeValueV2 = (value, fieldType) => {
if (value instanceof Date) {
return serializeDate(value);
}
Expand All @@ -438,19 +438,22 @@ const serializeValueV2 = (value) => {
if (value instanceof EdmLiteral) {
return value.valueOf();
}
if (fieldType && ['Date', 'DateTimeOffset'].includes(fieldType)) {
return value;
}
if (typeof value === 'string') {
return serializeString(value);
}
return String(value);
};

export const serializeValue = (value, protocolVersion) => {
export const serializeValue = (value, protocolVersion, fieldType?) => {
switch (protocolVersion) {
case 2:
case 3:
return serializeValueV2(value);
return serializeValueV2(value, fieldType);
case 4:
return serializeValueV4(value);
return serializeValueV4(value, fieldType);
default: throw errors.Error('E4002');
}
};
Expand Down Expand Up @@ -480,6 +483,10 @@ export const keyConverters = {
Single: (value) => (value instanceof EdmLiteral ? value : new EdmLiteral(`${value}f`)),

Decimal: (value) => (value instanceof EdmLiteral ? value : new EdmLiteral(`${value}m`)),

DateTimeOffset: (value) => value,

Date: (value) => value,
};

export const convertPrimitiveValue = (type, value) => {
Expand Down
20 changes: 19 additions & 1 deletion packages/devextreme/js/common/data.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1130,8 +1130,16 @@ export type ODataContextOptions = {
/**
* @docid
* @public
* @default false
* @deprecated ODataContextOptions.processDatesAsUtc
*/
deserializeDates?: boolean;
/**
* @docid ODataContextOptions.processDatesAsUtc
* @public
* @default false
*/
processDatesAsUtc?: boolean;
/**
* @docid
* @public
Expand Down Expand Up @@ -1232,8 +1240,16 @@ export type ODataStoreOptions<
/**
* @docid
* @public
* @default false
* @deprecated ODataStoreOptions.processDatesAsUtc
*/
deserializeDates?: boolean;
/**
* @docid ODataStoreOptions.processDatesAsUtc
* @public
* @default false
*/
processDatesAsUtc?: boolean;
/**
* @docid
* @type_function_param1 e:Error
Expand All @@ -1247,7 +1263,9 @@ export type ODataStoreOptions<
* @default {}
* @public
*/
fieldTypes?: any;
fieldTypes?: {
[fieldName: string]: 'String' | 'Int32' | 'Int64' | 'Guid' | 'Boolean' | 'Single' | 'Decimal' | 'Date' | 'DateTimeOffset';
};
/**
* @docid
* @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -916,16 +916,27 @@ QUnit.test('Values are converted according to \'fieldTypes\' property', function
fieldTypes: {
id1: 'Int64',
name: 'String',
total: 'Decimal' // T566307
total: 'Decimal', // T566307
date: 'Date',
dateTime: 'DateTimeOffset'
}
})
.filter([['id1', '=', 123], 'and', ['id2', '=', 456], 'and', ['name', '=', 789], 'and', ['total', '=', null]])
.filter([
['id1', '=', 123], 'and',
['id2', '=', 456], 'and',
['name', '=', 789], 'and',
['total', '=', null], 'and',
['date', '=', '2025-11-11'], 'and',
['dateTime', '=', '2025-11-11T11:11:11.000Z'], 'and',
['dateText', '=', '2025-11-11'], 'and',
['dateTimeText', '=', '2025-11-11T11:11:11.000Z'],
])
.enumerate()
.fail(function() {
assert.ok(false, MUST_NOT_REACH_MESSAGE);
})
.done(function(r) {
assert.equal(r[0].data['$filter'], '(id1 eq 123L) and (id2 eq 456) and (name eq \'789\') and (total eq null)');
assert.equal(r[0].data['$filter'], '(id1 eq 123L) and (id2 eq 456) and (name eq \'789\') and (total eq null) and (date eq 2025-11-11) and (dateTime eq 2025-11-11T11:11:11.000Z) and (dateText eq \'2025-11-11\') and (dateTimeText eq \'2025-11-11T11:11:11.000Z\')');
})
.always(done);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1718,7 +1718,7 @@ QUnit.test('Dates, on updating', function(assert) {
});

QUnit.module('Deserialization', moduleConfig);
QUnit.test('Dates, disableable, ODataStore', function(assert) {
QUnit.test('Dates, default behaviour (processDatesAsUtc = false), ODataStore', function(assert) {
assert.expect(2);

const done = assert.async();
Expand All @@ -1733,7 +1733,7 @@ QUnit.test('Dates, disableable, ODataStore', function(assert) {
responseText: { dateProperty: '1945-05-09T14:25:12.1234567Z' }
});

const store = new ODataStore({ version: 4, url: 'odata.org', deserializeDates: false });
const store = new ODataStore({ version: 4, url: 'odata.org' });
const promises = [
store.load()
.done(function(r) {
Expand All @@ -1751,7 +1751,7 @@ QUnit.test('Dates, disableable, ODataStore', function(assert) {
.always(done);
});

QUnit.test('Dates, disableable, ODataContext', function(assert) {
QUnit.test('Dates, default behaviour (processDatesAsUtc = false) and fieldType of dateProperty is undefined, ODataContext', function(assert) {
assert.expect(4);

const done = assert.async();
Expand All @@ -1774,10 +1774,9 @@ QUnit.test('Dates, disableable, ODataContext', function(assert) {
const ctx = new ODataContext({
version: 4,
url: 'odata.org',
deserializeDates: false,
entities: {
'X': { name: 'name' },
'Y': { name: 'name', deserializeDates: true }
'Y': { name: 'name', processDatesAsUtc: true }
}
});

Expand Down Expand Up @@ -1808,6 +1807,63 @@ QUnit.test('Dates, disableable, ODataContext', function(assert) {
.always(done);
});

QUnit.test('Dates, processDatesAsUtc = true, ODataContext', function(assert) {
assert.expect(4);

const done = assert.async();

ajaxMock.setup({
url: 'odata.org/name',
responseText: { value: [{ dateProperty: '1945-05-09T14:25:12.1234567Z' }] }
});

ajaxMock.setup({
url: 'odata.org/function()',
responseText: { dateProperty: '1945-05-09T14:25:12.1234567Z' }
});

ajaxMock.setup({
url: 'odata.org/action',
responseText: { dateProperty: '1945-05-09T14:25:12.1234567Z' }
});

const ctx = new ODataContext({
version: 4,
url: 'odata.org',
processDatesAsUtc: true,
entities: {
'X': { name: 'name' },
'Y': { name: 'name' }
}
});

const promises = [
ctx.get('function')
.done(function(r) {
assert.ok(isDate(r.dateProperty));
}),

ctx.invoke('action')
.done(function(r) {
assert.ok(isDate(r.dateProperty));
}),

ctx.X.load()
.done(function(r) {
assert.ok(isDate(r[0].dateProperty));
}),

ctx.Y.load()
.done(function(r) {
assert.ok(isDate(r[0].dateProperty));
})
];

$.when.apply($, promises)
.fail(function() { assert.ok(false, MUST_NOT_REACH_MESSAGE); })
.always(done);
});

QUnit.module('JSONP support', moduleConfig);
QUnit.test('load()', function(assert) {
const done = assert.async();
Expand Down
23 changes: 22 additions & 1 deletion packages/devextreme/ts/dx.all.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3801,8 +3801,13 @@ declare module DevExpress.common.data {
}) => void;
/**
* [descr:ODataContextOptions.deserializeDates]
* @deprecated [depNote:ODataContextOptions.deserializeDates]
*/
deserializeDates?: boolean;
/**
* [descr:ODataContextOptions.processDatesAsUtc]
*/
processDatesAsUtc?: boolean;
/**
* [descr:ODataContextOptions.entities]
*/
Expand Down Expand Up @@ -3884,8 +3889,13 @@ declare module DevExpress.common.data {
}) => void;
/**
* [descr:ODataStoreOptions.deserializeDates]
* @deprecated [depNote:ODataStoreOptions.deserializeDates]
*/
deserializeDates?: boolean;
/**
* [descr:ODataStoreOptions.processDatesAsUtc]
*/
processDatesAsUtc?: boolean;
/**
* [descr:ODataStoreOptions.errorHandler]
*/
Expand All @@ -3897,7 +3907,18 @@ declare module DevExpress.common.data {
/**
* [descr:ODataStoreOptions.fieldTypes]
*/
fieldTypes?: any;
fieldTypes?: {
[fieldName: string]:
| 'String'
| 'Int32'
| 'Int64'
| 'Guid'
| 'Boolean'
| 'Single'
| 'Decimal'
| 'Date'
| 'DateTimeOffset';
};
/**
* [descr:ODataStoreOptions.filterToLower]
*/
Expand Down
Loading