diff --git a/AUTO_RECONSCTRUCT_BY_JSON_SCHEME.md b/AUTO_RECONSCTRUCT_BY_JSON_SCHEME.md index 7cefc14aa..b5a9d97c2 100644 --- a/AUTO_RECONSCTRUCT_BY_JSON_SCHEME.md +++ b/AUTO_RECONSCTRUCT_BY_JSON_SCHEME.md @@ -53,13 +53,12 @@ add_a_car(car: Car) { ### The schema format #### We support multiple type in schema: * build-in non object types: `string`, `number`, `boolean` -* build-in object types: `date`, `bigint` +* build-in object types: `Date`, `BigInt`. And we can skip those two build-in object types in schema info * build-in collection types: `array`, `map` * for `array` type, we need to declare it in the format of `{array: {value: valueType}}` * for `map` type, we need to declare it in the format of `{map: {key: 'KeyType', value: 'valueType'}}` * Custom Class types: `Car` or any class types -* Near collection types: `Vector`, `LookupMap`, `LookupSet`, `UnorderedMap`, `UnorderedSet` - * +* Near collection types: `Vector`, `LookupMap`, `LookupSet`, `UnorderedMap`, `UnorderedSet` We have a test example which contains all those types in one schema: [status-deserialize-class.js](./examples/src/status-deserialize-class.js) ```js class StatusDeserializeClass { @@ -102,6 +101,27 @@ class StatusDeserializeClass { // other methods } ``` +#### Logic of auto reconstruct by json schema +The `_reconstruct` method in [near-bindgen.ts](./packages/near-sdk-js/src/near-bindgen.ts) will check whether there exit a schema in smart contract class, if there exist a static schema info, it will be decoded to class by invoking `decodeObj2class`, or it will fallback to previous behavior: +```typescript + static _reconstruct(classObject: object, plainObject: AnyObject): object { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (classObject.constructor.schema === undefined) { + for (const item in classObject) { + const reconstructor = classObject[item].constructor?.reconstruct; + + classObject[item] = reconstructor + ? reconstructor(plainObject[item]) + : plainObject[item]; + } + + return classObject; + } + + return decodeObj2class(classObject, plainObject); + } +``` #### no need to announce GetOptions.reconstructor in decoding nested collections In this other hand, after we set schema for the Near collections with nested collections, we don't need to announce `reconstructor` when we need to get and decode a nested collections because the data type info in the schema will tell sdk what the nested data type. Before we set schema if we need to get a nested collection we need to set `reconstructor` in `GetOptions`: diff --git a/examples/__tests__/test-status-deserialize-class.ava.js b/examples/__tests__/test-status-deserialize-class.ava.js index a7b291ed3..51634d9bb 100644 --- a/examples/__tests__/test-status-deserialize-class.ava.js +++ b/examples/__tests__/test-status-deserialize-class.ava.js @@ -41,7 +41,7 @@ test("Ali sets then gets status", async (t) => { ); }); -test.only("Ali set_truck_info and get_truck_info", async (t) => { +test("Ali set_truck_info and get_truck_info", async (t) => { const { ali, statusMessage } = t.context.accounts; let carName = "Mercedes-Benz"; let speed = 240; @@ -132,6 +132,17 @@ test("Ali set_big_num_and_date then gets", async (t) => { t.is(afterSetDate.toString(), '2023-08-19T23:15:30.000Z'); }); +test("Ali set_extra_data without schema defined then gets", async (t) => { + const { ali, statusMessage } = t.context.accounts; + await ali.call(statusMessage, "set_extra_data", { message: "Hello world!", number: 100 }); + + + const messageWithoutSchemaDefined = await statusMessage.view("get_extra_msg", { }); + t.is(messageWithoutSchemaDefined, "Hello world!"); + const numberWithoutSchemaDefined = await statusMessage.view("get_extra_number", { }); + t.is(numberWithoutSchemaDefined, 100); +}); + test("View get_subtype_of_efficient_recordes", async (t) => { const { statusMessage } = t.context.accounts; diff --git a/examples/src/status-deserialize-class.js b/examples/src/status-deserialize-class.js index d6e248aa2..7ee6978a0 100644 --- a/examples/src/status-deserialize-class.js +++ b/examples/src/status-deserialize-class.js @@ -77,6 +77,8 @@ export class StatusDeserializeClass { this.user_car_map = new UnorderedMap("g"); this.big_num = 1n; this.date = new Date(); + this.message_without_schema_defined = ""; + this.number_without_schema_defined = 0; } @call({}) @@ -256,6 +258,26 @@ export class StatusDeserializeClass { return this.unordered_set.contains(account_id); } + @call({}) + set_extra_data({ message, number }) { + let account_id = near.signerAccountId(); + near.log(`${account_id} set_extra_data message ${message}, number: ${number}`); + this.message_without_schema_defined = message; + this.number_without_schema_defined = number; + } + + @view({}) + get_extra_msg({ }) { + near.log(`get_extra_msg`); + return this.message_without_schema_defined; + } + + @view({}) + get_extra_number({ }) { + near.log(`get_extra_number`); + return this.number_without_schema_defined; + } + @view({}) get_subtype_of_efficient_recordes({ }) { near.log(`get_subtype_of_efficient_recordes`);