JSONDocument Value сериализуется как объект и приводит к ошибке
Bug Report
Environment and system information:
- ydb-nodejs-sdk version: 5.8.0
- Node.js version: does'n matter
- NPM version: does'n matter
- Operation System: does'n matter
Current behavior:
Сейчас корректно работает только строка размеченная как JSONDocument. Но это очень неудобно на уровне модели постоянно помнить, что нужно сериализовать данные в строку. Было бы удобнее унести это глубже.
Expected behavior:
Я могу разметить свойство с объектом @declareType(Types.JSON_DOCUMENT) и он возьмет на себя всю «магию».
Steps to reproduce:
Если в наследнике TypedData разметить свойство с типом object декоратором с типом JSON_DOCUMENT
export class Event<T> extends TypedData {
@declareType(Types.JSON_DOCUMENT)
public payload: object;
...
}
То при передаче Event.asTypedCollection([event]) в параметры метода session.execute мы получим
{
"type": {
"listType": {
"item": {
"structType": {
"members": [
{
"name": "payload",
"type": {
"typeId": 4612
}
}
]
}
}
}
},
"value": {
"items": [
{
"items": [
{
"textValue": { <=== Вот тут проблема. Объект, а нужна строка.
"key": "value",
...
}
}
]
}
]
}
}
Внимание надо обратить на то что в "textValue" попадает объект. В итоге в логах я вижу:
Error: Unexpected transport error code 13! Error itself: {"code":13,"details":"Request message serialization failure: The \"string\" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of Object","metadata":{}}
Вот такой вариант не приводит к ошибкам, но пользоваться им не удобно.
export class Event<T> extends TypedData {
@declareType(Types.JSON_DOCUMENT)
public payload: string; <== Различие в типе свойства модели и соответсвенно во всем остальном коде, который его исползует.
...
}
Related code:
Мне кажется проблема, что в preparePrimitiveValue объект не сериализуется в строку. В этом месте можно было бы проверять, что для JSONDocument'а, а возможно и просто JSON, передан объект, и тогда прогонять его через JSON.stringify.
https://github.com/ydb-platform/ydb-nodejs-sdk/blob/main/src/types.ts#L475
Пока обошел проблему, добавив у класса Event оверрайд метода
getValue(propertyKey: string): Ydb.IValue {
const val = super.getValue(propertyKey);
if (propertyKey === 'payload') {
return {
textValue: JSON.stringify(val.textValue),
}
}
return val;
}
Но это костыль.
Привет! Спасибо за issue! Я постараюсь посмотреть, что я могу сделать. Подскажи, пожалуйста, что бы ты хотел передавать как Types.JSON_DOCUMENT, там будут примитивные типы (string, number, boolean, null, bigint, Long) ?
Я бы хотел передавать там объекты или массивы.
там будут примитивные типы (string, number, boolean, null, bigint, Long) ?
Если речь про свойства эти объектов, то да. Однако я не ожидаю, что это будут плоские объекты.
Скорее есть ожидание, что это должны быть объекты переживающие JSON.parse(JSON.stringify())
var assert = require('assert');
const good = {foo: 1}
assert.deepEqual(good, JSON.parse(JSON.stringify(good)))
const bad = {foo: new Date()}
assert.deepEqual(bad, JSON.parse(JSON.stringify(bad)))
Если речь про свойства эти объектов, то да.
А если так?
export class Event<T> extends TypedData {
@declareType(Types.JSON_DOCUMENT)
public payload: string;
@declareType(Types.JSON_DOCUMENT)
public payload2: number;
@declareType(Types.JSON_DOCUMENT)
public payload3: boolean;
@declareType(Types.JSON_DOCUMENT)
public payload3: bigint;
@declareType(Types.JSON_DOCUMENT)
public payload3: Long;
@declareType(Types.JSON_DOCUMENT)
public payload3: Date;
@declareType(Types.JSON_DOCUMENT)
public payload3: { toString(): string };
@declareType(Types.JSON_DOCUMENT)
public payload3: { toJSON(): string };
...
}
А можно что-то такого вообще сделать? https://github.com/typegoose/typegoose?tab=readme-ov-file
Чтобы не дублировать типы, а обойтись @prop()
А можно что-то такого вообще сделать? https://github.com/typegoose/typegoose?tab=readme-ov-file Чтобы не дублировать типы, а обойтись
@prop()
Вообще есть планы закопать апи с декораторами... Добавить автоматический inference в нативные типы js если это возможно. А так же поддержать работу любых объектов, которые реализуют интерфейс с методами а-ля toYDB(jsNative): ydbValue, toNative(ydbValue): jsNative, нейминг не окончательный.
Пока я готов пофиксить конкретный баг, но не делать что-то новое в этом направлении.
И в планах к концу года - внедрение в популярные ORM (Drizzle, TypeORM, Prisma, ...). Отсюда и желание закопать апи с декораторами, это есть в ормках. Пока декораторы нативно не появятся в ECMAScript - это все experimental