From dff182856b62a8c761ffadda6913138b7447d98b Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 10:46:38 -0600 Subject: [PATCH 01/37] Change recursive to behave more like IDL.Rec --- examples/recursion/src/index.did | 56 +++--- examples/recursion/src/index.ts | 78 +++++---- examples/recursion/test/tests.ts | 161 +++++++++++++++++- src/lib_functional/candid/reference/record.ts | 14 +- .../candid/reference/recursive.ts | 18 +- .../candid/reference/variant.ts | 14 +- src/lib_new/primitives.ts | 4 +- src/lib_new/utils.ts | 3 - src/lib_new/visitors/encode_decode/index.ts | 26 ++- 9 files changed, 268 insertions(+), 106 deletions(-) diff --git a/examples/recursion/src/index.did b/examples/recursion/src/index.did index 5532077698..5a42acab96 100644 --- a/examples/recursion/src/index.did +++ b/examples/recursion/src/index.did @@ -1,23 +1,37 @@ -type rec_1 = variant {num:int8; varRec:rec_0}; -type rec_0 = record {myVar:rec_1}; -type rec_3 = variant {num:int8; varRec:rec_2}; -type rec_2 = record {myVar:rec_3}; -type rec_4 = variant {num:int8; recVariant:rec_4}; -type rec_5 = variant {num:int8; recVariant:rec_5}; -type rec_7 = variant {num:int8; varRec:rec_6}; -type rec_6 = record {myVar:rec_7}; -type rec_8 = variant {num:int8; recVariant:rec_8}; -type rec_9 = variant {num:int8; varTuple:record {rec_9; rec_9}}; -type rec_10 = variant {num:int8; varTuple:record {rec_10; rec_10}}; -type rec_11 = variant {num:int8; varTuple:record {rec_11; rec_11}}; -type rec_12 = variant {num:int8; varTuple:record {rec_12; rec_12}}; -type rec_13 = variant {num:int8; varTuple:record {rec_13; rec_13}}; -type rec_14 = variant {num:int8; varTuple:record {rec_14; rec_14}}; +type rec_0 = record {myOpt:opt rec_0}; +type rec_1 = record {myOpt:opt rec_1}; +type rec_2 = record {myVecRecords:vec rec_2}; +type rec_3 = record {myVecRecords:vec rec_3}; +type rec_4 = record {myVar:variant {num:int8; varRec:rec_4}}; +type rec_5 = record {myVar:variant {num:int8; varRec:rec_5}}; +type rec_6 = variant {num:int8; recVariant:rec_6}; +type rec_7 = variant {num:int8; recVariant:rec_7}; +type rec_8 = record {opt rec_8; opt rec_8}; +type rec_9 = record {opt rec_9; opt rec_9}; +type rec_10 = record {vec rec_10; vec rec_10}; +type rec_11 = record {vec rec_11; vec rec_11}; +type rec_12 = record {myOpt:opt rec_12}; +type rec_13 = record {myVecRecords:vec rec_13}; +type rec_14 = record {myVar:variant {num:int8; varRec:rec_14}}; +type rec_15 = variant {num:int8; recVariant:rec_15}; +type rec_16 = record {opt rec_16; opt rec_16}; +type rec_17 = record {vec rec_17; vec rec_17}; +type rec_18 = record {variant {num:int8; varTuple:rec_18}; variant {num:int8; varTuple:rec_18}}; +type rec_19 = record {variant {num:int8; varTuple:rec_19}; variant {num:int8; varTuple:rec_19}}; +type rec_20 = record {variant {num:int8; varTuple:rec_20}; variant {num:int8; varTuple:rec_20}}; service: () -> { - testRecRecordWithVariant: (rec_0) -> (rec_2) query; - testRecVariant: (rec_4) -> (rec_5) query; - testRecRecordWithVariantReturn: () -> (rec_6) query; - testRecVariantReturn: () -> (rec_8) query; - testRecTupleWithVariant: (record {rec_9; rec_10}) -> (record {rec_11; rec_12}) query; - testRecTupleWithVariantReturn: () -> (record {rec_13; rec_14}) query; + testRecRecordWithOpt: (rec_0) -> (rec_1) query; + testRecRecordWithVec: (rec_2) -> (rec_3) query; + testRecRecordWithVariant: (rec_4) -> (rec_5) query; + testRecVariant: (rec_6) -> (rec_7) query; + testRecTupleWithOpt: (rec_8) -> (rec_9) query; + testRecTupleWithVec: (rec_10) -> (rec_11) query; + testRecRecordWithOptReturn: () -> (rec_12) query; + testRecRecordWithVecReturn: () -> (rec_13) query; + testRecRecordWithVariantReturn: () -> (rec_14) query; + testRecVariantReturn: () -> (rec_15) query; + testRecTupleWithOptReturn: () -> (rec_16) query; + testRecTupleWithVecReturn: () -> (rec_17) query; + testRecTupleWithVariant: (rec_18) -> (rec_19) query; + testRecTupleWithVariantReturn: () -> (rec_20) query; } diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index d840a346c1..a17e098039 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -1,31 +1,22 @@ -import { query, Service, text, Tuple, Vec, Void } from 'azle'; +import { None, query, Service, Some, text, Tuple, Vec, Void } from 'azle'; import { Record, Recursive, int8, Variant, Opt } from 'azle'; // These are the types that can be recursive // Record // Record can't be recursive by itself. It needs something to be able to terminate it. It needs to work with Variants, Opts, and Vec -// const optRecord = Record({ myOpt: Opt(Recursive(() => optRecord)) }); -// const vecRecord = Record({ myVecRecords: Vec(Recursive(() => vecRecord)) }); -const varRecord = Record({ myVar: Recursive(() => myVar) }); -// TODO I would prefer this syntax -// const varRecord = Recursive(() => Record({ myVar: myVar })); -// const vecRecord = Recursive(() => Record({ myVecRecords: Vec(vecRecord) })); -// const optRecord = Recursive(() => Record({ myOpt: Opt(optRecord) })); +const varRecord = Recursive(() => Record({ myVar: myVar })); +const vecRecord = Recursive(() => Record({ myVecRecords: Vec(vecRecord) })); +const optRecord = Recursive(() => Record({ myOpt: Opt(optRecord) })); const myVar = Variant({ num: int8, varRec: varRecord }); // Variant // Variant is the only type that can be recursive all by itself but it does need a way to end the recursion -const recVariant = Variant({ - num: int8, - recVariant: Recursive(() => recVariant) -}); +const recVariant = Recursive(() => + Variant({ num: int8, recVariant: recVariant }) +); // Tuple const optTuple = Recursive(() => Tuple(Opt(optTuple), Opt(optTuple))); -const vecTuple = Recursive(() => Vec(vecTuple)); -// const varTuple = Recursive(() => Tuple(myTupleVar, myTupleVar)); -const varTuple = Tuple( - Recursive(() => myTupleVar), - Recursive(() => myTupleVar) -); +const vecTuple = Recursive(() => Tuple(Vec(vecTuple), Vec(vecTuple))); +const varTuple = Recursive(() => Tuple(myTupleVar, myTupleVar)); const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Vec // Vec can't be recursive by itself. At the end of it all it needs to have a concrete type. @@ -34,18 +25,29 @@ const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Func export default Service({ - // optRecord: query([optRecord], optRecord, (param) => param), - // vecRecord: query([vecRecord], vecRecord, (param) => param), + testRecRecordWithOpt: query([optRecord], optRecord, (param) => param), + testRecRecordWithVec: query([vecRecord], vecRecord, (param) => param), testRecRecordWithVariant: query([varRecord], varRecord, (param) => param), testRecVariant: query([recVariant], recVariant, (param) => param), - // optTuple: query([optTuple], optTuple, (param) => param), - // vecTuple: query([vecTuple], vecTuple, (param) => param), - // optRecordReturn: query([], optRecord, () => { - // throw ''; - // }), - // vecRecordReturn: query([], vecRecord, () => { - // throw ''; - // }), + testRecTupleWithOpt: query([optTuple], optTuple, (param) => param), + testRecTupleWithVec: query([vecTuple], vecTuple, (param) => param), + testRecRecordWithOptReturn: query([], optRecord, () => { + return { myOpt: Some({ myOpt: Some({ myOpt: None }) }) }; + }), + testRecRecordWithVecReturn: query([], vecRecord, () => { + return { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] } + ] + }; + }), testRecRecordWithVariantReturn: query([], varRecord, () => { return { myVar: { @@ -58,12 +60,20 @@ export default Service({ recVariant: { recVariant: { recVariant: { num: 12 } } } }; }), - // optTupleReturn: query([], optTuple, () => { - // throw ''; - // }), - // vecTupleReturn: query([], vecTuple, () => { - // throw ''; - // }), + testRecTupleWithOptReturn: query([], optTuple, () => { + return [None, Some([None, None])]; + }), + testRecTupleWithVecReturn: query([], vecTuple, () => { + return [ + [[[], [[[], []]]]], + [ + [[], []], + [[], []], + [[], []], + [[], []] + ] + ]; + }), testRecTupleWithVariant: query([varTuple], varTuple, (param) => param), testRecTupleWithVariantReturn: query([], varTuple, () => { return [ diff --git a/examples/recursion/test/tests.ts b/examples/recursion/test/tests.ts index 148820d18d..61f0ef0b16 100644 --- a/examples/recursion/test/tests.ts +++ b/examples/recursion/test/tests.ts @@ -1,5 +1,9 @@ import { Test } from 'azle/test'; -import { _SERVICE, rec_1 } from './dfx_generated/recursion/recursion.did'; +import { + _SERVICE, + rec_10, + rec_8 +} from './dfx_generated/recursion/recursion.did'; import { ActorSubclass } from '@dfinity/agent'; export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { @@ -104,6 +108,136 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { }; } }, + { + name: 'recursive records with opts', + test: async () => { + const result = await recursion_canister.testRecRecordWithOpt({ + myOpt: [{ myOpt: [] }] + }); + + return { + Ok: result.myOpt[0]?.myOpt.length === 0 + }; + } + }, + { + name: 'recursive records with vec', + test: async () => { + const input = { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] }, + { myVecRecords: [] } + ] + }; + const result = + await recursion_canister.testRecRecordWithVec(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with vec', + test: async () => { + const input: rec_10 = [[[[], [[[], []]]]], []]; + const result = + await recursion_canister.testRecTupleWithVec(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with vec return', + test: async () => { + const input = [ + [[[], [[[], []]]]], + [ + [[], []], + [[], []], + [[], []], + [[], []] + ] + ]; + const result = + await recursion_canister.testRecTupleWithVecReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with opt', + test: async () => { + const input: rec_8 = [[[[], [[[], []]]]], []]; + const result = + await recursion_canister.testRecTupleWithOpt(input); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive tuples with opt return', + test: async () => { + const input = [[], [[[], []]]]; + const result = + await recursion_canister.testRecTupleWithOptReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive records with vec return', + test: async () => { + const input = { + myVecRecords: [ + { myVecRecords: [{ myVecRecords: [] }] }, + { + myVecRecords: [ + { myVecRecords: [] }, + { myVecRecords: [{ myVecRecords: [] }] } + ] + }, + { myVecRecords: [] } + ] + }; + const result = + await recursion_canister.testRecRecordWithVecReturn(); + + return { + Ok: deepCompare(result, input) + }; + } + }, + { + name: 'recursive records with opts return type', + test: async () => { + const result = + await recursion_canister.testRecRecordWithOptReturn(); + + return { + Ok: result.myOpt[0]?.myOpt[0]?.myOpt.length === 0 + }; + } + }, { name: 'recursive tuples with variants', test: async () => { @@ -150,3 +284,28 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { } ]; } + +function deepCompare(obj1: any, obj2: any): boolean { + // Check if both objects are of type object + if (typeof obj1 !== 'object' || typeof obj2 !== 'object') { + return obj1 === obj2; + } + + // Get the keys of both objects + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + // Check if they have the same keys + if (keys1.length !== keys2.length) { + return false; + } + + // Check if each key's value is deeply equal + for (const key of keys1) { + if (!deepCompare(obj1[key], obj2[key])) { + return false; + } + } + + return true; +} diff --git a/src/lib_functional/candid/reference/record.ts b/src/lib_functional/candid/reference/record.ts index b6414687c3..a3e2159d3a 100644 --- a/src/lib_functional/candid/reference/record.ts +++ b/src/lib_functional/candid/reference/record.ts @@ -18,19 +18,7 @@ export function Record< ...obj, _azleName: name, getIDL(parents: Parent[]) { - const idl = IDL.Rec(); - idl.fill( - IDL.Record( - processMap(obj as any, [ - ...parents, - { - idl: idl, - name - } - ]) - ) - ); - return idl; + return IDL.Record(processMap(obj as any, parents)); } } as any; } diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index c1ef810ba7..be571a6be7 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -1,7 +1,17 @@ import { v4 } from 'uuid'; +import { IDL } from '@dfinity/candid'; +import { Parent } from '../../../lib_new/utils'; -export function Recursive(idl: any) { - idl._azleRecLambda = true; - idl._azleName = v4(); - return idl; +export function Recursive(idlCallback: any) { + const name = v4(); + + return { + idlCallback, + _azleName: name, + getIDL(parents: Parent[]) { + const idl = IDL.Rec(); + idl.fill(idlCallback().getIDL([...parents, { idl: idl, name }])); + return idl; + } + }; } diff --git a/src/lib_functional/candid/reference/variant.ts b/src/lib_functional/candid/reference/variant.ts index 60e8afddcb..03aa2c456e 100644 --- a/src/lib_functional/candid/reference/variant.ts +++ b/src/lib_functional/candid/reference/variant.ts @@ -19,19 +19,7 @@ export function Variant< ...obj, _azleName: name, getIDL(parents: any) { - const idl = IDL.Rec(); - idl.fill( - IDL.Variant( - processMap(obj as any, [ - ...parents, - { - idl: idl, - name - } - ]) - ) - ); - return idl; + return IDL.Variant(processMap(obj as any, parents)); } } as any; } diff --git a/src/lib_new/primitives.ts b/src/lib_new/primitives.ts index fae5ebdf9b..9c9c1a240a 100644 --- a/src/lib_new/primitives.ts +++ b/src/lib_new/primitives.ts @@ -255,7 +255,7 @@ export class AzleOpt { _azleCandidType?: '_azleCandidType'; getIDL(parents: Parent[]) { - return IDL.Opt(toIDLType(this._azleType, [])); + return IDL.Opt(toIDLType(this._azleType, parents)); } } @@ -268,7 +268,7 @@ export class AzleVec { _azleCandidType?: '_azleCandidType'; getIDL(parents: Parent[]) { - return IDL.Vec(toIDLType(this._azleType, [])); + return IDL.Vec(toIDLType(this._azleType, parents)); } } diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index e9de3a961a..692c28252a 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -168,9 +168,6 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { } return idl.getIDL(parents); } - if (idl._azleRecLambda) { - return toIDLType(idl(), [...parents, idl._azleName]); - } // if (idl.display === undefined || idl.getIDL === undefined) { // throw Error(`${JSON.stringify(idl)} is not a candid type`); // } diff --git a/src/lib_new/visitors/encode_decode/index.ts b/src/lib_new/visitors/encode_decode/index.ts index 33f3e5a842..06f7c419d9 100644 --- a/src/lib_new/visitors/encode_decode/index.ts +++ b/src/lib_new/visitors/encode_decode/index.ts @@ -22,13 +22,6 @@ export type VisitorResult = any; * is extracted into these helper methods. */ -function handleRecursiveClass(type: any) { - if (type._azleRecLambda) { - return type(); - } - return type; -} - export function visitTuple( visitor: DecodeVisitor | EncodeVisitor, components: IDL.Type[], @@ -37,7 +30,7 @@ export function visitTuple( const fields = components.map((value, index) => value.accept(visitor, { js_data: data.js_data[index], - js_class: handleRecursiveClass(data.js_class._azleTypes[index]) + js_class: data.js_class._azleTypes[index] }) ); return [...fields]; @@ -53,7 +46,7 @@ export function visitOpt( } const candid = ty.accept(visitor, { js_data: data.js_data[0], - js_class: handleRecursiveClass(data.js_class._azleType) + js_class: data.js_class._azleType }); return [candid]; } @@ -69,7 +62,7 @@ export function visitVec( return data.js_data.map((array_elem: any) => { return ty.accept(visitor, { js_data: array_elem, - js_class: handleRecursiveClass(data.js_class._azleType) + js_class: data.js_class._azleType }); }); } @@ -81,7 +74,7 @@ export function visitRecord( ): VisitorResult { const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = handleRecursiveClass(data.js_class[memberName]); + const fieldClass = data.js_class[memberName]; return { ...acc, @@ -104,7 +97,7 @@ export function visitVariant( if ('Ok' in data.js_data) { const okField = fields[0]; const okData = data.js_data['Ok']; - const okClass = handleRecursiveClass(data.js_class._azleOk); + const okClass = data.js_class._azleOk; return Result.Ok( okField[1].accept(visitor, { @@ -116,7 +109,7 @@ export function visitVariant( if ('Err' in data.js_data) { const errField = fields[0]; const errData = data.js_data['Err']; - const errClass = handleRecursiveClass(data.js_class._azleErr); + const errClass = data.js_class._azleErr; return Result.Err( errField[1].accept(visitor, { js_data: errData, @@ -127,7 +120,7 @@ export function visitVariant( } const candidFields = fields.reduce((acc, [memberName, memberIdl]) => { const fieldData = data.js_data[memberName]; - const fieldClass = handleRecursiveClass(data.js_class[memberName]); + const fieldClass = data.js_class[memberName]; if (fieldData === undefined) { // If the field data is undefined then it is not the variant that was used return acc; @@ -149,5 +142,8 @@ export function visitRec( ty: IDL.ConstructType, data: VisitorData ): VisitorResult { - return ty.accept(visitor, data); + return ty.accept(visitor, { + ...data, + js_class: data.js_class.idlCallback() + }); } From af514baf22648fdc0ce4a0f928c3aa25fe81a5f7 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 16:50:28 -0600 Subject: [PATCH 02/37] add func example to recursion --- examples/recursion/src/index.did | 5 ++++ examples/recursion/src/index.ts | 28 +++++++++++++++++++-- examples/recursion/test/tests.ts | 28 +++++++++++++++++++++ src/lib_functional/candid/reference/func.ts | 8 +++--- src/lib_new/utils.ts | 14 ++++++++--- 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/examples/recursion/src/index.did b/examples/recursion/src/index.did index 5a42acab96..da66aa4c1b 100644 --- a/examples/recursion/src/index.did +++ b/examples/recursion/src/index.did @@ -19,6 +19,9 @@ type rec_17 = record {vec rec_17; vec rec_17}; type rec_18 = record {variant {num:int8; varTuple:rec_18}; variant {num:int8; varTuple:rec_18}}; type rec_19 = record {variant {num:int8; varTuple:rec_19}; variant {num:int8; varTuple:rec_19}}; type rec_20 = record {variant {num:int8; varTuple:rec_20}; variant {num:int8; varTuple:rec_20}}; +type rec_21 = func (rec_21) -> (rec_21) query; +type rec_22 = func (rec_22) -> (rec_22) query; +type rec_23 = func (rec_23) -> (rec_23) query; service: () -> { testRecRecordWithOpt: (rec_0) -> (rec_1) query; testRecRecordWithVec: (rec_2) -> (rec_3) query; @@ -34,4 +37,6 @@ service: () -> { testRecTupleWithVecReturn: () -> (rec_17) query; testRecTupleWithVariant: (rec_18) -> (rec_19) query; testRecTupleWithVariantReturn: () -> (rec_20) query; + testRecFunc: (rec_21) -> (rec_22) query; + testRecFuncReturn: () -> (rec_23) query; } diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index a17e098039..2e992cc0df 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -1,4 +1,17 @@ -import { None, query, Service, Some, text, Tuple, Vec, Void } from 'azle'; +import { + Func, + ic, + None, + Principal, + query, + Service, + Some, + text, + Tuple, + update, + Vec, + Void +} from 'azle'; import { Record, Recursive, int8, Variant, Opt } from 'azle'; // These are the types that can be recursive @@ -22,7 +35,13 @@ const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Vec can't be recursive by itself. At the end of it all it needs to have a concrete type. // Opt // Service +const myService = Recursive(() => + Service({ + serviceQuery: query([myService], myService, (param) => param) + }) +); // Func +const myFunc = Recursive(() => Func([myFunc], myFunc, 'query')); export default Service({ testRecRecordWithOpt: query([optRecord], optRecord, (param) => param), @@ -85,7 +104,12 @@ export default Service({ }, { varTuple: [{ num: 40 }, { varTuple: [{ num: 5 }, { num: 10 }] }] } ]; - }) + }), + testRecFunc: query([myFunc], myFunc, (param) => param), + testRecFuncReturn: query([], myFunc, () => [ + Principal.fromText('aaaaa-aa'), + 'create_canister' + ]) }); // Below we have a bunch of different configurations of where to put the the diff --git a/examples/recursion/test/tests.ts b/examples/recursion/test/tests.ts index 61f0ef0b16..f6bc1e3fff 100644 --- a/examples/recursion/test/tests.ts +++ b/examples/recursion/test/tests.ts @@ -5,6 +5,7 @@ import { rec_8 } from './dfx_generated/recursion/recursion.did'; import { ActorSubclass } from '@dfinity/agent'; +import { Principal } from '@dfinity/principal'; export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { return [ @@ -120,6 +121,33 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { }; } }, + { + name: 'recursive funcs', + test: async () => { + const result = await recursion_canister.testRecFunc([ + Principal.fromText('aaaaa-aa'), + 'delete_canister' + ]); + + return { + Ok: + result[0].toString() === 'aaaaa-aa' && + result[1] === 'delete_canister' + }; + } + }, + { + name: 'recursive funcs return', + test: async () => { + const result = await recursion_canister.testRecFuncReturn(); + + return { + Ok: + result[0].toString() === 'aaaaa-aa' && + result[1] === 'create_canister' + }; + } + }, { name: 'recursive records with vec', test: async () => { diff --git a/src/lib_functional/candid/reference/func.ts b/src/lib_functional/candid/reference/func.ts index b798e4e6e8..d5d091214e 100644 --- a/src/lib_functional/candid/reference/func.ts +++ b/src/lib_functional/candid/reference/func.ts @@ -1,7 +1,7 @@ import { CandidType } from '..'; import { IDL } from '@dfinity/candid'; import { - processMap, + Parent, toParamIDLTypes, toReturnIDLType } from '../../../lib_new/utils'; @@ -26,10 +26,10 @@ export function Func( // const name = v4(); return { - getIDL() { + getIDL(parents: Parent[]) { return IDL.Func( - toParamIDLTypes(paramsIdls), - toReturnIDLType(returnIdl), + toParamIDLTypes(paramsIdls, parents), + toReturnIDLType(returnIdl, parents), modeToCandid[mode] ); } diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index 692c28252a..193015e0fb 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -174,12 +174,18 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { return idl; } -export function toParamIDLTypes(idl: CandidClass[]): IDL.Type[] { - return idl.map((value) => toIDLType(value, [])); +export function toParamIDLTypes( + idl: CandidClass[], + parents: Parent[] = [] +): IDL.Type[] { + return idl.map((value) => toIDLType(value, parents)); } -export function toReturnIDLType(returnIdl: ReturnCandidClass): IDL.Type[] { - const idlType = toIDLType(returnIdl, []); +export function toReturnIDLType( + returnIdl: ReturnCandidClass, + parents: Parent[] +): IDL.Type[] { + const idlType = toIDLType(returnIdl, parents); if (Array.isArray(idlType)) { return [...idlType]; From 1b02f4ec48cbb2d27655b98db33e929ec2090a22 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 16:51:05 -0600 Subject: [PATCH 03/37] reset after rebase --- examples/recursion/src/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index 2e992cc0df..6d0a3f0ae2 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -110,6 +110,11 @@ export default Service({ Principal.fromText('aaaaa-aa'), 'create_canister' ]) + // testRecService: query([myService], myService, (param) => param), + // testRecServiceReturn: query([], myService, () => {}), + // testRecServiceCall: update([myService], myService, (myService) => { + // return await ic.call(myService.serviceQuery(myService)); + // }) }); // Below we have a bunch of different configurations of where to put the the From 802a040fb6ca6c593c9e9d3cc545b60659b284a7 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 21:42:26 -0600 Subject: [PATCH 04/37] update to Canister from Service --- examples/recursion/src/index.ts | 10 +++++----- src/lib_new/method_decorators.ts | 13 ++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index 6d0a3f0ae2..9237d9ab1b 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -4,7 +4,7 @@ import { None, Principal, query, - Service, + Canister, Some, text, Tuple, @@ -35,15 +35,15 @@ const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Vec can't be recursive by itself. At the end of it all it needs to have a concrete type. // Opt // Service -const myService = Recursive(() => - Service({ - serviceQuery: query([myService], myService, (param) => param) +const MyCanister = Recursive(() => + Canister({ + myQuery: query([MyCanister], MyCanister, (param) => param) }) ); // Func const myFunc = Recursive(() => Func([myFunc], myFunc, 'query')); -export default Service({ +export default Canister({ testRecRecordWithOpt: query([optRecord], optRecord, (param) => param), testRecRecordWithVec: query([vecRecord], vecRecord, (param) => param), testRecRecordWithVariant: query([varRecord], varRecord, (param) => param), diff --git a/src/lib_new/method_decorators.ts b/src/lib_new/method_decorators.ts index 78da74a66c..7040b915bb 100644 --- a/src/lib_new/method_decorators.ts +++ b/src/lib_new/method_decorators.ts @@ -8,7 +8,8 @@ import { toReturnIDLType, CandidTypesDefs, CandidDef, - extractCandid + extractCandid, + Parent } from './utils'; import { display } from './utils'; import { @@ -181,18 +182,20 @@ export function newTypesToStingArr(newTypes: CandidTypesDefs): string[] { } export function handleRecursiveParams( - idls: CandidClass[] + idls: CandidClass[], + parents: Parent[] = [] ): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const paramIdls = toParamIDLTypes(idls); + const paramIdls = toParamIDLTypes(idls, parents); const paramInfo = paramIdls.map((paramIdl) => display(paramIdl, {})); return [paramIdls, ...extractCandid(paramInfo, {})]; } export function handleRecursiveReturn( returnIdl: ReturnCandidClass, - paramCandidTypeDefs: CandidTypesDefs + paramCandidTypeDefs: CandidTypesDefs, + parents: Parent[] = [] ): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const returnIdls = toReturnIDLType(returnIdl); + const returnIdls = toReturnIDLType(returnIdl, parents); const returnInfo = returnIdls.map((returnIdl) => display(returnIdl, {})); return [returnIdls, ...extractCandid(returnInfo, paramCandidTypeDefs)]; } From 6ac4e1cd9a0f80315cfdc0fbc24c1d15fed2ce0c Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 21:56:02 -0600 Subject: [PATCH 05/37] add recursion to the tests --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e5fe6aec7..2a95608d7a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -115,6 +115,7 @@ jobs: "examples/principal", "examples/query", "examples/randomness", + "examples/recursion", "examples/rejections", "examples/robust_imports", "examples/simple_erc20", From f376128078ed2ac274ade71eb44f846b5e09848d Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Wed, 27 Sep 2023 21:59:39 -0600 Subject: [PATCH 06/37] update compression --- examples/recursion/dfx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/recursion/dfx.json b/examples/recursion/dfx.json index abc071e77c..a06bb1e7b6 100644 --- a/examples/recursion/dfx.json +++ b/examples/recursion/dfx.json @@ -5,7 +5,7 @@ "main": "src/index.ts", "build": "npx azle recursion", "candid": "src/index.did", - "wasm": ".azle/recursion/recursion.wasm.gz", + "wasm": ".azle/recursion/recursion.wasm", "declarations": { "output": "test/dfx_generated/recursion", "node_compatibility": true From 07153e8d9778b30f8480ec55a1e5da7d62e7b3a0 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 10:12:30 -0600 Subject: [PATCH 07/37] first pass at recursion --- examples/recursion/Cargo.lock | 950 ------------------ examples/recursion/Cargo.toml | 9 - examples/recursion/dfx.json | 1 + examples/recursion/src/index.ts | 17 +- examples/simple_user_accounts/src/index.did | 9 +- src/compiler/compile_typescript_code.ts | 2 +- .../candid/reference/recursive.ts | 18 +- .../candid/reference/service.ts | 463 +++++---- .../canister_methods/heartbeat.ts | 46 +- src/lib_functional/canister_methods/index.ts | 7 + src/lib_functional/canister_methods/init.ts | 65 +- .../canister_methods/inspect_message.ts | 59 +- .../canister_methods/post_upgrade.ts | 65 +- .../canister_methods/pre_upgrade.ts | 46 +- src/lib_functional/canister_methods/query.ts | 72 +- src/lib_functional/canister_methods/update.ts | 68 +- src/lib_new/visitors/encode_decode/index.ts | 6 +- 17 files changed, 518 insertions(+), 1385 deletions(-) delete mode 100644 examples/recursion/Cargo.lock delete mode 100644 examples/recursion/Cargo.toml diff --git a/examples/recursion/Cargo.lock b/examples/recursion/Cargo.lock deleted file mode 100644 index 666a952a04..0000000000 --- a/examples/recursion/Cargo.lock +++ /dev/null @@ -1,950 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base32" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" - -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" - -[[package]] -name = "binread" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" -dependencies = [ - "binread_derive", - "lazy_static", - "rustversion", -] - -[[package]] -name = "binread_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "candid" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9e536514a3c655568e23e36e68cbef20ee6595f641719ade03a849a13ed0ac" -dependencies = [ - "anyhow", - "binread", - "byteorder", - "candid_derive", - "codespan-reporting", - "hex", - "ic-types", - "lalrpop", - "lalrpop-util", - "leb128", - "logos", - "num-bigint", - "num-traits", - "num_enum", - "paste", - "pretty", - "serde", - "serde_bytes", - "thiserror", -] - -[[package]] -name = "candid_derive" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e02c03c4d547674a3f3f3109538fb49871fbe636216daa019f06a62faca9061" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "ic-cdk" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e471fa2e2464d4f9d676b81d33ae0d1cd190981166c53bbe4d536f13da281fc6" -dependencies = [ - "candid", - "cfg-if", - "serde", -] - -[[package]] -name = "ic-cdk-macros" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6d2c14db28f427154a52088077419edf1848e2bbd0f527dee3150e592a0863" -dependencies = [ - "candid", - "ic-cdk", - "proc-macro2", - "quote", - "serde", - "serde_tokenstream", - "syn", -] - -[[package]] -name = "ic-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e78ec6f58886cdc252d6f912dc794211bd6bbc39ddc9dcda434b2dc16c335b3" -dependencies = [ - "base32", - "crc32fast", - "hex", - "serde", - "serde_bytes", - "sha2", - "thiserror", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "lalrpop" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "logos" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" -dependencies = [ - "logos-derive", -] - -[[package]] -name = "logos-derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax", - "syn", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "paste" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61" -dependencies = [ - "arrayvec", - "typed-arena", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" -dependencies = [ - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "rust" -version = "0.0.0" -dependencies = [ - "ic-cdk", - "ic-cdk-macros", -] - -[[package]] -name = "rustversion" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_tokenstream" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6deb15c3a535e81438110111d90168d91721652f502abb147f31cde129f683d" -dependencies = [ - "proc-macro2", - "serde", - "syn", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "typed-arena" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/examples/recursion/Cargo.toml b/examples/recursion/Cargo.toml deleted file mode 100644 index 4513438de5..0000000000 --- a/examples/recursion/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[workspace] -members = [ - "canisters/rust", -] - -[profile.release] -lto = true -opt-level = 'z' -codegen-units = 1 diff --git a/examples/recursion/dfx.json b/examples/recursion/dfx.json index a06bb1e7b6..92138d06c2 100644 --- a/examples/recursion/dfx.json +++ b/examples/recursion/dfx.json @@ -6,6 +6,7 @@ "build": "npx azle recursion", "candid": "src/index.did", "wasm": ".azle/recursion/recursion.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/recursion", "node_compatibility": true diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index 9237d9ab1b..45dd0bba60 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -109,12 +109,17 @@ export default Canister({ testRecFuncReturn: query([], myFunc, () => [ Principal.fromText('aaaaa-aa'), 'create_canister' - ]) - // testRecService: query([myService], myService, (param) => param), - // testRecServiceReturn: query([], myService, () => {}), - // testRecServiceCall: update([myService], myService, (myService) => { - // return await ic.call(myService.serviceQuery(myService)); - // }) + ]), + testRecService: query([MyCanister], MyCanister, (param) => param), + testRecServiceReturn: query([], MyCanister, () => { + MyCanister( + Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? + ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + ); + }), + testRecServiceCall: update([MyCanister], MyCanister, async (myCanister) => { + return await ic.call(myCanister.myQuery(myCanister)); + }) }); // Below we have a bunch of different configurations of where to put the the diff --git a/examples/simple_user_accounts/src/index.did b/examples/simple_user_accounts/src/index.did index bfcfd23d19..1fe0dd0102 100644 --- a/examples/simple_user_accounts/src/index.did +++ b/examples/simple_user_accounts/src/index.did @@ -1,8 +1,5 @@ -type rec_0 = record {id:text; username:text}; -type rec_1 = record {id:text; username:text}; -type rec_2 = record {id:text; username:text}; service: () -> { - getUserById: (text) -> (opt rec_0) query; - getAllUsers: () -> (vec rec_1) query; - createUser: (text) -> (rec_2); + getUserById: (text) -> (opt record {id:text; username:text}) query; + getAllUsers: () -> (vec record {id:text; username:text}) query; + createUser: (text) -> (record {id:text; username:text}); } diff --git a/src/compiler/compile_typescript_code.ts b/src/compiler/compile_typescript_code.ts index 621a2215f9..790e11d844 100644 --- a/src/compiler/compile_typescript_code.ts +++ b/src/compiler/compile_typescript_code.ts @@ -35,7 +35,7 @@ export function compileTypeScriptToJavaScript( export * from './${main}'; import CanisterMethods from './${main}'; - export const canisterMethods = CanisterMethods; + export const canisterMethods = CanisterMethods(); `; const canisterJavaScript = bundleAndTranspileJs(` diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index be571a6be7..22b058c9c6 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -2,16 +2,28 @@ import { v4 } from 'uuid'; import { IDL } from '@dfinity/candid'; import { Parent } from '../../../lib_new/utils'; -export function Recursive(idlCallback: any) { +export interface RecursiveResult { + idlCallback: () => any; + _azleName: string; + getIDL(parents: Parent[]): any; +} + +export function Recursive(idlCallback: any): RecursiveResult { const name = v4(); - return { + const result = { idlCallback, _azleName: name, getIDL(parents: Parent[]) { const idl = IDL.Rec(); - idl.fill(idlCallback().getIDL([...parents, { idl: idl, name }])); + let filler = idlCallback(); + if (filler._azleIsCanister) { + filler = filler(result); + } + idl.fill(filler.getIDL([...parents, { idl: idl, name }])); return idl; } }; + + return result; } diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index 3e01aaa94f..8a209baf31 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -1,4 +1,4 @@ -import { Principal, TypeMapping } from '../../'; +import { Principal, RecursiveResult, TypeMapping } from '../../'; import { IDL, ServiceFunctionInfo, @@ -34,138 +34,16 @@ type CallableObject = { export function Canister( serviceOptions: T ): CallableObject & { _azleCandidType?: '_azleCandidType' } { - const callbacks = Object.entries(serviceOptions).reduce((acc, entry) => { - const key = entry[0]; - const value = entry[1]; - - // if (principal === undefined) { - // return { - // ...acc, - // [key]: (...args: any[]) => { - // return serviceCall( - // principal as any, - // key, - // value.paramsIdls, - // value.returnIdl - // )(...args); - // } - // }; - // } else { - return { - ...acc, - [key]: { - canisterCallback: value.callback, - crossCanisterCallback: (...args: any[]) => { - return serviceCall( - this.principal as any, - key, - value.paramsIdls, - value.returnIdl - )(...args); - } - } - }; - // } - }, {}); - - // TODO Once types have names we should deduplicate the init and post_upgrade param types - const candidTypes = Object.values(serviceOptions).reduce( - (acc: string[], canisterMethodInfo) => { - return [...acc, ...canisterMethodInfo.candidTypes]; - }, - [] - ); - - const initOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'init' - ); - const init = - initOption === undefined - ? undefined - : { - name: initOption[0] - }; - - const postUpgradeOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'postUpgrade' - ); - const postUpgrade = - postUpgradeOption === undefined - ? undefined - : { - name: postUpgradeOption[0] - }; - - const preUpgradeOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'preUpgrade' - ); - const preUpgrade = - preUpgradeOption === undefined - ? undefined - : { - name: preUpgradeOption[0] - }; - - const heartbeatOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'heartbeat' - ); - const heartbeat = - heartbeatOption === undefined - ? undefined - : { - name: heartbeatOption[0] - }; - - const inspectMessageOption = Object.entries(serviceOptions).find( - ([key, value]) => value.mode === 'inspectMessage' - ); - const inspectMessage = - inspectMessageOption === undefined - ? undefined - : { - name: inspectMessageOption[0] - }; - - const queries = Object.entries(serviceOptions) - .filter((entry) => { - const key = entry[0]; - const value = entry[1]; - - return value.mode === 'query'; - }) - .map((entry) => { - const key = entry[0]; - const value = entry[1]; - - return { - name: key, - composite: value.async, - guard_name: createGlobalGuard(value.guard, key) - }; - }); - - const updates = Object.entries(serviceOptions) - .filter((entry) => { - const key = entry[0]; - const value = entry[1]; - - return value.mode === 'update'; - }) - .map((entry) => { - const key = entry[0]; - const value = entry[1]; - - return { - name: key, - guard_name: createGlobalGuard(value.guard, key) - }; - }); - - let returnFunction = (principal: Principal) => { + let result = (parentOrPrincipal: RecursiveResult | Principal) => { + const originalPrincipal = parentOrPrincipal; + const parentOrUndefined = + parentOrPrincipal instanceof Principal + ? undefined + : parentOrPrincipal; const callbacks = Object.entries(serviceOptions).reduce( (acc, entry) => { const key = entry[0]; - const value = entry[1]; + const value = entry[1](parentOrUndefined); // if (principal === undefined) { // return { @@ -186,7 +64,7 @@ export function Canister( canisterCallback: value.callback, crossCanisterCallback: (...args: any[]) => { return serviceCall( - principal as any, + this.principal as any, key, value.paramsIdls, value.returnIdl @@ -199,104 +77,255 @@ export function Canister( {} ); - return { - ...callbacks, - principal + // TODO Once types have names we should deduplicate the init and post_upgrade param types + const candidTypes = Object.values(serviceOptions).reduce( + (acc: string[], canisterMethodInfo) => { + return [ + ...acc, + ...canisterMethodInfo(parentOrUndefined).candidTypes + ]; + }, + [] + ); + + const initOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'init' + ); + const init = + initOption === undefined + ? undefined + : { + name: initOption[0] + }; + + const postUpgradeOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'postUpgrade' + ); + const postUpgrade = + postUpgradeOption === undefined + ? undefined + : { + name: postUpgradeOption[0] + }; + + const preUpgradeOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'preUpgrade' + ); + const preUpgrade = + preUpgradeOption === undefined + ? undefined + : { + name: preUpgradeOption[0] + }; + + const heartbeatOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'heartbeat' + ); + const heartbeat = + heartbeatOption === undefined + ? undefined + : { + name: heartbeatOption[0] + }; + + const inspectMessageOption = Object.entries(serviceOptions).find( + ([key, value]) => value(parentOrUndefined).mode === 'inspectMessage' + ); + const inspectMessage = + inspectMessageOption === undefined + ? undefined + : { + name: inspectMessageOption[0] + }; + + const queries = Object.entries(serviceOptions) + .filter((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return value.mode === 'query'; + }) + .map((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return { + name: key, + composite: value.async, + guard_name: createGlobalGuard(value.guard, key) + }; + }); + + const updates = Object.entries(serviceOptions) + .filter((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return value.mode === 'update'; + }) + .map((entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + return { + name: key, + guard_name: createGlobalGuard(value.guard, key) + }; + }); + + let returnFunction = (principal: Principal) => { + const callbacks = Object.entries(serviceOptions).reduce( + (acc, entry) => { + const key = entry[0]; + const value = entry[1](parentOrUndefined); + + // if (principal === undefined) { + // return { + // ...acc, + // [key]: (...args: any[]) => { + // return serviceCall( + // principal as any, + // key, + // value.paramsIdls, + // value.returnIdl + // )(...args); + // } + // }; + // } else { + return { + ...acc, + [key]: { + canisterCallback: value.callback, + crossCanisterCallback: (...args: any[]) => { + return serviceCall( + principal as any, + key, + value.paramsIdls, + value.returnIdl + )(...args); + } + } + }; + // } + }, + {} + ); + + return { + ...callbacks, + principal + }; }; - }; - returnFunction.candid = `${ - candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - }service: (${initOption?.[1].candid ?? ''}) -> { + returnFunction.candid = `${ + candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' + }service: (${initOption?.[1].candid ?? ''}) -> { ${Object.entries(serviceOptions) .filter( - ([_, value]) => value.mode === 'query' || value.mode === 'update' + ([_, value]) => + value(parentOrUndefined).mode === 'query' || + value(parentOrUndefined).mode === 'update' ) .map((entry) => { - return `${entry[0]}: ${entry[1].candid}`; + return `${entry[0]}: ${entry[1](parentOrUndefined).candid}`; }) .join('\n ')} } `; - returnFunction.init = init; - returnFunction.post_upgrade = postUpgrade; - returnFunction.pre_upgrade = preUpgrade; - returnFunction.heartbeat = heartbeat; - returnFunction.inspect_message = inspectMessage; - returnFunction.queries = queries; - returnFunction.updates = updates; - returnFunction.callbacks = callbacks; - returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { - const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - const record = Object.entries(serviceFunctionInfo).reduce( - (accumulator, [methodName, functionInfo]) => { - const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); - const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); - - const annotations = - functionInfo.mode === 'update' ? [] : ['query']; + returnFunction.init = init; + returnFunction.post_upgrade = postUpgrade; + returnFunction.pre_upgrade = preUpgrade; + returnFunction.heartbeat = heartbeat; + returnFunction.inspect_message = inspectMessage; + returnFunction.queries = queries; + returnFunction.updates = updates; + returnFunction.callbacks = callbacks; + returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { + const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + + const record = Object.entries(serviceFunctionInfo).reduce( + (accumulator, [methodName, functionInfo]) => { + const paramRealIdls = toParamIDLTypes( + functionInfo(parentOrUndefined).paramsIdls, + parents + ); + const returnRealIdl = toReturnIDLType( + functionInfo(parentOrUndefined).returnIdl, + parents + ); + + const annotations = + functionInfo(parentOrUndefined).mode === 'update' + ? [] + : ['query']; + + return { + ...accumulator, + [methodName]: IDL.Func( + paramRealIdls, + returnRealIdl, + annotations + ) + }; + }, + {} as Record + ); + + return IDL.Service(record); + }; - return { - ...accumulator, - [methodName]: IDL.Func( - paramRealIdls, - returnRealIdl, - annotations - ) - }; - }, - {} as Record - ); + if (originalPrincipal instanceof Principal) { + return returnFunction(originalPrincipal); + } - return IDL.Service(record); - }; + return returnFunction; - return returnFunction; - - // TODO loop through each key and simply grab the candid off - // TODO grab the init/post_upgrade candid as well - // return { - // candid: `${ - // candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - // }service: () -> { - // ${Object.entries(serviceOptions) - // .map((entry) => { - // return `${entry[0]}: ${entry[1].candid}`; - // }) - // .join('\n ')} - // } - // `, - // queries, - // updates, - // callbacks, - // principal, - // ...callbacks, // TODO then we can't use any names that could collide in this object - // getIDL(parents: Parent[]): IDL.ServiceClass { - // const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - - // const record = Object.entries(serviceFunctionInfo).reduce( - // (accumulator, [methodName, functionInfo]) => { - // const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); - // const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); - - // const annotations = - // functionInfo.mode === 'update' ? [] : ['query']; - - // return { - // ...accumulator, - // [methodName]: IDL.Func( - // paramRealIdls, - // returnRealIdl, - // annotations - // ) - // }; - // }, - // {} as Record - // ); - - // return IDL.Service(record); - // } - // } as any; + // TODO loop through each key and simply grab the candid off + // TODO grab the init/post_upgrade candid as well + // return { + // candid: `${ + // candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' + // }service: () -> { + // ${Object.entries(serviceOptions) + // .map((entry) => { + // return `${entry[0]}: ${entry[1].candid}`; + // }) + // .join('\n ')} + // } + // `, + // queries, + // updates, + // callbacks, + // principal, + // ...callbacks, // TODO then we can't use any names that could collide in this object + // getIDL(parents: Parent[]): IDL.ServiceClass { + // const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; + + // const record = Object.entries(serviceFunctionInfo).reduce( + // (accumulator, [methodName, functionInfo]) => { + // const paramRealIdls = toParamIDLTypes(functionInfo.paramsIdls); + // const returnRealIdl = toReturnIDLType(functionInfo.returnIdl); + + // const annotations = + // functionInfo.mode === 'update' ? [] : ['query']; + + // return { + // ...accumulator, + // [methodName]: IDL.Func( + // paramRealIdls, + // returnRealIdl, + // annotations + // ) + // }; + // }, + // {} as Record + // ); + + // return IDL.Service(record); + // } + // } as any; + }; + result._azleIsCanister = true; + return result; } diff --git a/src/lib_functional/canister_methods/heartbeat.ts b/src/lib_functional/canister_methods/heartbeat.ts index bc2bf0b897..d0037f6a09 100644 --- a/src/lib_functional/canister_methods/heartbeat.ts +++ b/src/lib_functional/canister_methods/heartbeat.ts @@ -4,28 +4,30 @@ import { Void } from '../../lib_new'; export function heartbeat( callback: () => void | Promise -): CanisterMethodInfo<[], Void> { - const finalCallback = (...args: any[]) => { - executeMethod( - 'heartbeat', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); - }; +): () => CanisterMethodInfo<[], Void> { + return () => { + const finalCallback = (...args: any[]) => { + executeMethod( + 'heartbeat', + undefined, + undefined, + args, + callback, + [], + Void, + false + ); + }; - return { - mode: 'heartbeat', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: isAsync(callback), - guard: undefined + return { + mode: 'heartbeat', + callback: finalCallback, + candid: '', + candidTypes: [], + paramsIdls: [], + returnIdl: Void, + async: isAsync(callback), + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/index.ts b/src/lib_functional/canister_methods/index.ts index e9ad5d98ad..8e968c09c0 100644 --- a/src/lib_functional/canister_methods/index.ts +++ b/src/lib_functional/canister_methods/index.ts @@ -5,6 +5,7 @@ import { DecodeVisitor, EncodeVisitor } from '../../lib_new/visitors/encode_decode'; +import { Parent } from '../../lib_new/utils'; export * from './heartbeat'; export * from './init'; @@ -137,3 +138,9 @@ export function executeMethod( console.log(`final instructions: ${ic.instructionCounter()}`); } } + +export function createParents(parent: any): Parent[] { + return parent === undefined + ? [] + : [{ idl: parent, name: parent._azleName }]; +} diff --git a/src/lib_functional/canister_methods/init.ts b/src/lib_functional/canister_methods/init.ts index 767caaa314..5700305d37 100644 --- a/src/lib_functional/canister_methods/init.ts +++ b/src/lib_functional/canister_methods/init.ts @@ -3,8 +3,8 @@ import { handleRecursiveReturn, newTypesToStingArr } from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; -import { CandidType, TypeMapping } from '../candid'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; +import { CandidType, RecursiveResult, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; export function init< @@ -15,34 +15,41 @@ export function init< callback?: Awaited> extends TypeMapping ? GenericCallback : never -): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); +): (parent: RecursiveResult) => CanisterMethodInfo { + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = handleRecursiveParams(paramsIdls as any, parents); + const returnCandid = handleRecursiveReturn( + Void as any, + paramCandid[2], + parents + ); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'init', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - Void, - false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'init', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + Void, + false + ); + }; - return { - mode: 'init', - callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl: Void, - async: false, - guard: undefined + return { + mode: 'init', + callback: finalCallback, + candid: paramCandid[1].join(', '), + candidTypes: newTypesToStingArr(returnCandid[2]), + paramsIdls: paramsIdls as any, + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/inspect_message.ts b/src/lib_functional/canister_methods/inspect_message.ts index d1617ffc79..24642c2298 100644 --- a/src/lib_functional/canister_methods/inspect_message.ts +++ b/src/lib_functional/canister_methods/inspect_message.ts @@ -1,37 +1,46 @@ -import { CanisterMethodInfo, executeMethod } from '.'; +import { CanisterMethodInfo, createParents, executeMethod } from '.'; import { Void, handleRecursiveParams, handleRecursiveReturn } from '../../lib_new'; +import { RecursiveResult } from '../candid'; export function inspectMessage( callback: () => void | Promise -): CanisterMethodInfo<[], Void> { - const paramCandid = handleRecursiveParams([]); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); - - const finalCallback = (...args: any[]) => { - executeMethod( - 'inspectMessage', - paramCandid, - returnCandid, - args, - callback, - [], - Void, - false +): (parent: RecursiveResult) => CanisterMethodInfo<[], Void> { + return (parent: any) => { + const parents = createParents(parent); + // TODO why are we doing this handle recursive params when there are none? + const paramCandid = handleRecursiveParams([], parents); + const returnCandid = handleRecursiveReturn( + Void as any, + paramCandid[2], + parents ); - }; - return { - mode: 'inspectMessage', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: false, - guard: undefined + const finalCallback = (...args: any[]) => { + executeMethod( + 'inspectMessage', + paramCandid, + returnCandid, + args, + callback, + [], + Void, + false + ); + }; + + return { + mode: 'inspectMessage', + callback: finalCallback, + candid: '', + candidTypes: [], + paramsIdls: [], + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/post_upgrade.ts b/src/lib_functional/canister_methods/post_upgrade.ts index dd54c7a2a6..d4b5a0929b 100644 --- a/src/lib_functional/canister_methods/post_upgrade.ts +++ b/src/lib_functional/canister_methods/post_upgrade.ts @@ -3,8 +3,8 @@ import { handleRecursiveReturn, newTypesToStingArr } from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; -import { CandidType, TypeMapping } from '../candid'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; +import { CandidType, RecursiveResult, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; export function postUpgrade< @@ -15,34 +15,41 @@ export function postUpgrade< callback?: Awaited> extends TypeMapping ? GenericCallback : never -): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn(Void as any, paramCandid[2]); +): (parent: RecursiveResult) => CanisterMethodInfo { + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = handleRecursiveParams(paramsIdls as any, parents); + const returnCandid = handleRecursiveReturn( + Void as any, + paramCandid[2], + parents + ); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'postUpgrade', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - Void, - false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'postUpgrade', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + Void, + false + ); + }; - return { - mode: 'postUpgrade', - callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl: Void, - async: false, - guard: undefined + return { + mode: 'postUpgrade', + callback: finalCallback, + candid: paramCandid[1].join(', '), + candidTypes: newTypesToStingArr(returnCandid[2]), + paramsIdls: paramsIdls as any, + returnIdl: Void, + async: false, + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/pre_upgrade.ts b/src/lib_functional/canister_methods/pre_upgrade.ts index c1a7acb4d5..e1247285a9 100644 --- a/src/lib_functional/canister_methods/pre_upgrade.ts +++ b/src/lib_functional/canister_methods/pre_upgrade.ts @@ -4,28 +4,30 @@ import { Void } from '../../lib_new'; export function preUpgrade( callback: () => void | Promise -): CanisterMethodInfo<[], Void> { - const finalCallback = (...args: any[]) => { - executeMethod( - 'preUpgrade', - undefined, - undefined, - args, - callback, - [], - Void, - false - ); - }; +): () => CanisterMethodInfo<[], Void> { + return () => { + const finalCallback = (...args: any[]) => { + executeMethod( + 'preUpgrade', + undefined, + undefined, + args, + callback, + [], + Void, + false + ); + }; - return { - mode: 'preUpgrade', - callback: finalCallback, - candid: '', - candidTypes: [], - paramsIdls: [], - returnIdl: Void, - async: isAsync(callback), - guard: undefined + return { + mode: 'preUpgrade', + callback: finalCallback, + candid: '', + candidTypes: [], + paramsIdls: [], + returnIdl: Void, + async: isAsync(callback), + guard: undefined + }; }; } diff --git a/src/lib_functional/canister_methods/query.ts b/src/lib_functional/canister_methods/query.ts index b0802bbb9d..99f654b0b0 100644 --- a/src/lib_functional/canister_methods/query.ts +++ b/src/lib_functional/canister_methods/query.ts @@ -5,8 +5,8 @@ import { isAsync, newTypesToStingArr } from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; -import { CandidType, TypeMapping } from '../candid'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; +import { CandidType, RecursiveResult, TypeMapping } from '../candid'; export function query< const Params extends ReadonlyArray, @@ -19,38 +19,44 @@ export function query< ? GenericCallback : never, methodArgs?: MethodArgs -): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2] - ); +): (parent: RecursiveResult) => CanisterMethodInfo { + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = handleRecursiveParams(paramsIdls as any, parents); + const returnCandid = handleRecursiveReturn( + returnIdl as any, + paramCandid[2], + parents + ); - // TODO maybe the cross canister callback should be made here? - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'query', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - returnIdl, - methodArgs?.manual ?? false - ); - }; + // TODO maybe the cross canister callback should be made here? + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'query', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + returnIdl, + methodArgs?.manual ?? false + ); + }; - return { - mode: 'query', - callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]}) query;`, - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl, - async: callback === undefined ? false : isAsync(callback), - guard: methodArgs?.guard + return { + mode: 'query', + callback: finalCallback, + candid: `(${paramCandid[1].join(', ')}) -> (${ + returnCandid[1] + }) query;`, + candidTypes: newTypesToStingArr(returnCandid[2]), + paramsIdls: paramsIdls as any, + returnIdl, + async: callback === undefined ? false : isAsync(callback), + guard: methodArgs?.guard + }; }; } diff --git a/src/lib_functional/canister_methods/update.ts b/src/lib_functional/canister_methods/update.ts index 9e2046ec8c..810ad22229 100644 --- a/src/lib_functional/canister_methods/update.ts +++ b/src/lib_functional/canister_methods/update.ts @@ -5,8 +5,8 @@ import { isAsync, newTypesToStingArr } from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, executeMethod } from '.'; -import { CandidType, TypeMapping } from '../candid'; +import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; +import { CandidType, RecursiveResult, TypeMapping } from '../candid'; export function update< const Params extends ReadonlyArray, @@ -19,37 +19,41 @@ export function update< ? GenericCallback : never, methodArgs?: MethodArgs -): CanisterMethodInfo { - const paramCandid = handleRecursiveParams(paramsIdls as any); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2] - ); +): (parent: RecursiveResult) => CanisterMethodInfo { + return (parent: any) => { + const parents = createParents(parent); + const paramCandid = handleRecursiveParams(paramsIdls as any, parents); + const returnCandid = handleRecursiveReturn( + returnIdl as any, + paramCandid[2], + parents + ); - const finalCallback = - callback === undefined - ? undefined - : (...args: any[]) => { - executeMethod( - 'update', - paramCandid, - returnCandid, - args, - callback, - paramsIdls as any, - returnIdl, - methodArgs?.manual ?? false - ); - }; + const finalCallback = + callback === undefined + ? undefined + : (...args: any[]) => { + executeMethod( + 'update', + paramCandid, + returnCandid, + args, + callback, + paramsIdls as any, + returnIdl, + methodArgs?.manual ?? false + ); + }; - return { - mode: 'update', - callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]});`, - candidTypes: newTypesToStingArr(returnCandid[2]), - paramsIdls: paramsIdls as any, - returnIdl, - async: callback === undefined ? false : isAsync(callback), - guard: methodArgs?.guard + return { + mode: 'update', + callback: finalCallback, + candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]});`, + candidTypes: newTypesToStingArr(returnCandid[2]), + paramsIdls: paramsIdls as any, + returnIdl, + async: callback === undefined ? false : isAsync(callback), + guard: methodArgs?.guard + }; }; } diff --git a/src/lib_new/visitors/encode_decode/index.ts b/src/lib_new/visitors/encode_decode/index.ts index 06f7c419d9..4fe48c4658 100644 --- a/src/lib_new/visitors/encode_decode/index.ts +++ b/src/lib_new/visitors/encode_decode/index.ts @@ -142,8 +142,12 @@ export function visitRec( ty: IDL.ConstructType, data: VisitorData ): VisitorResult { + let js_class = data.js_class.idlCallback(); + if (js_class._azleIsCanister) { + js_class = js_class([]); + } return ty.accept(visitor, { ...data, - js_class: data.js_class.idlCallback() + js_class }); } From eb2900a596ba4c4d039e1bc259012ffbc781a554 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 18:29:00 -0600 Subject: [PATCH 08/37] better typing --- src/lib_functional/candid/reference/recursive.ts | 8 +------- src/lib_functional/candid/reference/service.ts | 4 ++-- src/lib_functional/canister_methods/init.ts | 4 ++-- src/lib_functional/canister_methods/inspect_message.ts | 4 ++-- src/lib_functional/canister_methods/post_upgrade.ts | 4 ++-- src/lib_functional/canister_methods/query.ts | 4 ++-- src/lib_functional/canister_methods/update.ts | 4 ++-- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index 22b058c9c6..dd027ba0cc 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -2,13 +2,7 @@ import { v4 } from 'uuid'; import { IDL } from '@dfinity/candid'; import { Parent } from '../../../lib_new/utils'; -export interface RecursiveResult { - idlCallback: () => any; - _azleName: string; - getIDL(parents: Parent[]): any; -} - -export function Recursive(idlCallback: any): RecursiveResult { +export function Recursive any>(idlCallback: T): T { const name = v4(); const result = { diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index 8a209baf31..a1bad521ec 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -1,4 +1,4 @@ -import { Principal, RecursiveResult, TypeMapping } from '../../'; +import { Principal, TypeMapping } from '../../'; import { IDL, ServiceFunctionInfo, @@ -34,7 +34,7 @@ type CallableObject = { export function Canister( serviceOptions: T ): CallableObject & { _azleCandidType?: '_azleCandidType' } { - let result = (parentOrPrincipal: RecursiveResult | Principal) => { + let result = (parentOrPrincipal: any) => { const originalPrincipal = parentOrPrincipal; const parentOrUndefined = parentOrPrincipal instanceof Principal diff --git a/src/lib_functional/canister_methods/init.ts b/src/lib_functional/canister_methods/init.ts index 5700305d37..f29bf22b89 100644 --- a/src/lib_functional/canister_methods/init.ts +++ b/src/lib_functional/canister_methods/init.ts @@ -4,7 +4,7 @@ import { newTypesToStingArr } from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; -import { CandidType, RecursiveResult, TypeMapping } from '../candid'; +import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; export function init< @@ -15,7 +15,7 @@ export function init< callback?: Awaited> extends TypeMapping ? GenericCallback : never -): (parent: RecursiveResult) => CanisterMethodInfo { +): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); const paramCandid = handleRecursiveParams(paramsIdls as any, parents); diff --git a/src/lib_functional/canister_methods/inspect_message.ts b/src/lib_functional/canister_methods/inspect_message.ts index 24642c2298..cd228c803d 100644 --- a/src/lib_functional/canister_methods/inspect_message.ts +++ b/src/lib_functional/canister_methods/inspect_message.ts @@ -4,11 +4,11 @@ import { handleRecursiveParams, handleRecursiveReturn } from '../../lib_new'; -import { RecursiveResult } from '../candid'; +import { RecursiveType } from '../candid'; export function inspectMessage( callback: () => void | Promise -): (parent: RecursiveResult) => CanisterMethodInfo<[], Void> { +): CanisterMethodInfo<[], Void> { return (parent: any) => { const parents = createParents(parent); // TODO why are we doing this handle recursive params when there are none? diff --git a/src/lib_functional/canister_methods/post_upgrade.ts b/src/lib_functional/canister_methods/post_upgrade.ts index d4b5a0929b..098d676d8b 100644 --- a/src/lib_functional/canister_methods/post_upgrade.ts +++ b/src/lib_functional/canister_methods/post_upgrade.ts @@ -4,7 +4,7 @@ import { newTypesToStingArr } from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; -import { CandidType, RecursiveResult, TypeMapping } from '../candid'; +import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; export function postUpgrade< @@ -15,7 +15,7 @@ export function postUpgrade< callback?: Awaited> extends TypeMapping ? GenericCallback : never -): (parent: RecursiveResult) => CanisterMethodInfo { +): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); const paramCandid = handleRecursiveParams(paramsIdls as any, parents); diff --git a/src/lib_functional/canister_methods/query.ts b/src/lib_functional/canister_methods/query.ts index 99f654b0b0..5f0e5eaa01 100644 --- a/src/lib_functional/canister_methods/query.ts +++ b/src/lib_functional/canister_methods/query.ts @@ -6,7 +6,7 @@ import { newTypesToStingArr } from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; -import { CandidType, RecursiveResult, TypeMapping } from '../candid'; +import { CandidType, RecursiveType, TypeMapping } from '../candid'; export function query< const Params extends ReadonlyArray, @@ -19,7 +19,7 @@ export function query< ? GenericCallback : never, methodArgs?: MethodArgs -): (parent: RecursiveResult) => CanisterMethodInfo { +): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); const paramCandid = handleRecursiveParams(paramsIdls as any, parents); diff --git a/src/lib_functional/canister_methods/update.ts b/src/lib_functional/canister_methods/update.ts index 810ad22229..1367024bab 100644 --- a/src/lib_functional/canister_methods/update.ts +++ b/src/lib_functional/canister_methods/update.ts @@ -6,7 +6,7 @@ import { newTypesToStingArr } from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; -import { CandidType, RecursiveResult, TypeMapping } from '../candid'; +import { CandidType, RecursiveType, TypeMapping } from '../candid'; export function update< const Params extends ReadonlyArray, @@ -19,7 +19,7 @@ export function update< ? GenericCallback : never, methodArgs?: MethodArgs -): (parent: RecursiveResult) => CanisterMethodInfo { +): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); const paramCandid = handleRecursiveParams(paramsIdls as any, parents); From 2377bc190416f29203423f5371d4b5a701b45ba8 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 18:29:44 -0600 Subject: [PATCH 09/37] clean up imports --- examples/recursion/src/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index 45dd0bba60..4eb884d77a 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -6,11 +6,9 @@ import { query, Canister, Some, - text, Tuple, update, - Vec, - Void + Vec } from 'azle'; import { Record, Recursive, int8, Variant, Opt } from 'azle'; From efe2a35ae46d55d7c7fafd8d78f35535ac56fc70 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 20:07:01 -0600 Subject: [PATCH 10/37] implement DidVisitor --- examples/recursion/src/index.did | 100 +++++++++++------- .../generate_candid_and_canister_methods.ts | 14 ++- src/lib_new/visitors/did_visitor.ts | 40 +++++-- 3 files changed, 106 insertions(+), 48 deletions(-) diff --git a/examples/recursion/src/index.did b/examples/recursion/src/index.did index da66aa4c1b..c829973098 100644 --- a/examples/recursion/src/index.did +++ b/examples/recursion/src/index.did @@ -1,42 +1,60 @@ -type rec_0 = record {myOpt:opt rec_0}; -type rec_1 = record {myOpt:opt rec_1}; -type rec_2 = record {myVecRecords:vec rec_2}; -type rec_3 = record {myVecRecords:vec rec_3}; -type rec_4 = record {myVar:variant {num:int8; varRec:rec_4}}; -type rec_5 = record {myVar:variant {num:int8; varRec:rec_5}}; -type rec_6 = variant {num:int8; recVariant:rec_6}; -type rec_7 = variant {num:int8; recVariant:rec_7}; -type rec_8 = record {opt rec_8; opt rec_8}; -type rec_9 = record {opt rec_9; opt rec_9}; -type rec_10 = record {vec rec_10; vec rec_10}; -type rec_11 = record {vec rec_11; vec rec_11}; -type rec_12 = record {myOpt:opt rec_12}; -type rec_13 = record {myVecRecords:vec rec_13}; -type rec_14 = record {myVar:variant {num:int8; varRec:rec_14}}; -type rec_15 = variant {num:int8; recVariant:rec_15}; -type rec_16 = record {opt rec_16; opt rec_16}; -type rec_17 = record {vec rec_17; vec rec_17}; -type rec_18 = record {variant {num:int8; varTuple:rec_18}; variant {num:int8; varTuple:rec_18}}; -type rec_19 = record {variant {num:int8; varTuple:rec_19}; variant {num:int8; varTuple:rec_19}}; -type rec_20 = record {variant {num:int8; varTuple:rec_20}; variant {num:int8; varTuple:rec_20}}; -type rec_21 = func (rec_21) -> (rec_21) query; -type rec_22 = func (rec_22) -> (rec_22) query; -type rec_23 = func (rec_23) -> (rec_23) query; +type rec_291 = func (rec_291) -> (rec_291) query; +type rec_294 = func (rec_294) -> (rec_294) query; +type rec_299 = func (rec_299) -> (rec_299) query; +type rec_207 = record {myOpt:opt rec_207}; +type rec_210 = record {myOpt:opt rec_210}; +type rec_255 = record {myOpt:opt rec_255}; +type rec_223 = record {myVar:variant {num:int8; varRec:rec_223}}; +type rec_226 = record {myVar:variant {num:int8; varRec:rec_226}}; +type rec_263 = record {myVar:variant {num:int8; varRec:rec_263}}; +type rec_215 = record {myVecRecords:vec rec_215}; +type rec_218 = record {myVecRecords:vec rec_218}; +type rec_259 = record {myVecRecords:vec rec_259}; +type rec_303 = service { + myQuery: (rec_303) -> (rec_303) query; +}; +type rec_306 = service { + myQuery: (rec_306) -> (rec_306) query; +}; +type rec_315 = service { + myQuery: (rec_315) -> (rec_315) query; +}; +type rec_318 = service { + myQuery: (rec_318) -> (rec_318) query; +}; +type rec_311 = service { + myQuery: (rec_311) -> (rec_311) query; +}; +type rec_239 = record {opt rec_239; opt rec_239}; +type rec_242 = record {opt rec_242; opt rec_242}; +type rec_271 = record {opt rec_271; opt rec_271}; +type rec_279 = record {variant {num:int8; varTuple:rec_279}; variant {num:int8; varTuple:rec_279}}; +type rec_282 = record {variant {num:int8; varTuple:rec_282}; variant {num:int8; varTuple:rec_282}}; +type rec_287 = record {variant {num:int8; varTuple:rec_287}; variant {num:int8; varTuple:rec_287}}; +type rec_247 = record {vec rec_247; vec rec_247}; +type rec_250 = record {vec rec_250; vec rec_250}; +type rec_275 = record {vec rec_275; vec rec_275}; +type rec_231 = variant {num:int8; recVariant:rec_231}; +type rec_234 = variant {num:int8; recVariant:rec_234}; +type rec_267 = variant {num:int8; recVariant:rec_267}; service: () -> { - testRecRecordWithOpt: (rec_0) -> (rec_1) query; - testRecRecordWithVec: (rec_2) -> (rec_3) query; - testRecRecordWithVariant: (rec_4) -> (rec_5) query; - testRecVariant: (rec_6) -> (rec_7) query; - testRecTupleWithOpt: (rec_8) -> (rec_9) query; - testRecTupleWithVec: (rec_10) -> (rec_11) query; - testRecRecordWithOptReturn: () -> (rec_12) query; - testRecRecordWithVecReturn: () -> (rec_13) query; - testRecRecordWithVariantReturn: () -> (rec_14) query; - testRecVariantReturn: () -> (rec_15) query; - testRecTupleWithOptReturn: () -> (rec_16) query; - testRecTupleWithVecReturn: () -> (rec_17) query; - testRecTupleWithVariant: (rec_18) -> (rec_19) query; - testRecTupleWithVariantReturn: () -> (rec_20) query; - testRecFunc: (rec_21) -> (rec_22) query; - testRecFuncReturn: () -> (rec_23) query; -} + testRecFunc: (rec_291) -> (rec_294) query; + testRecFuncReturn: () -> (rec_299) query; + testRecRecordWithOpt: (rec_207) -> (rec_210) query; + testRecRecordWithOptReturn: () -> (rec_255) query; + testRecRecordWithVariant: (rec_223) -> (rec_226) query; + testRecRecordWithVariantReturn: () -> (rec_263) query; + testRecRecordWithVec: (rec_215) -> (rec_218) query; + testRecRecordWithVecReturn: () -> (rec_259) query; + testRecService: (rec_303) -> (rec_306) query; + testRecServiceCall: (rec_315) -> (rec_318) ; + testRecServiceReturn: () -> (rec_311) query; + testRecTupleWithOpt: (rec_239) -> (rec_242) query; + testRecTupleWithOptReturn: () -> (rec_271) query; + testRecTupleWithVariant: (rec_279) -> (rec_282) query; + testRecTupleWithVariantReturn: () -> (rec_287) query; + testRecTupleWithVec: (rec_247) -> (rec_250) query; + testRecTupleWithVecReturn: () -> (rec_275) query; + testRecVariant: (rec_231) -> (rec_234) query; + testRecVariantReturn: () -> (rec_267) query; +} \ No newline at end of file diff --git a/src/compiler/generate_candid_and_canister_methods.ts b/src/compiler/generate_candid_and_canister_methods.ts index 9be7eb072a..deb63c621b 100644 --- a/src/compiler/generate_candid_and_canister_methods.ts +++ b/src/compiler/generate_candid_and_canister_methods.ts @@ -1,4 +1,9 @@ import { CanisterMethods } from './utils/types'; +import { + DEFAULT_VISITOR_DATA, + DidResultToCandidString, + DidVisitor +} from '../lib_new/visitors/did_visitor'; export function generateCandidAndCanisterMethods(mainJs: string): { candid: string; @@ -29,8 +34,15 @@ export function generateCandidAndCanisterMethods(mainJs: string): { const script = new vm.Script(mainJs); script.runInContext(context); + const candidInfo = (sandbox.exports as any).canisterMethods + .getIDL([]) + .accept(new DidVisitor(), { + ...DEFAULT_VISITOR_DATA, + isFirstService: true + }); + return { - candid: (sandbox.exports as any).canisterMethods.candid, + candid: DidResultToCandidString(candidInfo), canisterMethods: (sandbox.exports as any).canisterMethods }; } diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 93b6724dfe..e07b490543 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -1,8 +1,32 @@ import { IDL } from '@dfinity/candid'; -type VisitorData = { usedRecClasses: IDL.RecClass[]; is_on_service: boolean }; +type VisitorData = { + usedRecClasses: IDL.RecClass[]; + is_on_service: boolean; + isFirstService: boolean; +}; type VisitorResult = [CandidDef, CandidTypesDefs]; +export const DEFAULT_VISITOR_DATA: VisitorData = { + usedRecClasses: [], + is_on_service: false, + isFirstService: false +}; + +export function DidResultToCandidString(result: VisitorResult): string { + const candid = result[0]; + const candidTypes = Object.values(result[1]); + const candidTypesString = + candidTypes.length > 0 + ? Object.entries(result[1]) + .map(([name, type]) => `type ${name} = ${type};`) + .join('\n') + '\n' + : ''; + const candidTypesStringOld = + candidTypes.length > 0 ? candidTypes.join(';\n') + ';\n' : ''; + return candidTypesString + candid; +} + type TypeName = string; export type CandidDef = string; export type CandidTypesDefs = { [key: TypeName]: CandidDef }; @@ -21,7 +45,7 @@ export function extractCandid( return [paramCandid, candidTypeDefs]; } -class DidVisitor extends IDL.Visitor { +export class DidVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { const stuff = t._fields.map(([_name, func]) => func.accept(this, { ...data, is_on_service: true }) @@ -29,9 +53,12 @@ class DidVisitor extends IDL.Visitor { const candid = extractCandid(stuff); const funcStrings = candid[0] .map((value, index) => { - return `\t${t._fields[index][0]}: ${value}`; + return `\t${t._fields[index][0]}: ${value};`; }) .join('\n'); + if (data.isFirstService) { + return [`service: () -> {\n${funcStrings}\n}`, candid[1]]; + } return [`service {\n${funcStrings}\n}`, candid[1]]; } visitPrimitive( @@ -97,11 +124,12 @@ class DidVisitor extends IDL.Visitor { // Everything else will just be the normal inline candid def const usedRecClasses = data.usedRecClasses; if (!usedRecClasses.includes(t)) { - const candid = t.accept(this, { + const candid = ty.accept(this, { usedRecClasses: [...usedRecClasses, t], - is_on_service: false + is_on_service: false, + isFirstService: false }); - return [t.name, { ...candid[1], [t.name]: candid[0][0] }]; + return [t.name, { ...candid[1], [t.name]: candid[0] }]; } // If our list already includes this rec class then just return, we don't // need the list because we will get it when we go through the arm above From 582d8b48bb026df78ccdfda4f468a7de15abc368 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 20:12:23 -0600 Subject: [PATCH 11/37] remove body from canister type --- examples/recursion/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/index.ts index 4eb884d77a..05d5efe251 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/index.ts @@ -35,7 +35,7 @@ const myTupleVar = Variant({ num: int8, varTuple: varTuple }); // Service const MyCanister = Recursive(() => Canister({ - myQuery: query([MyCanister], MyCanister, (param) => param) + myQuery: query([MyCanister], MyCanister) }) ); // Func From 079dda5dc2b5fa230649b9d07067de8f3bde7f80 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 20:28:55 -0600 Subject: [PATCH 12/37] add second canister --- examples/recursion/dfx.json | 16 ++++++++++++++-- examples/recursion/src/{ => recursion}/index.did | 0 examples/recursion/src/{ => recursion}/index.ts | 7 +++++-- .../recursion/src/recursive_canister/index.did | 9 +++++++++ .../recursion/src/recursive_canister/index.ts | 9 +++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) rename examples/recursion/src/{ => recursion}/index.did (100%) rename examples/recursion/src/{ => recursion}/index.ts (96%) create mode 100644 examples/recursion/src/recursive_canister/index.did create mode 100644 examples/recursion/src/recursive_canister/index.ts diff --git a/examples/recursion/dfx.json b/examples/recursion/dfx.json index 92138d06c2..62f13159eb 100644 --- a/examples/recursion/dfx.json +++ b/examples/recursion/dfx.json @@ -2,15 +2,27 @@ "canisters": { "recursion": { "type": "custom", - "main": "src/index.ts", + "main": "src/recursion/index.ts", "build": "npx azle recursion", - "candid": "src/index.did", + "candid": "src/recursion/index.did", "wasm": ".azle/recursion/recursion.wasm", "gzip": true, "declarations": { "output": "test/dfx_generated/recursion", "node_compatibility": true } + }, + "recursive_canister": { + "type": "custom", + "main": "src/recursive_canister/index.ts", + "build": "npx azle recursive_canister", + "candid": "src/recursive_canister/index.did", + "wasm": ".azle/recursive_canister/recursive_canister.wasm", + "gzip": true, + "declarations": { + "output": "test/dfx_generated/recursive_canister", + "node_compatibility": true + } } } } diff --git a/examples/recursion/src/index.did b/examples/recursion/src/recursion/index.did similarity index 100% rename from examples/recursion/src/index.did rename to examples/recursion/src/recursion/index.did diff --git a/examples/recursion/src/index.ts b/examples/recursion/src/recursion/index.ts similarity index 96% rename from examples/recursion/src/index.ts rename to examples/recursion/src/recursion/index.ts index 05d5efe251..0565db640f 100644 --- a/examples/recursion/src/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -110,8 +110,11 @@ export default Canister({ ]), testRecService: query([MyCanister], MyCanister, (param) => param), testRecServiceReturn: query([], MyCanister, () => { - MyCanister( - Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? + MyCanister.idlCallback( + Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') + )( + // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? + Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') ); }), diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did new file mode 100644 index 0000000000..7198db700f --- /dev/null +++ b/examples/recursion/src/recursive_canister/index.did @@ -0,0 +1,9 @@ +type rec_16 = service { + myQuery: (rec_16) -> (rec_16) query; +}; +type rec_19 = service { + myQuery: (rec_19) -> (rec_19) query; +}; +service: () -> { + myQuery: (rec_16) -> (rec_19) query; +} \ No newline at end of file diff --git a/examples/recursion/src/recursive_canister/index.ts b/examples/recursion/src/recursive_canister/index.ts new file mode 100644 index 0000000000..6bf65f831f --- /dev/null +++ b/examples/recursion/src/recursive_canister/index.ts @@ -0,0 +1,9 @@ +import { query, Canister, Recursive } from 'azle'; + +const MyCanister = Recursive(() => + Canister({ + myQuery: query([MyCanister], MyCanister, (param) => param) + }) +); + +export default MyCanister.idlCallback(); From 80070630288925895a67824006253761507244ce Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 20:30:40 -0600 Subject: [PATCH 13/37] rename is_on_service --- src/lib_new/visitors/did_visitor.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index e07b490543..69ff891126 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -2,14 +2,14 @@ import { IDL } from '@dfinity/candid'; type VisitorData = { usedRecClasses: IDL.RecClass[]; - is_on_service: boolean; + isOnService: boolean; isFirstService: boolean; }; type VisitorResult = [CandidDef, CandidTypesDefs]; export const DEFAULT_VISITOR_DATA: VisitorData = { usedRecClasses: [], - is_on_service: false, + isOnService: false, isFirstService: false }; @@ -48,7 +48,7 @@ export function extractCandid( export class DidVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { const stuff = t._fields.map(([_name, func]) => - func.accept(this, { ...data, is_on_service: true }) + func.accept(this, { ...data, isOnService: true }) ); const candid = extractCandid(stuff); const funcStrings = candid[0] @@ -73,7 +73,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const fields = components.map((value) => - value.accept(this, { ...data, is_on_service: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(fields); return [`record {${candid[0].join('; ')}}`, candid[1]]; @@ -83,7 +83,7 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, is_on_service: false }); + const candid = ty.accept(this, { ...data, isOnService: false }); return [`opt ${candid[0]}`, candid[1]]; } visitVec( @@ -91,25 +91,23 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, is_on_service: false }); + const candid = ty.accept(this, { ...data, isOnService: false }); return [`vec ${candid[0]}`, candid[1]]; } visitFunc(t: IDL.FuncClass, data: VisitorData): VisitorResult { const argsTypes = t.argTypes.map((value) => - value.accept(this, { ...data, is_on_service: false }) + value.accept(this, { ...data, isOnService: false }) ); const candidArgs = extractCandid(argsTypes); const retsTypes = t.retTypes.map((value) => - value.accept(this, { ...data, is_on_service: false }) + value.accept(this, { ...data, isOnService: false }) ); const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); const rets = candidRets[0].join(', '); const annon = ' ' + t.annotations.join(' '); return [ - `${ - data.is_on_service ? '' : 'func ' - }(${args}) -> (${rets})${annon}`, + `${data.isOnService ? '' : 'func '}(${args}) -> (${rets})${annon}`, { ...candidArgs[1], ...candidRets[1] } ]; } @@ -126,7 +124,7 @@ export class DidVisitor extends IDL.Visitor { if (!usedRecClasses.includes(t)) { const candid = ty.accept(this, { usedRecClasses: [...usedRecClasses, t], - is_on_service: false, + isOnService: false, isFirstService: false }); return [t.name, { ...candid[1], [t.name]: candid[0] }]; @@ -141,7 +139,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, is_on_service: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const field_strings = fields.map( @@ -155,7 +153,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, is_on_service: false }) + value.accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const fields_string = fields.map( From 0561ef9e62b2c00d91e69d9b57fc5e1da6b59361 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 21:38:51 -0600 Subject: [PATCH 14/37] remove candid strings --- .../candid/reference/service.ts | 27 ------ .../canister_methods/heartbeat.ts | 4 +- src/lib_functional/canister_methods/index.ts | 40 ++++---- src/lib_functional/canister_methods/init.ts | 16 +--- .../canister_methods/inspect_message.ts | 17 +--- .../canister_methods/post_upgrade.ts | 16 +--- .../canister_methods/pre_upgrade.ts | 4 +- src/lib_functional/canister_methods/query.ts | 25 ++--- src/lib_functional/canister_methods/update.ts | 23 ++--- src/lib_new/utils.ts | 93 +++---------------- src/lib_new/visitors/did_visitor.ts | 31 +++++-- 11 files changed, 83 insertions(+), 213 deletions(-) diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index a1bad521ec..1d7da177ff 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -77,17 +77,6 @@ export function Canister( {} ); - // TODO Once types have names we should deduplicate the init and post_upgrade param types - const candidTypes = Object.values(serviceOptions).reduce( - (acc: string[], canisterMethodInfo) => { - return [ - ...acc, - ...canisterMethodInfo(parentOrUndefined).candidTypes - ]; - }, - [] - ); - const initOption = Object.entries(serviceOptions).find( ([key, value]) => value(parentOrUndefined).mode === 'init' ); @@ -217,22 +206,6 @@ export function Canister( }; }; - returnFunction.candid = `${ - candidTypes.length === 0 ? '' : candidTypes.join('\n') + '\n' - }service: (${initOption?.[1].candid ?? ''}) -> { - ${Object.entries(serviceOptions) - .filter( - ([_, value]) => - value(parentOrUndefined).mode === 'query' || - value(parentOrUndefined).mode === 'update' - ) - .map((entry) => { - return `${entry[0]}: ${entry[1](parentOrUndefined).candid}`; - }) - .join('\n ')} -} -`; - returnFunction.init = init; returnFunction.post_upgrade = postUpgrade; returnFunction.pre_upgrade = preUpgrade; diff --git a/src/lib_functional/canister_methods/heartbeat.ts b/src/lib_functional/canister_methods/heartbeat.ts index d0037f6a09..2d791a4e07 100644 --- a/src/lib_functional/canister_methods/heartbeat.ts +++ b/src/lib_functional/canister_methods/heartbeat.ts @@ -1,4 +1,4 @@ -import { isAsync } from '../../lib_new/method_decorators'; +import { isAsync } from '../../lib_new/utils'; import { CanisterMethodInfo, executeMethod } from '.'; import { Void } from '../../lib_new'; @@ -22,8 +22,6 @@ export function heartbeat( return { mode: 'heartbeat', callback: finalCallback, - candid: '', - candidTypes: [], paramsIdls: [], returnIdl: Void, async: isAsync(callback), diff --git a/src/lib_functional/canister_methods/index.ts b/src/lib_functional/canister_methods/index.ts index 8e968c09c0..ecf236a735 100644 --- a/src/lib_functional/canister_methods/index.ts +++ b/src/lib_functional/canister_methods/index.ts @@ -15,6 +15,8 @@ export * from './pre_upgrade'; export * from './query'; export * from './update'; +export type MethodArgs = { manual?: boolean; guard?: () => void }; + export type CanisterMethodInfo, K> = { mode: | 'query' @@ -26,8 +28,6 @@ export type CanisterMethodInfo, K> = { | 'preUpgrade'; async: boolean; callback?: (...args: any) => any; - candid: string; - candidTypes: string[]; paramsIdls: any[]; returnIdl: any; guard: (() => any) | undefined; @@ -39,12 +39,12 @@ export type Callback, Return> = ( export function executeMethod( mode: CanisterMethodInfo['mode'], - paramCandid: any, - returnCandid: any, + finalParamIdls: any, + finalReturnIdl: any, args: any[], callback: any, - paramsIdls: any[], - returnIdl: any, + userMadeParamsIdls: any[], + userMadeReturnIdl: any, manual: boolean ) { if (mode === 'heartbeat') { @@ -68,11 +68,11 @@ export function executeMethod( return; } - const decoded = IDL.decode(paramCandid[0] as any, args[0]); + const decoded = IDL.decode(finalParamIdls as any, args[0]); - const myDecodedObject = paramCandid[0].map((idl: any, index: any) => { + const myDecodedObject = finalParamIdls.map((idl: any, index: any) => { return idl.accept(new DecodeVisitor(), { - js_class: paramsIdls[index], + js_class: userMadeParamsIdls[index], js_data: decoded[index] }); }); @@ -100,16 +100,14 @@ export function executeMethod( if (!manual) { // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = returnCandid[0].map( - (idl: any) => { - return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, - js_data: result - }); - } - ); + const encodeReadyResult = finalReturnIdl.map((idl: any) => { + return idl.accept(new EncodeVisitor(), { + js_class: userMadeReturnIdl, + js_data: result + }); + }); const encoded = IDL.encode( - returnCandid[0] as any, + finalReturnIdl as any, encodeReadyResult ); ic.replyRaw(new Uint8Array(encoded)); @@ -121,15 +119,15 @@ export function executeMethod( } else { if (!manual) { // const encodeReadyResult = result === undefined ? [] : [result]; - const encodeReadyResult = returnCandid[0].map((idl: any) => { + const encodeReadyResult = finalReturnIdl.map((idl: any) => { return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, + js_class: userMadeReturnIdl, js_data: result }); }); const encoded = IDL.encode( - returnCandid[0] as any, + finalReturnIdl as any, encodeReadyResult ); ic.replyRaw(new Uint8Array(encoded)); diff --git a/src/lib_functional/canister_methods/init.ts b/src/lib_functional/canister_methods/init.ts index f29bf22b89..122be5714c 100644 --- a/src/lib_functional/canister_methods/init.ts +++ b/src/lib_functional/canister_methods/init.ts @@ -1,11 +1,7 @@ -import { - handleRecursiveParams, - handleRecursiveReturn, - newTypesToStingArr -} from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function init< const Params extends ReadonlyArray, @@ -18,12 +14,8 @@ export function init< ): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); - const paramCandid = handleRecursiveParams(paramsIdls as any, parents); - const returnCandid = handleRecursiveReturn( - Void as any, - paramCandid[2], - parents - ); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(Void as any, parents); const finalCallback = callback === undefined @@ -44,8 +36,6 @@ export function init< return { mode: 'init', callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), paramsIdls: paramsIdls as any, returnIdl: Void, async: false, diff --git a/src/lib_functional/canister_methods/inspect_message.ts b/src/lib_functional/canister_methods/inspect_message.ts index cd228c803d..918df84c01 100644 --- a/src/lib_functional/canister_methods/inspect_message.ts +++ b/src/lib_functional/canister_methods/inspect_message.ts @@ -1,9 +1,6 @@ import { CanisterMethodInfo, createParents, executeMethod } from '.'; -import { - Void, - handleRecursiveParams, - handleRecursiveReturn -} from '../../lib_new'; +import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; import { RecursiveType } from '../candid'; export function inspectMessage( @@ -12,12 +9,8 @@ export function inspectMessage( return (parent: any) => { const parents = createParents(parent); // TODO why are we doing this handle recursive params when there are none? - const paramCandid = handleRecursiveParams([], parents); - const returnCandid = handleRecursiveReturn( - Void as any, - paramCandid[2], - parents - ); + const paramCandid = toParamIDLTypes([], parents); + const returnCandid = toReturnIDLType(Void as any, parents); const finalCallback = (...args: any[]) => { executeMethod( @@ -35,8 +28,6 @@ export function inspectMessage( return { mode: 'inspectMessage', callback: finalCallback, - candid: '', - candidTypes: [], paramsIdls: [], returnIdl: Void, async: false, diff --git a/src/lib_functional/canister_methods/post_upgrade.ts b/src/lib_functional/canister_methods/post_upgrade.ts index 098d676d8b..35df523fac 100644 --- a/src/lib_functional/canister_methods/post_upgrade.ts +++ b/src/lib_functional/canister_methods/post_upgrade.ts @@ -1,11 +1,7 @@ -import { - handleRecursiveParams, - handleRecursiveReturn, - newTypesToStingArr -} from '../../lib_new/method_decorators'; import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; import { CandidType, TypeMapping } from '../candid'; import { Void } from '../../lib_new'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function postUpgrade< const Params extends ReadonlyArray, @@ -18,12 +14,8 @@ export function postUpgrade< ): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); - const paramCandid = handleRecursiveParams(paramsIdls as any, parents); - const returnCandid = handleRecursiveReturn( - Void as any, - paramCandid[2], - parents - ); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(Void as any, parents); const finalCallback = callback === undefined @@ -44,8 +36,6 @@ export function postUpgrade< return { mode: 'postUpgrade', callback: finalCallback, - candid: paramCandid[1].join(', '), - candidTypes: newTypesToStingArr(returnCandid[2]), paramsIdls: paramsIdls as any, returnIdl: Void, async: false, diff --git a/src/lib_functional/canister_methods/pre_upgrade.ts b/src/lib_functional/canister_methods/pre_upgrade.ts index e1247285a9..8661c05b22 100644 --- a/src/lib_functional/canister_methods/pre_upgrade.ts +++ b/src/lib_functional/canister_methods/pre_upgrade.ts @@ -1,4 +1,4 @@ -import { isAsync } from '../../lib_new/method_decorators'; +import { isAsync } from '../../lib_new/utils'; import { CanisterMethodInfo, executeMethod } from '.'; import { Void } from '../../lib_new'; @@ -22,8 +22,6 @@ export function preUpgrade( return { mode: 'preUpgrade', callback: finalCallback, - candid: '', - candidTypes: [], paramsIdls: [], returnIdl: Void, async: isAsync(callback), diff --git a/src/lib_functional/canister_methods/query.ts b/src/lib_functional/canister_methods/query.ts index 5f0e5eaa01..20d9940744 100644 --- a/src/lib_functional/canister_methods/query.ts +++ b/src/lib_functional/canister_methods/query.ts @@ -1,12 +1,13 @@ +import { isAsync } from '../../lib_new/utils'; import { + Callback, + CanisterMethodInfo, MethodArgs, - handleRecursiveParams, - handleRecursiveReturn, - isAsync, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; + createParents, + executeMethod +} from '.'; import { CandidType, RecursiveType, TypeMapping } from '../candid'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function query< const Params extends ReadonlyArray, @@ -22,12 +23,8 @@ export function query< ): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); - const paramCandid = handleRecursiveParams(paramsIdls as any, parents); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2], - parents - ); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(returnIdl as any, parents); // TODO maybe the cross canister callback should be made here? const finalCallback = @@ -49,10 +46,6 @@ export function query< return { mode: 'query', callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${ - returnCandid[1] - }) query;`, - candidTypes: newTypesToStingArr(returnCandid[2]), paramsIdls: paramsIdls as any, returnIdl, async: callback === undefined ? false : isAsync(callback), diff --git a/src/lib_functional/canister_methods/update.ts b/src/lib_functional/canister_methods/update.ts index 1367024bab..303aac69e4 100644 --- a/src/lib_functional/canister_methods/update.ts +++ b/src/lib_functional/canister_methods/update.ts @@ -1,12 +1,13 @@ +import { isAsync } from '../../lib_new/utils'; import { + Callback, + CanisterMethodInfo, MethodArgs, - handleRecursiveParams, - handleRecursiveReturn, - isAsync, - newTypesToStingArr -} from '../../lib_new/method_decorators'; -import { Callback, CanisterMethodInfo, createParents, executeMethod } from '.'; + createParents, + executeMethod +} from '.'; import { CandidType, RecursiveType, TypeMapping } from '../candid'; +import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function update< const Params extends ReadonlyArray, @@ -22,12 +23,8 @@ export function update< ): CanisterMethodInfo { return (parent: any) => { const parents = createParents(parent); - const paramCandid = handleRecursiveParams(paramsIdls as any, parents); - const returnCandid = handleRecursiveReturn( - returnIdl as any, - paramCandid[2], - parents - ); + const paramCandid = toParamIDLTypes(paramsIdls as any, parents); + const returnCandid = toReturnIDLType(returnIdl as any, parents); const finalCallback = callback === undefined @@ -48,8 +45,6 @@ export function update< return { mode: 'update', callback: finalCallback, - candid: `(${paramCandid[1].join(', ')}) -> (${returnCandid[1]});`, - candidTypes: newTypesToStingArr(returnCandid[2]), paramsIdls: paramsIdls as any, returnIdl, async: callback === undefined ? false : isAsync(callback), diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index 193015e0fb..8acf82da85 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -31,86 +31,6 @@ export function extractCandid( return [paramCandid, candidTypeDefs]; } -export function display( - idl: IDL.Type, - candidTypeDefs: CandidTypesDefs -): [CandidDef, CandidTypesDefs] { - if (idl instanceof IDL.RecClass) { - // For RecClasses the definition will be the name, that name will - // reference the actual definition which will be added to the list of - // candid type defs that will get put at the top of the candid file - // Everything else will just be the normal inline candid def - const candid = extractCandid( - [display(idl.getType(), candidTypeDefs)], - candidTypeDefs - ); - return [idl.name, { ...candid[1], [idl.name]: candid[0][0] }]; - } - if (idl instanceof IDL.TupleClass) { - const fields = idl._components.map((value) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(fields, candidTypeDefs); - return [`record {${candid[0].join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.OptClass) { - const candid = extractCandid( - [display(idl._type, candidTypeDefs)], - candidTypeDefs - ); - return [`opt ${candid[0]}`, candid[1]]; - } - if (idl instanceof IDL.VecClass) { - const candid = extractCandid( - [display(idl._type, candidTypeDefs)], - candidTypeDefs - ); - return [`vec ${candid[0]}`, candid[1]]; - } - if (idl instanceof IDL.RecordClass) { - const candidFields = idl._fields.map(([key, value]) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(candidFields, candidTypeDefs); - const fields = idl._fields.map( - ([key, value], index) => key + ':' + candid[0][index] - ); - return [`record {${fields.join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.VariantClass) { - const candidFields = idl._fields.map(([key, value]) => - display(value, candidTypeDefs) - ); - const candid = extractCandid(candidFields, candidTypeDefs); - const fields = idl._fields.map( - ([key, value], index) => - key + (value.name === 'null' ? '' : ':' + candid[0][index]) - ); - return [`variant {${fields.join('; ')}}`, candid[1]]; - } - if (idl instanceof IDL.FuncClass) { - const argsTypes = idl.argTypes.map((value) => - display(value, candidTypeDefs) - ); - const candidArgs = extractCandid(argsTypes, candidTypeDefs); - const retsTypes = idl.retTypes.map((value) => - display(value, candidArgs[1]) - ); - const candidRets = extractCandid(retsTypes, candidArgs[1]); - const args = candidArgs[0].join(', '); - const rets = candidRets[0].join(', '); - const annon = ' ' + idl.annotations.join(' '); - return [`func (${args}) -> (${rets})${annon}`, candidRets[1]]; - } - if (idl !== undefined && !('display' in idl)) { - throw Error(`${JSON.stringify(idl)} is not a candid type`); - } - if (idl === undefined) { - throw Error('cannot convert undefined to candid'); - } - return [idl.display(), candidTypeDefs]; -} - export type Parent = { idl: IDL.RecClass; name: string; @@ -145,6 +65,7 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { _buildTypeTableImpl: (typeTable): void => { return parent.idl._buildTypeTableImpl(typeTable); }, + // TODO check if this is still being called. maybe by adding a throw here and see if we hit it display: () => parent.idl.name, decodeValue: (b, t) => { return parent.idl.decodeValue(b, t); @@ -194,6 +115,18 @@ export function toReturnIDLType( return [idlType]; } +export function isAsync(originalFunction: any) { + if (originalFunction[Symbol.toStringTag] === 'AsyncFunction') { + return true; + } else if (originalFunction.constructor.name === 'AsyncFunction') { + return true; + } else if (originalFunction.toString().includes('async ')) { + return true; + } else { + return false; + } +} + type CandidMap = { [key: string]: any }; export function processMap(targetMap: CandidMap, parent: Parent[]): CandidMap { diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 69ff891126..8d330c9499 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -7,6 +7,13 @@ type VisitorData = { }; type VisitorResult = [CandidDef, CandidTypesDefs]; +// TODO it would be nice to have names for the rec types instead of rec_1, rec_2 etc +// TODO Once types have names we should deduplicate the init and post_upgrade param types +// TODO maybe even before we have names we should deduplicate all sorts of types +// The rust to candid converter we were using did have names, but if two things +// had the same shape they got merged into one type that had one of the names. +// That might not be the ideal situation, but it is the expected behavior in rust + export const DEFAULT_VISITOR_DATA: VisitorData = { usedRecClasses: [], isOnService: false, @@ -14,19 +21,23 @@ export const DEFAULT_VISITOR_DATA: VisitorData = { }; export function DidResultToCandidString(result: VisitorResult): string { - const candid = result[0]; - const candidTypes = Object.values(result[1]); - const candidTypesString = - candidTypes.length > 0 - ? Object.entries(result[1]) - .map(([name, type]) => `type ${name} = ${type};`) - .join('\n') + '\n' - : ''; - const candidTypesStringOld = - candidTypes.length > 0 ? candidTypes.join(';\n') + ';\n' : ''; + const [candid, candidTypeDefs] = result; + const candidTypesString = newTypeToCandidString(candidTypeDefs); return candidTypesString + candid; } +function newTypeToCandidString(newTypes: CandidTypesDefs): string { + return Object.entries(newTypes).length > 0 + ? newTypesToStingArr(newTypes).join('\n') + '\n' + : ''; +} + +function newTypesToStingArr(newTypes: CandidTypesDefs): string[] { + return Object.entries(newTypes).map( + ([name, candid]) => `type ${name} = ${candid};` + ); +} + type TypeName = string; export type CandidDef = string; export type CandidTypesDefs = { [key: TypeName]: CandidDef }; From a3f5efd11b94ef8b9103e8a828718da70a180928 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 21:42:09 -0600 Subject: [PATCH 15/37] remove method decorators --- src/lib_new/method_decorators.ts | 425 ------------------------------- 1 file changed, 425 deletions(-) diff --git a/src/lib_new/method_decorators.ts b/src/lib_new/method_decorators.ts index 7040b915bb..2d2d4ea3b2 100644 --- a/src/lib_new/method_decorators.ts +++ b/src/lib_new/method_decorators.ts @@ -1,396 +1,6 @@ import { ic } from './ic'; import { GuardResult, IDL } from './index'; -import { - CandidClass, - ReturnCandidClass, - toParamIDLTypes, - toReturnIDLType, - CandidTypesDefs, - CandidDef, - extractCandid, - Parent -} from './utils'; -import { display } from './utils'; -import { - Service, - serviceCall, - ServiceConstructor, - serviceDecorator -} from './service'; -import { DecodeVisitor, EncodeVisitor } from './visitors/encode_decode/'; - -export type Manual = void; - -type Mode = - | 'init' - | 'postUpgrade' - | 'preUpgrade' - | 'query' - | 'update' - | 'heartbeat' - | 'inspectMessage'; - -const modeToCandid = { - query: ' query', - update: '' -}; - -// TODO add the GuardResult return type -export type MethodArgs = { manual?: boolean; guard?: () => void }; - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function init(paramsIdls: any[]): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - return setupCanisterMethod( - target, - paramsIdls, - [], - 'init', - false, - undefined, - key, - descriptor - ); - }; -} - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function postUpgrade(paramsIdls: any[]): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - return setupCanisterMethod( - target, - paramsIdls, - [], - 'postUpgrade', - false, - undefined, - key, - descriptor - ); - }; -} - -export function preUpgrade( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'preUpgrade', - false, - undefined, - key, - descriptor - ); -} - -export function heartbeat( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'heartbeat', - false, - undefined, - key, - descriptor - ); -} - -export function inspectMessage( - target: any, - key: string, - descriptor?: PropertyDescriptor -) { - return setupCanisterMethod( - target, - [], - [], - 'inspectMessage', - false, - undefined, - key, - descriptor - ); -} - -// Until we can figure how how to type check Funcs, Variants, and Records we are just going to have to use any here -// export function query(paramsIdls: CandidClass[], returnIdl: ReturnCandidClass) { -export function query( - paramsIdls: any[], - returnIdl: any, - args: MethodArgs = { manual: false } -): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - if (descriptor === undefined) { - serviceDecorator(target, key, paramsIdls, returnIdl); - } else { - return setupCanisterMethod( - target, - paramsIdls, - returnIdl, - 'query', - args.manual, - args.guard, - key, - descriptor - ); - } - }; -} - -// export function update( -// paramsIdls: CandidClass[], -// returnIdl: ReturnCandidClass -export function update( - paramsIdls: any[], - returnIdl: any, - args: MethodArgs = { manual: false } -): any { - return (target: any, key: string, descriptor?: PropertyDescriptor) => { - if (descriptor === undefined) { - serviceDecorator(target, key, paramsIdls, returnIdl); - } else { - return setupCanisterMethod( - target, - paramsIdls, - returnIdl, - 'update', - args.manual, - args.guard, - key, - descriptor - ); - } - }; -} - -export function newTypesToStingArr(newTypes: CandidTypesDefs): string[] { - return Object.entries(newTypes).map( - ([name, candid]) => `type ${name} = ${candid};` - ); -} - -export function handleRecursiveParams( - idls: CandidClass[], - parents: Parent[] = [] -): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const paramIdls = toParamIDLTypes(idls, parents); - const paramInfo = paramIdls.map((paramIdl) => display(paramIdl, {})); - return [paramIdls, ...extractCandid(paramInfo, {})]; -} - -export function handleRecursiveReturn( - returnIdl: ReturnCandidClass, - paramCandidTypeDefs: CandidTypesDefs, - parents: Parent[] = [] -): [IDL.Type[], CandidDef[], CandidTypesDefs] { - const returnIdls = toReturnIDLType(returnIdl, parents); - const returnInfo = returnIdls.map((returnIdl) => display(returnIdl, {})); - return [returnIdls, ...extractCandid(returnInfo, paramCandidTypeDefs)]; -} - -function setupCanisterMethod( - target: any, - paramsIdls: CandidClass[], - returnIdl: ReturnCandidClass, - mode: Mode, - manual: boolean, - guard: (() => GuardResult) | undefined, - key: string, - descriptor: PropertyDescriptor -) { - const paramCandid = handleRecursiveParams(paramsIdls); - const returnCandid = handleRecursiveReturn(returnIdl, paramCandid[2]); - - if (target.constructor._azleCanisterMethods === undefined) { - target.constructor._azleCanisterMethods = { - queries: [], - updates: [] - }; - } - - if (target.constructor._azleCandidInitParams === undefined) { - target.constructor._azleCandidInitParams = []; - } - - if (mode === 'init' || mode === 'postUpgrade') { - target.constructor._azleCandidInitParams = paramCandid[1]; - } - - if (target.constructor._azleCandidTypes === undefined) { - target.constructor._azleCandidTypes = []; - } - - target.constructor._azleCandidTypes = [ - ...target.constructor._azleCandidTypes, - ...newTypesToStingArr(returnCandid[2]) - ]; - - if (mode === 'query' || mode === 'update') { - if (target.constructor._azleCandidMethods === undefined) { - target.constructor._azleCandidMethods = []; - } - - target.constructor._azleCandidMethods.push( - `${key}: (${paramCandid[1].join(', ')}) -> (${returnCandid[1]})${ - modeToCandid[mode] - };` - ); - - if (target instanceof Service) { - addIDLForMethodToServiceConstructor( - target.constructor, - key, - paramsIdls, - returnIdl, - mode - ); - } - } - - const originalMethod = descriptor.value; - - if (mode === 'query') { - target.constructor._azleCanisterMethods.queries.push({ - name: key, - composite: isAsync(originalMethod, key), - guard_name: createGlobalGuard(guard, key) - }); - } - - if (mode === 'update') { - target.constructor._azleCanisterMethods.updates.push({ - name: key, - guard_name: createGlobalGuard(guard, key) - }); - } - - if (mode === 'heartbeat') { - target.constructor._azleCanisterMethods.heartbeat = { - name: key - }; - } - - if (mode === 'inspectMessage') { - target.constructor._azleCanisterMethods.inspect_message = { - name: key - }; - } - - if (mode === 'preUpgrade') { - target.constructor._azleCanisterMethods.pre_upgrade = { - name: key - }; - } - - // This must remain a function and not an arrow function - // in order to set the context (this) correctly - descriptor.value = function (...args: any[]) { - if (args[0] === '_AZLE_CROSS_CANISTER_CALL') { - const serviceCallInner = serviceCall(key, paramsIdls, returnIdl); - return serviceCallInner.call(this, ...args); - } - - if (mode === 'heartbeat' || mode === 'preUpgrade') { - originalMethod.call(this); - return; - } - - const decoded = IDL.decode(paramCandid[0], args[0]); - const myDecodedObject = paramCandid[0].map((idl, index) => { - return idl.accept(new DecodeVisitor(), { - js_class: paramsIdls[index], - js_data: decoded[index] - }); - }); - - const result = originalMethod.apply(this, myDecodedObject); - - if ( - mode === 'init' || - mode === 'postUpgrade' || - mode === 'inspectMessage' - ) { - return; - } - - const is_promise = - result !== undefined && - result !== null && - typeof result.then === 'function'; - - if (is_promise) { - result - .then((result) => { - // TODO this won't be accurate because we have most likely had - // TODO cross-canister calls - console.log( - `final instructions: ${ic.instructionCounter()}` - ); - - if (!manual) { - const encodeReadyResult = - result === undefined ? [] : [result]; - const encoded = IDL.encode( - returnCandid[0], - encodeReadyResult - ); - ic.replyRaw(new Uint8Array(encoded)); - } - }) - .catch((error) => { - ic.trap(error.toString()); - }); - } else { - if (!manual) { - const encodeReadyResult = returnCandid[0].map((idl) => { - return idl.accept(new EncodeVisitor(), { - js_class: returnIdl, - js_data: result - }); - }); - const encoded = IDL.encode(returnCandid[0], encodeReadyResult); - ic.replyRaw(new Uint8Array(encoded)); - } - - console.log(`final instructions: ${ic.instructionCounter()}`); - } - }; - - if (mode === 'init') { - globalThis._azleInitName = key; - } - - if (mode === 'postUpgrade') { - globalThis._azlePostUpgradeName = key; - } - - return descriptor; -} - -export function isAsync(originalFunction: any) { - if (originalFunction[Symbol.toStringTag] === 'AsyncFunction') { - return true; - } else if (originalFunction.constructor.name === 'AsyncFunction') { - return true; - } else if (originalFunction.toString().includes('async ')) { - return true; - } else { - return false; - } -} - export function createGlobalGuard( guard: (() => GuardResult) | undefined, functionName: string @@ -405,38 +15,3 @@ export function createGlobalGuard( return guardName; } - -/** - * Stores an IDL representation of the canister method into a private - * `_azleFunctionInfo` object on the provided constructor. If that property doesn't - * exist, then it will be added as a side-effect. - * - * @param constructor The class on which to store the IDL information. This - * should probably be a Service. This type should probably be tightened down. - * @param methodName The public name of the canister method - * @param paramIdls The IDLs of the parameters, coming from the `@query` and - * `@update` decorators. - * @param returnIdl The IDL of the return type, coming from the `@query` and - * `@update` decorators. - * @param mode The mode in which the method should be executed. - */ -function addIDLForMethodToServiceConstructor( - constructor: T & ServiceConstructor, - methodName: string, - paramIdls: CandidClass[], - returnIdl: ReturnCandidClass, - mode: 'query' | 'update' -): void { - if (constructor._azleFunctionInfo === undefined) { - constructor._azleFunctionInfo = {}; - } - - // TODO: Technically, there is a possibility that the method name already - // exists. We may want to handle that case. - - constructor._azleFunctionInfo[methodName] = { - mode, - paramIdls, - returnIdl - }; -} From 24a03e828a726c4c3e44f7ab3b953a0083f9599f Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Thu, 28 Sep 2023 21:42:23 -0600 Subject: [PATCH 16/37] WIP --- examples/recursion/src/recursion/index.did | 101 ++++++++---------- examples/recursion/src/recursion/index.ts | 38 ++++--- .../src/recursive_canister/index.did | 10 +- 3 files changed, 73 insertions(+), 76 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index c829973098..8c4d50b764 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,60 +1,49 @@ -type rec_291 = func (rec_291) -> (rec_291) query; -type rec_294 = func (rec_294) -> (rec_294) query; -type rec_299 = func (rec_299) -> (rec_299) query; -type rec_207 = record {myOpt:opt rec_207}; -type rec_210 = record {myOpt:opt rec_210}; -type rec_255 = record {myOpt:opt rec_255}; -type rec_223 = record {myVar:variant {num:int8; varRec:rec_223}}; -type rec_226 = record {myVar:variant {num:int8; varRec:rec_226}}; -type rec_263 = record {myVar:variant {num:int8; varRec:rec_263}}; -type rec_215 = record {myVecRecords:vec rec_215}; -type rec_218 = record {myVecRecords:vec rec_218}; -type rec_259 = record {myVecRecords:vec rec_259}; -type rec_303 = service { - myQuery: (rec_303) -> (rec_303) query; +type rec_190 = func (rec_190) -> (rec_190) query; +type rec_193 = func (rec_193) -> (rec_193) query; +type rec_198 = func (rec_198) -> (rec_198) query; +type rec_106 = record {myOpt:opt rec_106}; +type rec_109 = record {myOpt:opt rec_109}; +type rec_154 = record {myOpt:opt rec_154}; +type rec_122 = record {myVar:variant {num:int8; varRec:rec_122}}; +type rec_125 = record {myVar:variant {num:int8; varRec:rec_125}}; +type rec_162 = record {myVar:variant {num:int8; varRec:rec_162}}; +type rec_114 = record {myVecRecords:vec rec_114}; +type rec_117 = record {myVecRecords:vec rec_117}; +type rec_158 = record {myVecRecords:vec rec_158}; +type rec_202 = service { + myQuery: (rec_202) -> (rec_202) query; }; -type rec_306 = service { - myQuery: (rec_306) -> (rec_306) query; +type rec_205 = service { + myQuery: (rec_205) -> (rec_205) query; }; -type rec_315 = service { - myQuery: (rec_315) -> (rec_315) query; -}; -type rec_318 = service { - myQuery: (rec_318) -> (rec_318) query; -}; -type rec_311 = service { - myQuery: (rec_311) -> (rec_311) query; -}; -type rec_239 = record {opt rec_239; opt rec_239}; -type rec_242 = record {opt rec_242; opt rec_242}; -type rec_271 = record {opt rec_271; opt rec_271}; -type rec_279 = record {variant {num:int8; varTuple:rec_279}; variant {num:int8; varTuple:rec_279}}; -type rec_282 = record {variant {num:int8; varTuple:rec_282}; variant {num:int8; varTuple:rec_282}}; -type rec_287 = record {variant {num:int8; varTuple:rec_287}; variant {num:int8; varTuple:rec_287}}; -type rec_247 = record {vec rec_247; vec rec_247}; -type rec_250 = record {vec rec_250; vec rec_250}; -type rec_275 = record {vec rec_275; vec rec_275}; -type rec_231 = variant {num:int8; recVariant:rec_231}; -type rec_234 = variant {num:int8; recVariant:rec_234}; -type rec_267 = variant {num:int8; recVariant:rec_267}; +type rec_138 = record {opt rec_138; opt rec_138}; +type rec_141 = record {opt rec_141; opt rec_141}; +type rec_170 = record {opt rec_170; opt rec_170}; +type rec_178 = record {variant {num:int8; varTuple:rec_178}; variant {num:int8; varTuple:rec_178}}; +type rec_181 = record {variant {num:int8; varTuple:rec_181}; variant {num:int8; varTuple:rec_181}}; +type rec_186 = record {variant {num:int8; varTuple:rec_186}; variant {num:int8; varTuple:rec_186}}; +type rec_146 = record {vec rec_146; vec rec_146}; +type rec_149 = record {vec rec_149; vec rec_149}; +type rec_174 = record {vec rec_174; vec rec_174}; +type rec_130 = variant {num:int8; recVariant:rec_130}; +type rec_133 = variant {num:int8; recVariant:rec_133}; +type rec_166 = variant {num:int8; recVariant:rec_166}; service: () -> { - testRecFunc: (rec_291) -> (rec_294) query; - testRecFuncReturn: () -> (rec_299) query; - testRecRecordWithOpt: (rec_207) -> (rec_210) query; - testRecRecordWithOptReturn: () -> (rec_255) query; - testRecRecordWithVariant: (rec_223) -> (rec_226) query; - testRecRecordWithVariantReturn: () -> (rec_263) query; - testRecRecordWithVec: (rec_215) -> (rec_218) query; - testRecRecordWithVecReturn: () -> (rec_259) query; - testRecService: (rec_303) -> (rec_306) query; - testRecServiceCall: (rec_315) -> (rec_318) ; - testRecServiceReturn: () -> (rec_311) query; - testRecTupleWithOpt: (rec_239) -> (rec_242) query; - testRecTupleWithOptReturn: () -> (rec_271) query; - testRecTupleWithVariant: (rec_279) -> (rec_282) query; - testRecTupleWithVariantReturn: () -> (rec_287) query; - testRecTupleWithVec: (rec_247) -> (rec_250) query; - testRecTupleWithVecReturn: () -> (rec_275) query; - testRecVariant: (rec_231) -> (rec_234) query; - testRecVariantReturn: () -> (rec_267) query; + testRecFunc: (rec_190) -> (rec_193) query; + testRecFuncReturn: () -> (rec_198) query; + testRecRecordWithOpt: (rec_106) -> (rec_109) query; + testRecRecordWithOptReturn: () -> (rec_154) query; + testRecRecordWithVariant: (rec_122) -> (rec_125) query; + testRecRecordWithVariantReturn: () -> (rec_162) query; + testRecRecordWithVec: (rec_114) -> (rec_117) query; + testRecRecordWithVecReturn: () -> (rec_158) query; + testRecServiceSimple: (rec_202) -> (rec_205) query; + testRecTupleWithOpt: (rec_138) -> (rec_141) query; + testRecTupleWithOptReturn: () -> (rec_170) query; + testRecTupleWithVariant: (rec_178) -> (rec_181) query; + testRecTupleWithVariantReturn: () -> (rec_186) query; + testRecTupleWithVec: (rec_146) -> (rec_149) query; + testRecTupleWithVecReturn: () -> (rec_174) query; + testRecVariant: (rec_130) -> (rec_133) query; + testRecVariantReturn: () -> (rec_166) query; } \ No newline at end of file diff --git a/examples/recursion/src/recursion/index.ts b/examples/recursion/src/recursion/index.ts index 0565db640f..c600e8c7e1 100644 --- a/examples/recursion/src/recursion/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -8,9 +8,14 @@ import { Some, Tuple, update, - Vec + Vec, + Record, + Recursive, + int8, + Variant, + Opt } from 'azle'; -import { Record, Recursive, int8, Variant, Opt } from 'azle'; +import MyFullCanister from '../recursive_canister'; // These are the types that can be recursive // Record @@ -108,19 +113,22 @@ export default Canister({ Principal.fromText('aaaaa-aa'), 'create_canister' ]), - testRecService: query([MyCanister], MyCanister, (param) => param), - testRecServiceReturn: query([], MyCanister, () => { - MyCanister.idlCallback( - Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') - )( - // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? - Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? - ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') - ); - }), - testRecServiceCall: update([MyCanister], MyCanister, async (myCanister) => { - return await ic.call(myCanister.myQuery(myCanister)); - }) + testRecServiceSimple: query([MyCanister], MyCanister, (param) => param) + // testRecService: query([MyFullCanister], MyFullCanister, (param) => param) + // testRecServiceReturn: query([], MyFullCanister, () => { + // MyFullCanister( + // // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? + // Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? + // ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + // ); + // }), + // testRecServiceCall: update( + // [MyFullCanister], + // MyFullCanister, + // async (myCanister) => { + // return await ic.call(myCanister.myQuery(myCanister)); + // } + // ) }); // Below we have a bunch of different configurations of where to put the the diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did index 7198db700f..82208ac4f9 100644 --- a/examples/recursion/src/recursive_canister/index.did +++ b/examples/recursion/src/recursive_canister/index.did @@ -1,9 +1,9 @@ -type rec_16 = service { - myQuery: (rec_16) -> (rec_16) query; +type rec_10 = service { + myQuery: (rec_10) -> (rec_10) query; }; -type rec_19 = service { - myQuery: (rec_19) -> (rec_19) query; +type rec_13 = service { + myQuery: (rec_13) -> (rec_13) query; }; service: () -> { - myQuery: (rec_16) -> (rec_19) query; + myQuery: (rec_10) -> (rec_13) query; } \ No newline at end of file From c032519905d332e49c1f37690e183db20573d194 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 09:33:22 -0600 Subject: [PATCH 17/37] get rid of need to call idlCallback when exporting --- examples/recursion/src/recursion/index.did | 93 ++++++++++--------- examples/recursion/src/recursion/index.ts | 4 +- .../recursion/src/recursive_canister/index.ts | 2 +- src/compiler/compile_typescript_code.ts | 12 ++- .../candid/reference/recursive.ts | 1 + 5 files changed, 65 insertions(+), 47 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index 8c4d50b764..6ad4a16aa8 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,49 +1,56 @@ -type rec_190 = func (rec_190) -> (rec_190) query; -type rec_193 = func (rec_193) -> (rec_193) query; type rec_198 = func (rec_198) -> (rec_198) query; -type rec_106 = record {myOpt:opt rec_106}; -type rec_109 = record {myOpt:opt rec_109}; -type rec_154 = record {myOpt:opt rec_154}; -type rec_122 = record {myVar:variant {num:int8; varRec:rec_122}}; -type rec_125 = record {myVar:variant {num:int8; varRec:rec_125}}; -type rec_162 = record {myVar:variant {num:int8; varRec:rec_162}}; -type rec_114 = record {myVecRecords:vec rec_114}; -type rec_117 = record {myVecRecords:vec rec_117}; -type rec_158 = record {myVecRecords:vec rec_158}; -type rec_202 = service { - myQuery: (rec_202) -> (rec_202) query; +type rec_201 = func (rec_201) -> (rec_201) query; +type rec_206 = func (rec_206) -> (rec_206) query; +type rec_114 = record {myOpt:opt rec_114}; +type rec_117 = record {myOpt:opt rec_117}; +type rec_162 = record {myOpt:opt rec_162}; +type rec_130 = record {myVar:variant {num:int8; varRec:rec_130}}; +type rec_133 = record {myVar:variant {num:int8; varRec:rec_133}}; +type rec_170 = record {myVar:variant {num:int8; varRec:rec_170}}; +type rec_122 = record {myVecRecords:vec rec_122}; +type rec_125 = record {myVecRecords:vec rec_125}; +type rec_166 = record {myVecRecords:vec rec_166}; +type rec_218 = service { + myQuery: (rec_218) -> (rec_218) query; }; -type rec_205 = service { - myQuery: (rec_205) -> (rec_205) query; +type rec_221 = service { + myQuery: (rec_221) -> (rec_221) query; }; -type rec_138 = record {opt rec_138; opt rec_138}; -type rec_141 = record {opt rec_141; opt rec_141}; -type rec_170 = record {opt rec_170; opt rec_170}; -type rec_178 = record {variant {num:int8; varTuple:rec_178}; variant {num:int8; varTuple:rec_178}}; -type rec_181 = record {variant {num:int8; varTuple:rec_181}; variant {num:int8; varTuple:rec_181}}; +type rec_210 = service { + myQuery: (rec_210) -> (rec_210) query; +}; +type rec_213 = service { + myQuery: (rec_213) -> (rec_213) query; +}; +type rec_146 = record {opt rec_146; opt rec_146}; +type rec_149 = record {opt rec_149; opt rec_149}; +type rec_178 = record {opt rec_178; opt rec_178}; type rec_186 = record {variant {num:int8; varTuple:rec_186}; variant {num:int8; varTuple:rec_186}}; -type rec_146 = record {vec rec_146; vec rec_146}; -type rec_149 = record {vec rec_149; vec rec_149}; -type rec_174 = record {vec rec_174; vec rec_174}; -type rec_130 = variant {num:int8; recVariant:rec_130}; -type rec_133 = variant {num:int8; recVariant:rec_133}; -type rec_166 = variant {num:int8; recVariant:rec_166}; +type rec_189 = record {variant {num:int8; varTuple:rec_189}; variant {num:int8; varTuple:rec_189}}; +type rec_194 = record {variant {num:int8; varTuple:rec_194}; variant {num:int8; varTuple:rec_194}}; +type rec_154 = record {vec rec_154; vec rec_154}; +type rec_157 = record {vec rec_157; vec rec_157}; +type rec_182 = record {vec rec_182; vec rec_182}; +type rec_138 = variant {num:int8; recVariant:rec_138}; +type rec_141 = variant {num:int8; recVariant:rec_141}; +type rec_174 = variant {num:int8; recVariant:rec_174}; service: () -> { - testRecFunc: (rec_190) -> (rec_193) query; - testRecFuncReturn: () -> (rec_198) query; - testRecRecordWithOpt: (rec_106) -> (rec_109) query; - testRecRecordWithOptReturn: () -> (rec_154) query; - testRecRecordWithVariant: (rec_122) -> (rec_125) query; - testRecRecordWithVariantReturn: () -> (rec_162) query; - testRecRecordWithVec: (rec_114) -> (rec_117) query; - testRecRecordWithVecReturn: () -> (rec_158) query; - testRecServiceSimple: (rec_202) -> (rec_205) query; - testRecTupleWithOpt: (rec_138) -> (rec_141) query; - testRecTupleWithOptReturn: () -> (rec_170) query; - testRecTupleWithVariant: (rec_178) -> (rec_181) query; - testRecTupleWithVariantReturn: () -> (rec_186) query; - testRecTupleWithVec: (rec_146) -> (rec_149) query; - testRecTupleWithVecReturn: () -> (rec_174) query; - testRecVariant: (rec_130) -> (rec_133) query; - testRecVariantReturn: () -> (rec_166) query; + testRecFunc: (rec_198) -> (rec_201) query; + testRecFuncReturn: () -> (rec_206) query; + testRecRecordWithOpt: (rec_114) -> (rec_117) query; + testRecRecordWithOptReturn: () -> (rec_162) query; + testRecRecordWithVariant: (rec_130) -> (rec_133) query; + testRecRecordWithVariantReturn: () -> (rec_170) query; + testRecRecordWithVec: (rec_122) -> (rec_125) query; + testRecRecordWithVecReturn: () -> (rec_166) query; + testRecService: (rec_218) -> (rec_221) query; + testRecServiceSimple: (rec_210) -> (rec_213) query; + testRecTupleWithOpt: (rec_146) -> (rec_149) query; + testRecTupleWithOptReturn: () -> (rec_178) query; + testRecTupleWithVariant: (rec_186) -> (rec_189) query; + testRecTupleWithVariantReturn: () -> (rec_194) query; + testRecTupleWithVec: (rec_154) -> (rec_157) query; + testRecTupleWithVecReturn: () -> (rec_182) query; + testRecVariant: (rec_138) -> (rec_141) query; + testRecVariantReturn: () -> (rec_174) query; } \ No newline at end of file diff --git a/examples/recursion/src/recursion/index.ts b/examples/recursion/src/recursion/index.ts index c600e8c7e1..961743b9eb 100644 --- a/examples/recursion/src/recursion/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -113,8 +113,8 @@ export default Canister({ Principal.fromText('aaaaa-aa'), 'create_canister' ]), - testRecServiceSimple: query([MyCanister], MyCanister, (param) => param) - // testRecService: query([MyFullCanister], MyFullCanister, (param) => param) + testRecServiceSimple: query([MyCanister], MyCanister, (param) => param), + testRecService: query([MyFullCanister], MyFullCanister, (param) => param) // testRecServiceReturn: query([], MyFullCanister, () => { // MyFullCanister( // // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? diff --git a/examples/recursion/src/recursive_canister/index.ts b/examples/recursion/src/recursive_canister/index.ts index 6bf65f831f..7ca4594c33 100644 --- a/examples/recursion/src/recursive_canister/index.ts +++ b/examples/recursion/src/recursive_canister/index.ts @@ -6,4 +6,4 @@ const MyCanister = Recursive(() => }) ); -export default MyCanister.idlCallback(); +export default MyCanister; diff --git a/src/compiler/compile_typescript_code.ts b/src/compiler/compile_typescript_code.ts index 790e11d844..b5320c82fc 100644 --- a/src/compiler/compile_typescript_code.ts +++ b/src/compiler/compile_typescript_code.ts @@ -35,7 +35,17 @@ export function compileTypeScriptToJavaScript( export * from './${main}'; import CanisterMethods from './${main}'; - export const canisterMethods = CanisterMethods(); + const getCanisterMethods = () => { + if (CanisterMethods._azleIsRecursive) { + return CanisterMethods.idlCallback(); + } else { + return CanisterMethods; + } + } + + const getCanisterMethodsResult = getCanisterMethods(); + export const canisterMethods = getCanisterMethodsResult(); + `; const canisterJavaScript = bundleAndTranspileJs(` diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index dd027ba0cc..f4ba67d5fd 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -8,6 +8,7 @@ export function Recursive any>(idlCallback: T): T { const result = { idlCallback, _azleName: name, + _azleIsRecursive: true, getIDL(parents: Parent[]) { const idl = IDL.Rec(); let filler = idlCallback(); From c6da764680f9b41c38b733bb00d0f867b4cfe493 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 10:07:31 -0600 Subject: [PATCH 18/37] rec service return type working --- examples/recursion/src/recursion/index.did | 122 ++++++++++++--------- examples/recursion/src/recursion/index.ts | 32 +++--- 2 files changed, 85 insertions(+), 69 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index 6ad4a16aa8..a333b91778 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,56 +1,70 @@ -type rec_198 = func (rec_198) -> (rec_198) query; -type rec_201 = func (rec_201) -> (rec_201) query; -type rec_206 = func (rec_206) -> (rec_206) query; -type rec_114 = record {myOpt:opt rec_114}; -type rec_117 = record {myOpt:opt rec_117}; -type rec_162 = record {myOpt:opt rec_162}; -type rec_130 = record {myVar:variant {num:int8; varRec:rec_130}}; -type rec_133 = record {myVar:variant {num:int8; varRec:rec_133}}; -type rec_170 = record {myVar:variant {num:int8; varRec:rec_170}}; -type rec_122 = record {myVecRecords:vec rec_122}; -type rec_125 = record {myVecRecords:vec rec_125}; -type rec_166 = record {myVecRecords:vec rec_166}; -type rec_218 = service { - myQuery: (rec_218) -> (rec_218) query; -}; -type rec_221 = service { - myQuery: (rec_221) -> (rec_221) query; -}; -type rec_210 = service { - myQuery: (rec_210) -> (rec_210) query; -}; -type rec_213 = service { - myQuery: (rec_213) -> (rec_213) query; -}; -type rec_146 = record {opt rec_146; opt rec_146}; -type rec_149 = record {opt rec_149; opt rec_149}; -type rec_178 = record {opt rec_178; opt rec_178}; -type rec_186 = record {variant {num:int8; varTuple:rec_186}; variant {num:int8; varTuple:rec_186}}; -type rec_189 = record {variant {num:int8; varTuple:rec_189}; variant {num:int8; varTuple:rec_189}}; -type rec_194 = record {variant {num:int8; varTuple:rec_194}; variant {num:int8; varTuple:rec_194}}; -type rec_154 = record {vec rec_154; vec rec_154}; -type rec_157 = record {vec rec_157; vec rec_157}; -type rec_182 = record {vec rec_182; vec rec_182}; -type rec_138 = variant {num:int8; recVariant:rec_138}; -type rec_141 = variant {num:int8; recVariant:rec_141}; -type rec_174 = variant {num:int8; recVariant:rec_174}; +type rec_214 = func (rec_214) -> (rec_214) query; +type rec_217 = func (rec_217) -> (rec_217) query; +type rec_222 = func (rec_222) -> (rec_222) query; +type rec_130 = record {myOpt:opt rec_130}; +type rec_133 = record {myOpt:opt rec_133}; +type rec_178 = record {myOpt:opt rec_178}; +type rec_146 = record {myVar:variant {num:int8; varRec:rec_146}}; +type rec_149 = record {myVar:variant {num:int8; varRec:rec_149}}; +type rec_186 = record {myVar:variant {num:int8; varRec:rec_186}}; +type rec_138 = record {myVecRecords:vec rec_138}; +type rec_141 = record {myVecRecords:vec rec_141}; +type rec_182 = record {myVecRecords:vec rec_182}; +type rec_234 = service { + myQuery: (rec_234) -> (rec_234) query; +}; +type rec_237 = service { + myQuery: (rec_237) -> (rec_237) query; +}; +type rec_247 = service { + myQuery: (rec_247) -> (rec_247) query; +}; +type rec_248 = service { + myQuery: (rec_248) -> (rec_248) query; +}; +type rec_252 = service { + myQuery: (rec_252) -> (rec_252) query; +}; +type rec_242 = service { + myQuery: (rec_242) -> (rec_242) query; +}; +type rec_226 = service { + myQuery: (rec_226) -> (rec_226) query; +}; +type rec_229 = service { + myQuery: (rec_229) -> (rec_229) query; +}; +type rec_162 = record {opt rec_162; opt rec_162}; +type rec_165 = record {opt rec_165; opt rec_165}; +type rec_194 = record {opt rec_194; opt rec_194}; +type rec_202 = record {variant {num:int8; varTuple:rec_202}; variant {num:int8; varTuple:rec_202}}; +type rec_205 = record {variant {num:int8; varTuple:rec_205}; variant {num:int8; varTuple:rec_205}}; +type rec_210 = record {variant {num:int8; varTuple:rec_210}; variant {num:int8; varTuple:rec_210}}; +type rec_170 = record {vec rec_170; vec rec_170}; +type rec_173 = record {vec rec_173; vec rec_173}; +type rec_198 = record {vec rec_198; vec rec_198}; +type rec_154 = variant {num:int8; recVariant:rec_154}; +type rec_157 = variant {num:int8; recVariant:rec_157}; +type rec_190 = variant {num:int8; recVariant:rec_190}; service: () -> { - testRecFunc: (rec_198) -> (rec_201) query; - testRecFuncReturn: () -> (rec_206) query; - testRecRecordWithOpt: (rec_114) -> (rec_117) query; - testRecRecordWithOptReturn: () -> (rec_162) query; - testRecRecordWithVariant: (rec_130) -> (rec_133) query; - testRecRecordWithVariantReturn: () -> (rec_170) query; - testRecRecordWithVec: (rec_122) -> (rec_125) query; - testRecRecordWithVecReturn: () -> (rec_166) query; - testRecService: (rec_218) -> (rec_221) query; - testRecServiceSimple: (rec_210) -> (rec_213) query; - testRecTupleWithOpt: (rec_146) -> (rec_149) query; - testRecTupleWithOptReturn: () -> (rec_178) query; - testRecTupleWithVariant: (rec_186) -> (rec_189) query; - testRecTupleWithVariantReturn: () -> (rec_194) query; - testRecTupleWithVec: (rec_154) -> (rec_157) query; - testRecTupleWithVecReturn: () -> (rec_182) query; - testRecVariant: (rec_138) -> (rec_141) query; - testRecVariantReturn: () -> (rec_174) query; + testRecFunc: (rec_214) -> (rec_217) query; + testRecFuncReturn: () -> (rec_222) query; + testRecRecordWithOpt: (rec_130) -> (rec_133) query; + testRecRecordWithOptReturn: () -> (rec_178) query; + testRecRecordWithVariant: (rec_146) -> (rec_149) query; + testRecRecordWithVariantReturn: () -> (rec_186) query; + testRecRecordWithVec: (rec_138) -> (rec_141) query; + testRecRecordWithVecReturn: () -> (rec_182) query; + testRecService: (rec_234) -> (rec_237) query; + testRecServiceCall: (rec_247, rec_248) -> (rec_252) ; + testRecServiceReturn: () -> (rec_242) query; + testRecServiceSimple: (rec_226) -> (rec_229) query; + testRecTupleWithOpt: (rec_162) -> (rec_165) query; + testRecTupleWithOptReturn: () -> (rec_194) query; + testRecTupleWithVariant: (rec_202) -> (rec_205) query; + testRecTupleWithVariantReturn: () -> (rec_210) query; + testRecTupleWithVec: (rec_170) -> (rec_173) query; + testRecTupleWithVecReturn: () -> (rec_198) query; + testRecVariant: (rec_154) -> (rec_157) query; + testRecVariantReturn: () -> (rec_190) query; } \ No newline at end of file diff --git a/examples/recursion/src/recursion/index.ts b/examples/recursion/src/recursion/index.ts index 961743b9eb..324e529794 100644 --- a/examples/recursion/src/recursion/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -114,21 +114,23 @@ export default Canister({ 'create_canister' ]), testRecServiceSimple: query([MyCanister], MyCanister, (param) => param), - testRecService: query([MyFullCanister], MyFullCanister, (param) => param) - // testRecServiceReturn: query([], MyFullCanister, () => { - // MyFullCanister( - // // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? - // Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? - // ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') - // ); - // }), - // testRecServiceCall: update( - // [MyFullCanister], - // MyFullCanister, - // async (myCanister) => { - // return await ic.call(myCanister.myQuery(myCanister)); - // } - // ) + testRecService: query([MyFullCanister], MyFullCanister, (param) => param), + testRecServiceReturn: query([], MyFullCanister, () => { + return MyFullCanister.idlCallback()( + // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? + Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? + ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + ); + }), + testRecServiceCall: update( + [MyFullCanister], + MyFullCanister, + async (myFullCanister) => { + return await ic.call(myFullCanister.myQuery, { + args: [myFullCanister] + }); + } + ) }); // Below we have a bunch of different configurations of where to put the the From 774acc6b9fcc6ef400b41c7f2c59a1320cdbc0fd Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 10:19:11 -0600 Subject: [PATCH 19/37] get rid of idlCallback --- examples/recursion/src/recursion/index.did | 119 +++++++++--------- examples/recursion/src/recursion/index.ts | 2 +- src/compiler/compile_typescript_code.ts | 11 +- .../candid/reference/recursive.ts | 29 +++-- src/lib_new/visitors/encode_decode/index.ts | 2 +- 5 files changed, 78 insertions(+), 85 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index a333b91778..2eaeb9a700 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,70 +1,67 @@ -type rec_214 = func (rec_214) -> (rec_214) query; -type rec_217 = func (rec_217) -> (rec_217) query; -type rec_222 = func (rec_222) -> (rec_222) query; -type rec_130 = record {myOpt:opt rec_130}; -type rec_133 = record {myOpt:opt rec_133}; -type rec_178 = record {myOpt:opt rec_178}; -type rec_146 = record {myVar:variant {num:int8; varRec:rec_146}}; -type rec_149 = record {myVar:variant {num:int8; varRec:rec_149}}; -type rec_186 = record {myVar:variant {num:int8; varRec:rec_186}}; -type rec_138 = record {myVecRecords:vec rec_138}; -type rec_141 = record {myVecRecords:vec rec_141}; -type rec_182 = record {myVecRecords:vec rec_182}; -type rec_234 = service { - myQuery: (rec_234) -> (rec_234) query; +type rec_210 = func (rec_210) -> (rec_210) query; +type rec_213 = func (rec_213) -> (rec_213) query; +type rec_218 = func (rec_218) -> (rec_218) query; +type rec_126 = record {myOpt:opt rec_126}; +type rec_129 = record {myOpt:opt rec_129}; +type rec_174 = record {myOpt:opt rec_174}; +type rec_142 = record {myVar:variant {num:int8; varRec:rec_142}}; +type rec_145 = record {myVar:variant {num:int8; varRec:rec_145}}; +type rec_182 = record {myVar:variant {num:int8; varRec:rec_182}}; +type rec_134 = record {myVecRecords:vec rec_134}; +type rec_137 = record {myVecRecords:vec rec_137}; +type rec_178 = record {myVecRecords:vec rec_178}; +type rec_230 = service { + myQuery: (rec_230) -> (rec_230) query; }; -type rec_237 = service { - myQuery: (rec_237) -> (rec_237) query; -}; -type rec_247 = service { - myQuery: (rec_247) -> (rec_247) query; -}; -type rec_248 = service { - myQuery: (rec_248) -> (rec_248) query; -}; -type rec_252 = service { - myQuery: (rec_252) -> (rec_252) query; +type rec_233 = service { + myQuery: (rec_233) -> (rec_233) query; }; type rec_242 = service { myQuery: (rec_242) -> (rec_242) query; }; -type rec_226 = service { - myQuery: (rec_226) -> (rec_226) query; +type rec_245 = service { + myQuery: (rec_245) -> (rec_245) query; +}; +type rec_238 = service { + myQuery: (rec_238) -> (rec_238) query; +}; +type rec_222 = service { + myQuery: (rec_222) -> (rec_222) query; }; -type rec_229 = service { - myQuery: (rec_229) -> (rec_229) query; +type rec_225 = service { + myQuery: (rec_225) -> (rec_225) query; }; -type rec_162 = record {opt rec_162; opt rec_162}; -type rec_165 = record {opt rec_165; opt rec_165}; -type rec_194 = record {opt rec_194; opt rec_194}; -type rec_202 = record {variant {num:int8; varTuple:rec_202}; variant {num:int8; varTuple:rec_202}}; -type rec_205 = record {variant {num:int8; varTuple:rec_205}; variant {num:int8; varTuple:rec_205}}; -type rec_210 = record {variant {num:int8; varTuple:rec_210}; variant {num:int8; varTuple:rec_210}}; -type rec_170 = record {vec rec_170; vec rec_170}; -type rec_173 = record {vec rec_173; vec rec_173}; -type rec_198 = record {vec rec_198; vec rec_198}; -type rec_154 = variant {num:int8; recVariant:rec_154}; -type rec_157 = variant {num:int8; recVariant:rec_157}; -type rec_190 = variant {num:int8; recVariant:rec_190}; +type rec_158 = record {opt rec_158; opt rec_158}; +type rec_161 = record {opt rec_161; opt rec_161}; +type rec_190 = record {opt rec_190; opt rec_190}; +type rec_198 = record {variant {num:int8; varTuple:rec_198}; variant {num:int8; varTuple:rec_198}}; +type rec_201 = record {variant {num:int8; varTuple:rec_201}; variant {num:int8; varTuple:rec_201}}; +type rec_206 = record {variant {num:int8; varTuple:rec_206}; variant {num:int8; varTuple:rec_206}}; +type rec_166 = record {vec rec_166; vec rec_166}; +type rec_169 = record {vec rec_169; vec rec_169}; +type rec_194 = record {vec rec_194; vec rec_194}; +type rec_150 = variant {num:int8; recVariant:rec_150}; +type rec_153 = variant {num:int8; recVariant:rec_153}; +type rec_186 = variant {num:int8; recVariant:rec_186}; service: () -> { - testRecFunc: (rec_214) -> (rec_217) query; - testRecFuncReturn: () -> (rec_222) query; - testRecRecordWithOpt: (rec_130) -> (rec_133) query; - testRecRecordWithOptReturn: () -> (rec_178) query; - testRecRecordWithVariant: (rec_146) -> (rec_149) query; - testRecRecordWithVariantReturn: () -> (rec_186) query; - testRecRecordWithVec: (rec_138) -> (rec_141) query; - testRecRecordWithVecReturn: () -> (rec_182) query; - testRecService: (rec_234) -> (rec_237) query; - testRecServiceCall: (rec_247, rec_248) -> (rec_252) ; - testRecServiceReturn: () -> (rec_242) query; - testRecServiceSimple: (rec_226) -> (rec_229) query; - testRecTupleWithOpt: (rec_162) -> (rec_165) query; - testRecTupleWithOptReturn: () -> (rec_194) query; - testRecTupleWithVariant: (rec_202) -> (rec_205) query; - testRecTupleWithVariantReturn: () -> (rec_210) query; - testRecTupleWithVec: (rec_170) -> (rec_173) query; - testRecTupleWithVecReturn: () -> (rec_198) query; - testRecVariant: (rec_154) -> (rec_157) query; - testRecVariantReturn: () -> (rec_190) query; + testRecFunc: (rec_210) -> (rec_213) query; + testRecFuncReturn: () -> (rec_218) query; + testRecRecordWithOpt: (rec_126) -> (rec_129) query; + testRecRecordWithOptReturn: () -> (rec_174) query; + testRecRecordWithVariant: (rec_142) -> (rec_145) query; + testRecRecordWithVariantReturn: () -> (rec_182) query; + testRecRecordWithVec: (rec_134) -> (rec_137) query; + testRecRecordWithVecReturn: () -> (rec_178) query; + testRecService: (rec_230) -> (rec_233) query; + testRecServiceCall: (rec_242) -> (rec_245) ; + testRecServiceReturn: () -> (rec_238) query; + testRecServiceSimple: (rec_222) -> (rec_225) query; + testRecTupleWithOpt: (rec_158) -> (rec_161) query; + testRecTupleWithOptReturn: () -> (rec_190) query; + testRecTupleWithVariant: (rec_198) -> (rec_201) query; + testRecTupleWithVariantReturn: () -> (rec_206) query; + testRecTupleWithVec: (rec_166) -> (rec_169) query; + testRecTupleWithVecReturn: () -> (rec_194) query; + testRecVariant: (rec_150) -> (rec_153) query; + testRecVariantReturn: () -> (rec_186) query; } \ No newline at end of file diff --git a/examples/recursion/src/recursion/index.ts b/examples/recursion/src/recursion/index.ts index 324e529794..221f39079d 100644 --- a/examples/recursion/src/recursion/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -116,7 +116,7 @@ export default Canister({ testRecServiceSimple: query([MyCanister], MyCanister, (param) => param), testRecService: query([MyFullCanister], MyFullCanister, (param) => param), testRecServiceReturn: query([], MyFullCanister, () => { - return MyFullCanister.idlCallback()( + return MyFullCanister( // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') diff --git a/src/compiler/compile_typescript_code.ts b/src/compiler/compile_typescript_code.ts index b5320c82fc..a0fecc4104 100644 --- a/src/compiler/compile_typescript_code.ts +++ b/src/compiler/compile_typescript_code.ts @@ -35,16 +35,7 @@ export function compileTypeScriptToJavaScript( export * from './${main}'; import CanisterMethods from './${main}'; - const getCanisterMethods = () => { - if (CanisterMethods._azleIsRecursive) { - return CanisterMethods.idlCallback(); - } else { - return CanisterMethods; - } - } - - const getCanisterMethodsResult = getCanisterMethods(); - export const canisterMethods = getCanisterMethodsResult(); + export const canisterMethods = CanisterMethods(); `; diff --git a/src/lib_functional/candid/reference/recursive.ts b/src/lib_functional/candid/reference/recursive.ts index f4ba67d5fd..83ee4a69f3 100644 --- a/src/lib_functional/candid/reference/recursive.ts +++ b/src/lib_functional/candid/reference/recursive.ts @@ -5,19 +5,24 @@ import { Parent } from '../../../lib_new/utils'; export function Recursive any>(idlCallback: T): T { const name = v4(); - const result = { - idlCallback, - _azleName: name, - _azleIsRecursive: true, - getIDL(parents: Parent[]) { - const idl = IDL.Rec(); - let filler = idlCallback(); - if (filler._azleIsCanister) { - filler = filler(result); - } - idl.fill(filler.getIDL([...parents, { idl: idl, name }])); - return idl; + let result = (...args: any[]) => { + const idl = idlCallback(); + if (idl._azleIsCanister) { + return idl(...args); } + return idl; + }; + + result._azleName = name; + result._azleIsRecursive = true; + result.getIDL = (parents: Parent[]) => { + const idl = IDL.Rec(); + let filler = idlCallback(); + if (filler._azleIsCanister) { + filler = filler(result); + } + idl.fill(filler.getIDL([...parents, { idl: idl, name }])); + return idl; }; return result; diff --git a/src/lib_new/visitors/encode_decode/index.ts b/src/lib_new/visitors/encode_decode/index.ts index 4fe48c4658..b2119a5dd9 100644 --- a/src/lib_new/visitors/encode_decode/index.ts +++ b/src/lib_new/visitors/encode_decode/index.ts @@ -142,7 +142,7 @@ export function visitRec( ty: IDL.ConstructType, data: VisitorData ): VisitorResult { - let js_class = data.js_class.idlCallback(); + let js_class = data.js_class(); if (js_class._azleIsCanister) { js_class = js_class([]); } From dbf75dd10c10ef5614836a0a4eeac410d0cb6558 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 13:07:08 -0600 Subject: [PATCH 20/37] update to candid files --- .../src/canister1/index.did | 18 ++- .../src/canister2/index.did | 19 ++- examples/recursion/src/recursion/index.did | 116 +++++++++--------- .../src/recursive_canister/index.did | 10 +- 4 files changed, 79 insertions(+), 84 deletions(-) diff --git a/examples/cross_canister_calls/src/canister1/index.did b/examples/cross_canister_calls/src/canister1/index.did index 36003a4a00..8485841545 100644 --- a/examples/cross_canister_calls/src/canister1/index.did +++ b/examples/cross_canister_calls/src/canister1/index.did @@ -1,11 +1,9 @@ -type rec_3 = record {id:text}; -type rec_4 = record {id:text; balance:nat64}; -type rec_5 = record {id:text; balance:nat64}; service: () -> { - transfer: (text, text, nat64) -> (nat64); - balance: (text) -> (nat64); - account: (rec_3) -> (opt rec_4); - accounts: () -> (vec rec_5); - trap: () -> (text); - sendNotification: () -> (); -} + account: (record {id:text}) -> (opt record {id:text; balance:nat64}) ; + accounts: () -> (vec record {id:text; balance:nat64}) ; + balance: (text) -> (nat64) ; + init: () -> () query; + sendNotification: () -> () ; + transfer: (text, text, nat64) -> (nat64) ; + trap: () -> (text) ; +} \ No newline at end of file diff --git a/examples/cross_canister_calls/src/canister2/index.did b/examples/cross_canister_calls/src/canister2/index.did index 83ffe987ef..81034884ad 100644 --- a/examples/cross_canister_calls/src/canister2/index.did +++ b/examples/cross_canister_calls/src/canister2/index.did @@ -1,12 +1,9 @@ -type rec_0 = record {id:text}; -type rec_1 = record {id:text; balance:nat64}; -type rec_2 = record {id:text; balance:nat64}; service: () -> { - transfer: (text, text, nat64) -> (nat64); - balance: (text) -> (nat64) query; - account: (rec_0) -> (opt rec_1) query; - accounts: () -> (vec rec_2) query; - trap: () -> (text) query; - receiveNotification: (text) -> (); - getNotification: () -> (text) query; -} + account: (record {id:text}) -> (opt record {id:text; balance:nat64}) query; + accounts: () -> (vec record {id:text; balance:nat64}) query; + balance: (text) -> (nat64) query; + getNotification: () -> (text) query; + receiveNotification: (text) -> () ; + transfer: (text, text, nat64) -> (nat64) ; + trap: () -> (text) query; +} \ No newline at end of file diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index 2eaeb9a700..1b3b308f39 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,67 +1,67 @@ -type rec_210 = func (rec_210) -> (rec_210) query; -type rec_213 = func (rec_213) -> (rec_213) query; -type rec_218 = func (rec_218) -> (rec_218) query; -type rec_126 = record {myOpt:opt rec_126}; -type rec_129 = record {myOpt:opt rec_129}; -type rec_174 = record {myOpt:opt rec_174}; -type rec_142 = record {myVar:variant {num:int8; varRec:rec_142}}; -type rec_145 = record {myVar:variant {num:int8; varRec:rec_145}}; -type rec_182 = record {myVar:variant {num:int8; varRec:rec_182}}; -type rec_134 = record {myVecRecords:vec rec_134}; -type rec_137 = record {myVecRecords:vec rec_137}; -type rec_178 = record {myVecRecords:vec rec_178}; -type rec_230 = service { - myQuery: (rec_230) -> (rec_230) query; +type rec_365 = func (rec_365) -> (rec_365) query; +type rec_368 = func (rec_368) -> (rec_368) query; +type rec_373 = func (rec_373) -> (rec_373) query; +type rec_281 = record {myOpt:opt rec_281}; +type rec_284 = record {myOpt:opt rec_284}; +type rec_329 = record {myOpt:opt rec_329}; +type rec_297 = record {myVar:variant {num:int8; varRec:rec_297}}; +type rec_300 = record {myVar:variant {num:int8; varRec:rec_300}}; +type rec_337 = record {myVar:variant {num:int8; varRec:rec_337}}; +type rec_289 = record {myVecRecords:vec rec_289}; +type rec_292 = record {myVecRecords:vec rec_292}; +type rec_333 = record {myVecRecords:vec rec_333}; +type rec_385 = service { + myQuery: (rec_385) -> (rec_385) query; }; -type rec_233 = service { - myQuery: (rec_233) -> (rec_233) query; +type rec_388 = service { + myQuery: (rec_388) -> (rec_388) query; }; -type rec_242 = service { - myQuery: (rec_242) -> (rec_242) query; +type rec_397 = service { + myQuery: (rec_397) -> (rec_397) query; }; -type rec_245 = service { - myQuery: (rec_245) -> (rec_245) query; +type rec_400 = service { + myQuery: (rec_400) -> (rec_400) query; }; -type rec_238 = service { - myQuery: (rec_238) -> (rec_238) query; +type rec_393 = service { + myQuery: (rec_393) -> (rec_393) query; }; -type rec_222 = service { - myQuery: (rec_222) -> (rec_222) query; +type rec_377 = service { + myQuery: (rec_377) -> (rec_377) query; }; -type rec_225 = service { - myQuery: (rec_225) -> (rec_225) query; +type rec_380 = service { + myQuery: (rec_380) -> (rec_380) query; }; -type rec_158 = record {opt rec_158; opt rec_158}; -type rec_161 = record {opt rec_161; opt rec_161}; -type rec_190 = record {opt rec_190; opt rec_190}; -type rec_198 = record {variant {num:int8; varTuple:rec_198}; variant {num:int8; varTuple:rec_198}}; -type rec_201 = record {variant {num:int8; varTuple:rec_201}; variant {num:int8; varTuple:rec_201}}; -type rec_206 = record {variant {num:int8; varTuple:rec_206}; variant {num:int8; varTuple:rec_206}}; -type rec_166 = record {vec rec_166; vec rec_166}; -type rec_169 = record {vec rec_169; vec rec_169}; -type rec_194 = record {vec rec_194; vec rec_194}; -type rec_150 = variant {num:int8; recVariant:rec_150}; -type rec_153 = variant {num:int8; recVariant:rec_153}; -type rec_186 = variant {num:int8; recVariant:rec_186}; +type rec_313 = record {opt rec_313; opt rec_313}; +type rec_316 = record {opt rec_316; opt rec_316}; +type rec_345 = record {opt rec_345; opt rec_345}; +type rec_353 = record {variant {num:int8; varTuple:rec_353}; variant {num:int8; varTuple:rec_353}}; +type rec_356 = record {variant {num:int8; varTuple:rec_356}; variant {num:int8; varTuple:rec_356}}; +type rec_361 = record {variant {num:int8; varTuple:rec_361}; variant {num:int8; varTuple:rec_361}}; +type rec_321 = record {vec rec_321; vec rec_321}; +type rec_324 = record {vec rec_324; vec rec_324}; +type rec_349 = record {vec rec_349; vec rec_349}; +type rec_305 = variant {num:int8; recVariant:rec_305}; +type rec_308 = variant {num:int8; recVariant:rec_308}; +type rec_341 = variant {num:int8; recVariant:rec_341}; service: () -> { - testRecFunc: (rec_210) -> (rec_213) query; - testRecFuncReturn: () -> (rec_218) query; - testRecRecordWithOpt: (rec_126) -> (rec_129) query; - testRecRecordWithOptReturn: () -> (rec_174) query; - testRecRecordWithVariant: (rec_142) -> (rec_145) query; - testRecRecordWithVariantReturn: () -> (rec_182) query; - testRecRecordWithVec: (rec_134) -> (rec_137) query; - testRecRecordWithVecReturn: () -> (rec_178) query; - testRecService: (rec_230) -> (rec_233) query; - testRecServiceCall: (rec_242) -> (rec_245) ; - testRecServiceReturn: () -> (rec_238) query; - testRecServiceSimple: (rec_222) -> (rec_225) query; - testRecTupleWithOpt: (rec_158) -> (rec_161) query; - testRecTupleWithOptReturn: () -> (rec_190) query; - testRecTupleWithVariant: (rec_198) -> (rec_201) query; - testRecTupleWithVariantReturn: () -> (rec_206) query; - testRecTupleWithVec: (rec_166) -> (rec_169) query; - testRecTupleWithVecReturn: () -> (rec_194) query; - testRecVariant: (rec_150) -> (rec_153) query; - testRecVariantReturn: () -> (rec_186) query; + testRecFunc: (rec_365) -> (rec_368) query; + testRecFuncReturn: () -> (rec_373) query; + testRecRecordWithOpt: (rec_281) -> (rec_284) query; + testRecRecordWithOptReturn: () -> (rec_329) query; + testRecRecordWithVariant: (rec_297) -> (rec_300) query; + testRecRecordWithVariantReturn: () -> (rec_337) query; + testRecRecordWithVec: (rec_289) -> (rec_292) query; + testRecRecordWithVecReturn: () -> (rec_333) query; + testRecService: (rec_385) -> (rec_388) query; + testRecServiceCall: (rec_397) -> (rec_400) ; + testRecServiceReturn: () -> (rec_393) query; + testRecServiceSimple: (rec_377) -> (rec_380) query; + testRecTupleWithOpt: (rec_313) -> (rec_316) query; + testRecTupleWithOptReturn: () -> (rec_345) query; + testRecTupleWithVariant: (rec_353) -> (rec_356) query; + testRecTupleWithVariantReturn: () -> (rec_361) query; + testRecTupleWithVec: (rec_321) -> (rec_324) query; + testRecTupleWithVecReturn: () -> (rec_349) query; + testRecVariant: (rec_305) -> (rec_308) query; + testRecVariantReturn: () -> (rec_341) query; } \ No newline at end of file diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did index 82208ac4f9..b2f5f7c53e 100644 --- a/examples/recursion/src/recursive_canister/index.did +++ b/examples/recursion/src/recursive_canister/index.did @@ -1,9 +1,9 @@ -type rec_10 = service { - myQuery: (rec_10) -> (rec_10) query; +type rec_20 = service { + myQuery: (rec_20) -> (rec_20) query; }; -type rec_13 = service { - myQuery: (rec_13) -> (rec_13) query; +type rec_23 = service { + myQuery: (rec_23) -> (rec_23) query; }; service: () -> { - myQuery: (rec_10) -> (rec_13) query; + myQuery: (rec_20) -> (rec_23) query; } \ No newline at end of file From 407c7f9d7e7342a773a79c788c31f8c526f8cc66 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 13:47:14 -0600 Subject: [PATCH 21/37] get complex types test passing --- .github/workflows/test.yml | 2 +- examples/complex_types/dfx.json | 3 +- .../complex_types/src/candid_types/index.ts | 48 +++++++++++ .../complex_types/src/candid_types/post.ts | 21 ----- .../src/candid_types/reaction.ts | 18 ---- .../src/candid_types/reaction_type.ts | 12 --- .../complex_types/src/candid_types/thread.ts | 17 ---- .../complex_types/src/candid_types/user.ts | 21 ----- examples/complex_types/src/index.did | 59 ++++++++++++- examples/complex_types/src/index.ts | 86 ++++++++----------- examples/complex_types/src/posts.ts | 12 +-- examples/complex_types/src/reactions.ts | 15 ++-- examples/complex_types/src/threads.ts | 12 +-- examples/complex_types/src/users.ts | 12 +-- 14 files changed, 171 insertions(+), 167 deletions(-) create mode 100644 examples/complex_types/src/candid_types/index.ts delete mode 100644 examples/complex_types/src/candid_types/post.ts delete mode 100644 examples/complex_types/src/candid_types/reaction.ts delete mode 100644 examples/complex_types/src/candid_types/reaction_type.ts delete mode 100644 examples/complex_types/src/candid_types/thread.ts delete mode 100644 examples/complex_types/src/candid_types/user.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a95608d7a..375e87d808 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,6 @@ # The check-basic-integration-tests-success job is designed to ensure that all jobs spun up from the matrix in the basic-integration-tests have succeeded # All Examples TODO restore when https://github.com/demergent-labs/azle/issues/1192 is resolved -# "examples/complex_types", # "examples/func_types", # "examples/generics", # "examples/motoko_examples/superheroes", # blocked by recursive @@ -74,6 +73,7 @@ jobs: "examples/candid_encoding", "examples/canister", "examples/complex_init", + "examples/complex_types", "examples/composite_queries", "examples/counter", "examples/cross_canister_calls", diff --git a/examples/complex_types/dfx.json b/examples/complex_types/dfx.json index ac87899737..e572d2a5cb 100644 --- a/examples/complex_types/dfx.json +++ b/examples/complex_types/dfx.json @@ -5,7 +5,8 @@ "main": "src/index.ts", "build": "npx azle complex_types", "candid": "src/index.did", - "wasm": ".azle/complex_types/complex_types.wasm.gz", + "wasm": ".azle/complex_types/complex_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/complex_types", "node_compatibility": true diff --git a/examples/complex_types/src/candid_types/index.ts b/examples/complex_types/src/candid_types/index.ts new file mode 100644 index 0000000000..0294f5880d --- /dev/null +++ b/examples/complex_types/src/candid_types/index.ts @@ -0,0 +1,48 @@ +import { Record, Null, text, Variant, Vec, Recursive } from 'azle'; + +export const ReactionType = Variant({ + Fire: Null, + ThumbsUp: Null, + ThumbsDown: Null +}); + +export const User = Recursive(() => + Record({ + id: text, + posts: Vec(Post), + reactions: Vec(Reaction), + threads: Vec(Thread), + username: text + }) +); + +export const Post = Recursive(() => + Record({ + id: text, + + author: User, + + reactions: Vec(Reaction), + + text: text, + + thread: Thread + }) +); + +export const Thread = Record({ + id: text, + + author: User, + + posts: Vec(Post), + + title: text +}); + +export const Reaction = Record({ + id: text, + author: User, + post: Post, + reactionType: ReactionType +}); diff --git a/examples/complex_types/src/candid_types/post.ts b/examples/complex_types/src/candid_types/post.ts deleted file mode 100644 index 341b02421c..0000000000 --- a/examples/complex_types/src/candid_types/post.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Reaction } from './reaction'; -import { Thread } from './thread'; -import { User } from './user'; - -export class Post extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Vec(Reaction)) - reactions: Vec; - - @candid(text) - text: text; - - @candid(Thread) - thread: Thread; -} diff --git a/examples/complex_types/src/candid_types/reaction.ts b/examples/complex_types/src/candid_types/reaction.ts deleted file mode 100644 index 57e936eefb..0000000000 --- a/examples/complex_types/src/candid_types/reaction.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { candid, Record, text } from 'azle'; -import { Post } from './post'; -import { ReactionType } from './reaction_type'; -import { User } from './user'; - -export class Reaction extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Post) - post: Post; - - @candid(ReactionType) - reactionType: ReactionType; -} diff --git a/examples/complex_types/src/candid_types/reaction_type.ts b/examples/complex_types/src/candid_types/reaction_type.ts deleted file mode 100644 index c44853365f..0000000000 --- a/examples/complex_types/src/candid_types/reaction_type.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { candid, Null, Variant } from 'azle'; - -export class ReactionType extends Variant { - @candid(Null) - Fire?: null; - - @candid(Null) - ThumbsUp?: null; - - @candid(Null) - ThumbsDown?: null; -} diff --git a/examples/complex_types/src/candid_types/thread.ts b/examples/complex_types/src/candid_types/thread.ts deleted file mode 100644 index 0fca81eb31..0000000000 --- a/examples/complex_types/src/candid_types/thread.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Post } from './post'; -import { User } from './user'; - -export class Thread extends Record { - @candid(text) - id: text; - - @candid(User) - author: User; - - @candid(Vec(Post)) - posts: Vec; - - @candid(text) - title: text; -} diff --git a/examples/complex_types/src/candid_types/user.ts b/examples/complex_types/src/candid_types/user.ts deleted file mode 100644 index 1aaf8353fd..0000000000 --- a/examples/complex_types/src/candid_types/user.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { candid, Record, text, Vec } from 'azle'; -import { Post } from './post'; -import { Reaction } from './reaction'; -import { Thread } from './thread'; - -export class User extends Record { - @candid(text) - id: text; - - @candid(Vec(Post)) - posts: Vec; - - @candid(Vec(Reaction)) - reactions: Vec; - - @candid(Vec(Thread)) - threads: Vec; - - @candid(text) - username: text; -} diff --git a/examples/complex_types/src/index.did b/examples/complex_types/src/index.did index 8904ac346b..bee0f6b3f1 100644 --- a/examples/complex_types/src/index.did +++ b/examples/complex_types/src/index.did @@ -1,3 +1,58 @@ +type rec_441 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_441; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_441; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_443 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_443; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_443; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_442 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_442; posts:vec rec_440}; posts:vec rec_440; reactions:vec record {id:text; post:rec_440; author:rec_442; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_440 = record {id:text; text:text; author:rec_441; thread:record {id:text; title:text; author:rec_443; posts:vec rec_440}; reactions:vec record {id:text; post:rec_440; author:rec_442; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_485 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_485; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_485; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_487 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_487; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_487; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_486 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_486; posts:vec rec_484}; posts:vec rec_484; reactions:vec record {id:text; post:rec_484; author:rec_486; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_484 = record {id:text; text:text; author:rec_485; thread:record {id:text; title:text; author:rec_487; posts:vec rec_484}; reactions:vec record {id:text; post:rec_484; author:rec_486; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_483 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_483}; reactions:vec record {id:text; post:rec_483; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_481 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_481}; reactions:vec record {id:text; post:rec_481; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_482 = record {id:text; text:text; author:rec_480; thread:record {id:text; title:text; author:rec_480; posts:vec rec_482}; reactions:vec record {id:text; post:rec_482; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_480 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_480; posts:vec rec_483}; posts:vec rec_481; reactions:vec record {id:text; post:rec_482; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_547 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_547}; reactions:vec record {id:text; post:rec_547; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_545 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_545}; reactions:vec record {id:text; post:rec_545; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_546 = record {id:text; text:text; author:rec_544; thread:record {id:text; title:text; author:rec_544; posts:vec rec_546}; reactions:vec record {id:text; post:rec_546; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_544 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_544; posts:vec rec_547}; posts:vec rec_545; reactions:vec record {id:text; post:rec_546; author:rec_544; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_549 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_549; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_549; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_551 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_551; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_551; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_550 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_550; posts:vec rec_548}; posts:vec rec_548; reactions:vec record {id:text; post:rec_548; author:rec_550; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_548 = record {id:text; text:text; author:rec_549; thread:record {id:text; title:text; author:rec_551; posts:vec rec_548}; reactions:vec record {id:text; post:rec_548; author:rec_550; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_603 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_603}; reactions:vec record {id:text; post:rec_603; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_601 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_601}; reactions:vec record {id:text; post:rec_601; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_602 = record {id:text; text:text; author:rec_600; thread:record {id:text; title:text; author:rec_600; posts:vec rec_602}; reactions:vec record {id:text; post:rec_602; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_600 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_600; posts:vec rec_603}; posts:vec rec_601; reactions:vec record {id:text; post:rec_602; author:rec_600; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_457 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_457; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_457; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_459 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_459; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_459; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_458 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_458; posts:vec rec_456}; posts:vec rec_456; reactions:vec record {id:text; post:rec_456; author:rec_458; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_456 = record {id:text; text:text; author:rec_457; thread:record {id:text; title:text; author:rec_459; posts:vec rec_456}; reactions:vec record {id:text; post:rec_456; author:rec_458; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_517 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_517; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_517; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_519 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_519; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_519; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_518 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_518; posts:vec rec_516}; posts:vec rec_516; reactions:vec record {id:text; post:rec_516; author:rec_518; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_516 = record {id:text; text:text; author:rec_517; thread:record {id:text; title:text; author:rec_519; posts:vec rec_516}; reactions:vec record {id:text; post:rec_516; author:rec_518; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_515 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_515}; reactions:vec record {id:text; post:rec_515; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_513 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_513}; reactions:vec record {id:text; post:rec_513; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_514 = record {id:text; text:text; author:rec_512; thread:record {id:text; title:text; author:rec_512; posts:vec rec_514}; reactions:vec record {id:text; post:rec_514; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_512 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_512; posts:vec rec_515}; posts:vec rec_513; reactions:vec record {id:text; post:rec_514; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_579 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_579}; reactions:vec record {id:text; post:rec_579; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_577 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_577}; reactions:vec record {id:text; post:rec_577; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_578 = record {id:text; text:text; author:rec_576; thread:record {id:text; title:text; author:rec_576; posts:vec rec_578}; reactions:vec record {id:text; post:rec_578; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_576 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_576; posts:vec rec_579}; posts:vec rec_577; reactions:vec record {id:text; post:rec_578; author:rec_576; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_581 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_581; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_581; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_583 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_583; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_583; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_582 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_582; posts:vec rec_580}; posts:vec rec_580; reactions:vec record {id:text; post:rec_580; author:rec_582; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_580 = record {id:text; text:text; author:rec_581; thread:record {id:text; title:text; author:rec_583; posts:vec rec_580}; reactions:vec record {id:text; post:rec_580; author:rec_582; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_619 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_619}; reactions:vec record {id:text; post:rec_619; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_617 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_617}; reactions:vec record {id:text; post:rec_617; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_618 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_618}; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; +type rec_616 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_616; posts:vec rec_619}; posts:vec rec_617; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; service: () -> { - test: (record {id:text; username:text}) -> (text); -} + createPost: (text, text, text, nat32) -> (rec_440) ; + createReaction: (text, text, variant {Fire; ThumbsDown; ThumbsUp}, nat32) -> (record {id:text; post:rec_484; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) ; + createThread: (text, text, nat32) -> (record {id:text; title:text; author:rec_544; posts:vec rec_548}) ; + createUser: (text, nat32) -> (rec_600) ; + getAllPosts: (nat32) -> (vec rec_456) query; + getAllReactions: (nat32) -> (vec record {id:text; post:rec_516; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) query; + getAllThreads: (nat32) -> (vec record {id:text; title:text; author:rec_576; posts:vec rec_580}) query; + getAllUsers: (nat32) -> (vec rec_616) query; +} \ No newline at end of file diff --git a/examples/complex_types/src/index.ts b/examples/complex_types/src/index.ts index d8d2e931ec..eb63d4e197 100644 --- a/examples/complex_types/src/index.ts +++ b/examples/complex_types/src/index.ts @@ -1,62 +1,52 @@ -import { nat32, query, Service, text, update, Vec } from 'azle'; -import { Post } from './candid_types/post'; -import { Reaction } from './candid_types/reaction'; -import { ReactionType } from './candid_types/reaction_type'; -import { Thread } from './candid_types/thread'; -import { User } from './candid_types/user'; +import { nat32, query, Canister, text, update, Vec } from 'azle'; +import { Post, Reaction, ReactionType, Thread, User } from './candid_types'; import { createPost, getAllPosts } from './posts'; import { createReaction, getAllReactions } from './reactions'; import { createThread, getAllThreads } from './threads'; import { createUser, getAllUsers } from './users'; -export default class extends Service { - @update([text, text, text, nat32], Post) - createPost( - authorId: text, - text: text, - threadId: text, - joinDepth: nat32 - ): Post { - return createPost(authorId, text, threadId, joinDepth); - } - - @query([nat32], Vec(Post)) - getAllPosts(joinDepth: nat32): Vec { +export default Canister({ + createPost: update( + [text, text, text, nat32], + Post, + (authorId, text, threadId, joinDepth) => { + return createPost(authorId, text, threadId, joinDepth); + } + ), + + getAllPosts: query([nat32], Vec(Post), (joinDepth) => { return getAllPosts(joinDepth); - } - - @update([text, text, ReactionType, nat32], Reaction) - createReaction( - authorId: string, - postId: string, - reactionType: ReactionType, - joinDepth: nat32 - ): Reaction { - return createReaction(authorId, postId, reactionType, joinDepth); - } - - @query([nat32], Vec(Reaction)) - getAllReactions(joinDepth: nat32): Vec { + }), + + createReaction: update( + [text, text, ReactionType, nat32], + Reaction, + (authorId, postId, reactionType, joinDepth) => { + return createReaction(authorId, postId, reactionType, joinDepth); + } + ), + + getAllReactions: query([nat32], Vec(Reaction), (joinDepth) => { return getAllReactions(joinDepth); - } + }), - @update([text, text, nat32], Thread) - createThread(title: text, authorId: text, joinDepth: nat32): Thread { - return createThread(title, authorId, joinDepth); - } + createThread: update( + [text, text, nat32], + Thread, + (title, authorId, joinDepth) => { + return createThread(title, authorId, joinDepth); + } + ), - @query([nat32], Vec(Thread)) - getAllThreads(joinDepth: nat32): Vec { + getAllThreads: query([nat32], Vec(Thread), (joinDepth) => { return getAllThreads(joinDepth); - } + }), - @update([text, nat32], User) - createUser(username: string, joinDepth: nat32): User { + createUser: update([text, nat32], User, (username, joinDepth) => { return createUser(username, joinDepth); - } + }), - @query([nat32], Vec(User)) - getAllUsers(joinDepth: nat32): Vec { + getAllUsers: query([nat32], Vec(User), (joinDepth) => { return getAllUsers(joinDepth); - } -} + }) +}); diff --git a/examples/complex_types/src/posts.ts b/examples/complex_types/src/posts.ts index bb2a6dc4e6..1af1125a3c 100644 --- a/examples/complex_types/src/posts.ts +++ b/examples/complex_types/src/posts.ts @@ -1,5 +1,5 @@ import { nat32, Vec } from 'azle'; -import { Post } from './candid_types/post'; +import { Post } from './candid_types'; import { getReactionFromStateReaction } from './reactions'; import { state, StatePost, StateThread, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; @@ -10,7 +10,7 @@ export function createPost( text: string, threadId: string, joinDepth: nat32 -): Post { +): typeof Post { const id = Object.keys(state.posts).length.toString(); const statePost: StatePost = { @@ -32,7 +32,7 @@ export function createPost( return post; } -export function getAllPosts(joinDepth: nat32): Vec { +export function getAllPosts(joinDepth: nat32): (typeof Post)[] { return Object.values(state.posts).map((statePost) => getPostFromStatePost(statePost, joinDepth) ); @@ -41,7 +41,7 @@ export function getAllPosts(joinDepth: nat32): Vec { export function getPostFromStatePost( statePost: StatePost, joinDepth: nat32 -): Post { +): typeof Post { const stateAuthor = state.users[statePost.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); @@ -63,13 +63,13 @@ export function getPostFromStatePost( getReactionFromStateReaction(stateReaction, joinDepth - 1) ); - return Post.create({ + return { id: statePost.id, author, reactions, text: statePost.text, thread - }); + }; } } diff --git a/examples/complex_types/src/reactions.ts b/examples/complex_types/src/reactions.ts index 35e342b734..fb5aa95948 100644 --- a/examples/complex_types/src/reactions.ts +++ b/examples/complex_types/src/reactions.ts @@ -1,6 +1,5 @@ import { nat32, Vec } from 'azle'; -import { Reaction } from './candid_types/reaction'; -import { ReactionType } from './candid_types/reaction_type'; +import { Reaction, ReactionType } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StatePost, StateReaction, StateUser } from './state'; import { getUserFromStateUser } from './users'; @@ -8,9 +7,9 @@ import { getUserFromStateUser } from './users'; export function createReaction( authorId: string, postId: string, - reactionType: ReactionType, + reactionType: typeof ReactionType, joinDepth: nat32 -): Reaction { +): typeof Reaction { const id = Object.keys(state.reactions).length.toString(); const stateReaction: StateReaction = { @@ -34,7 +33,7 @@ export function createReaction( return reaction; } -export function getAllReactions(joinDepth: nat32): Vec { +export function getAllReactions(joinDepth: nat32): (typeof Reaction)[] { return Object.values(state.reactions).map((stateReaction) => getReactionFromStateReaction(stateReaction, joinDepth) ); @@ -43,19 +42,19 @@ export function getAllReactions(joinDepth: nat32): Vec { export function getReactionFromStateReaction( stateReaction: StateReaction, joinDepth: nat32 -): Reaction { +): typeof Reaction { const stateAuthor = state.users[stateReaction.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); const statePost = state.posts[stateReaction.postId]; const post = getPostFromStatePost(statePost, joinDepth); - return Reaction.create({ + return { id: stateReaction.id, author, post, reactionType: stateReaction.reactionType - }); + }; } function getUpdatedStateAuthor( diff --git a/examples/complex_types/src/threads.ts b/examples/complex_types/src/threads.ts index d070ba07a7..6bea9fd903 100644 --- a/examples/complex_types/src/threads.ts +++ b/examples/complex_types/src/threads.ts @@ -1,5 +1,5 @@ import { nat32, Vec } from 'azle'; -import { Thread } from './candid_types/thread'; +import { Thread } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StateThread, StateUser } from './state'; import { getUserFromStateUser } from './users'; @@ -8,7 +8,7 @@ export function createThread( title: string, authorId: string, joinDepth: nat32 -): Thread { +): typeof Thread { const id = Object.keys(state.threads).length.toString(); const stateThread: StateThread = { @@ -27,7 +27,7 @@ export function createThread( return thread; } -export function getAllThreads(joinDepth: nat32): Vec { +export function getAllThreads(joinDepth: nat32): (typeof Thread)[] { return Object.values(state.threads).map((stateThread) => getThreadFromStateThread(stateThread, joinDepth) ); @@ -36,7 +36,7 @@ export function getAllThreads(joinDepth: nat32): Vec { export function getThreadFromStateThread( stateThread: StateThread, joinDepth: nat32 -): Thread { +): typeof Thread { const stateAuthor = state.users[stateThread.authorId]; const author = getUserFromStateUser(stateAuthor, joinDepth); @@ -52,12 +52,12 @@ export function getThreadFromStateThread( .map((postId) => state.posts[postId]) .map((statePost) => getPostFromStatePost(statePost, joinDepth - 1)); - return Thread.create({ + return { id: stateThread.id, author, posts, title: stateThread.title - }); + }; } } diff --git a/examples/complex_types/src/users.ts b/examples/complex_types/src/users.ts index cc437169a5..9c98ed25f2 100644 --- a/examples/complex_types/src/users.ts +++ b/examples/complex_types/src/users.ts @@ -1,11 +1,11 @@ import { nat32, Vec } from 'azle'; -import { User } from './candid_types/user'; +import { User } from './candid_types'; import { getPostFromStatePost } from './posts'; import { getReactionFromStateReaction } from './reactions'; import { state, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; -export function createUser(username: string, joinDepth: nat32): User { +export function createUser(username: string, joinDepth: nat32): typeof User { const id = Object.keys(state.users).length.toString(); const stateUser: StateUser = { @@ -23,7 +23,7 @@ export function createUser(username: string, joinDepth: nat32): User { return user; } -export function getAllUsers(joinDepth: nat32): Vec { +export function getAllUsers(joinDepth: nat32): (typeof User)[] { return Object.values(state.users).map((stateUser) => getUserFromStateUser(stateUser, joinDepth) ); @@ -32,7 +32,7 @@ export function getAllUsers(joinDepth: nat32): Vec { export function getUserFromStateUser( stateUser: StateUser, joinDepth: nat32 -): User { +): typeof User { if (joinDepth === 0) { return { id: stateUser.id, @@ -58,12 +58,12 @@ export function getUserFromStateUser( getThreadFromStateThread(stateThread, joinDepth - 1) ); - return User.create({ + return { id: stateUser.id, posts, reactions, threads, username: stateUser.username - }); + }; } } From 9413f6d0925f58e3e081fb74eb5e09ac7e7e79a9 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 14:11:57 -0600 Subject: [PATCH 22/37] update func_types example --- .github/workflows/test.yml | 2 +- .../func_types/canisters/func_types/index.did | 63 ++------- .../func_types/canisters/func_types/index.ts | 132 ++++++++---------- .../func_types/canisters/notifiers/index.did | 4 +- .../func_types/canisters/notifiers/index.ts | 18 ++- examples/func_types/dfx.json | 6 +- src/lib_new/utils.ts | 2 +- 7 files changed, 88 insertions(+), 139 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 375e87d808..72d3a2c862 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,6 @@ # The check-basic-integration-tests-success job is designed to ensure that all jobs spun up from the matrix in the basic-integration-tests have succeeded # All Examples TODO restore when https://github.com/demergent-labs/azle/issues/1192 is resolved -# "examples/func_types", # "examples/generics", # "examples/motoko_examples/superheroes", # blocked by recursive # "examples/run_time_errors", @@ -80,6 +79,7 @@ jobs: "examples/cycles", "examples/date", "examples/ethereum_json_rpc", + "examples/func_types", "examples/guard_functions", "examples/heartbeat", "examples/ic_api", diff --git a/examples/func_types/canisters/func_types/index.did b/examples/func_types/canisters/func_types/index.did index 9fab503be8..289a4bd06a 100644 --- a/examples/func_types/canisters/func_types/index.did +++ b/examples/func_types/canisters/func_types/index.did @@ -1,50 +1,15 @@ -type ComplexFunc = func ( - record { - id : text; - complexFunc : ComplexFunc; - basicFunc : func (text) -> (text) query; - }, - variant { - Bad; - ComplexFunc : ComplexFunc; - Good; - BasicFunc : func (text) -> (text) query; - }, - ) -> (nat64); -type ManualReply = variant { Ok : func (vec nat8) -> () oneway; Err : text }; -type Reaction = variant { - Bad; - ComplexFunc : ComplexFunc; - Good; - BasicFunc : func (text) -> (text) query; -}; -type User = record { - id : text; - complexFunc : ComplexFunc; - basicFunc : func (text) -> (text) query; -}; -service : () -> { - basicFuncParam : (func (text) -> (text) query) -> ( - func (text) -> (text) query, - ) query; - basicFuncParamArray : (vec func (text) -> (text) query) -> ( - vec func (text) -> (text) query, - ) query; - basicFuncReturnType : () -> (func (text) -> (text) query) query; - basicFuncReturnTypeArray : () -> (vec func (text) -> (text) query) query; - complexFuncParam : (func (User, Reaction) -> (nat64)) -> ( - func (User, Reaction) -> (nat64), - ) query; - complexFuncReturnType : () -> (func (User, Reaction) -> (nat64)) query; - getNotifierFromNotifiersCanister : () -> (ManualReply); - getStableFunc : () -> (func (nat64, text) -> () query) query; - nullFuncParam : ( - func (opt null, vec null, null, vec vec null, vec opt null) -> ( - null, - ) query, - ) -> ( - func (opt null, vec null, null, vec vec null, vec opt null) -> ( - null, - ) query, - ) query; +type rec_26 = func (record {id:text; complexFunc:rec_26; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_26; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +type rec_29 = func (record {id:text; complexFunc:rec_29; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_29; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +type rec_34 = func (record {id:text; complexFunc:rec_34; basicFunc:func (text) -> (text) query}, variant {Bad; ComplexFunc:rec_34; Good; BasicFunc:func (text) -> (text) query}) -> (nat64) ; +service: () -> { + basicFuncParam: (func (text) -> (text) query) -> (func (text) -> (text) query) query; + basicFuncParamArray: (vec func (text) -> (text) query) -> (vec func (text) -> (text) query) query; + basicFuncReturnType: () -> (func (text) -> (text) query) query; + basicFuncReturnTypeArray: () -> (vec func (text) -> (text) query) query; + complexFuncParam: (rec_26) -> (rec_29) query; + complexFuncReturnType: () -> (rec_34) query; + getNotifierFromNotifiersCanister: () -> (func (vec nat8) -> () oneway) ; + getStableFunc: () -> (func (nat64, text) -> () query) query; + init: () -> () query; + nullFuncParam: (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) -> (func (opt null, vec null, null, vec vec null, vec opt null) -> (null) query) query; } \ No newline at end of file diff --git a/examples/func_types/canisters/func_types/index.ts b/examples/func_types/canisters/func_types/index.ts index b317653fd9..01165f4b0c 100644 --- a/examples/func_types/canisters/func_types/index.ts +++ b/examples/func_types/canisters/func_types/index.ts @@ -1,4 +1,5 @@ import { + Canister, Func, init, ic, @@ -7,115 +8,98 @@ import { Principal, query, Record, - Service, StableBTreeMap, update, Variant, Vec, - candid, text, - func, Void, - Null + Null, + Recursive } from 'azle'; import Notifier, { NotifierFunc } from '../notifiers'; -@func([text], text, 'query') -class BasicFunc extends Func {} - -@func([User, Reaction], nat64, 'update') -class ComplexFunc extends Func {} - -class User extends Record { - @candid(text) - id: text; +const BasicFunc = Func([text], text, 'query'); - @candid(BasicFunc) - basicFunc: BasicFunc; +const ComplexFunc = Recursive(() => Func([User, Reaction], nat64, 'update')); - @candid(ComplexFunc) - complexFunc: ComplexFunc; -} +const User = Record({ + id: text, + basicFunc: BasicFunc, + complexFunc: ComplexFunc +}); -class Reaction extends Variant { - Good: null; - Bad: null; - BasicFunc: BasicFunc; - ComplexFunc: ComplexFunc; -} +const Reaction = Variant({ + Good: Null, + Bad: Null, + BasicFunc: BasicFunc, + ComplexFunc: ComplexFunc +}); -@func([nat64, text], Void, 'query') -class StableFunc extends Func {} +const StableFunc = Func([nat64, text], Void, 'query'); -@func( +const NullFunc = Func( [Opt(Null), Vec(Null), Null, Vec(Vec(Null)), Vec(Opt(Null))], Null, 'query' -) -class NullFunc extends Func {} +); -export default class extends Service { - stableStorage = new StableBTreeMap(text, StableFunc, 0); +let stableStorage = StableBTreeMap(text, StableFunc, 0); - @init([]) - init() { - this.stableStorage.insert( - 'stableFunc', - new StableFunc(Principal.from('aaaaa-aa'), 'start_canister') - ); - } +export default Canister({ + init: init([], () => { + stableStorage.insert('stableFunc', [ + Principal.from('aaaaa-aa'), + 'start_canister' + ]); + }), - @query([], StableFunc) - getStableFunc(): StableFunc { - const stableFuncOpt = this.stableStorage.get('stableFunc'); + getStableFunc: query([], StableFunc, () => { + const stableFuncOpt = stableStorage.get('stableFunc'); if (stableFuncOpt.length === 1) { return stableFuncOpt[0]; } - return new StableFunc(Principal.from('aaaaa-aa'), 'raw_rand'); - } + return [Principal.from('aaaaa-aa'), 'raw_rand']; + }), - @query([BasicFunc], BasicFunc) - basicFuncParam(basicFunc: BasicFunc): BasicFunc { + basicFuncParam: query([BasicFunc], BasicFunc, (basicFunc) => { return basicFunc; - } + }), - @query([NullFunc], NullFunc) - nullFuncParam(nullFunc: NullFunc): NullFunc { + nullFuncParam: query([NullFunc], NullFunc, (nullFunc) => { return nullFunc; - } + }), - @query([Vec(BasicFunc)], Vec(BasicFunc)) - basicFuncParamArray(basicFunc: Vec): Vec { - return basicFunc; - } + basicFuncParamArray: query( + [Vec(BasicFunc)], + Vec(BasicFunc), + (basicFunc) => { + return basicFunc; + } + ), - @query([], BasicFunc) - basicFuncReturnType(): BasicFunc { - return new BasicFunc(Principal.fromText('aaaaa-aa'), 'create_canister'); - } + basicFuncReturnType: query([], BasicFunc, () => { + return [Principal.fromText('aaaaa-aa'), 'create_canister']; + }), - @query([], Vec(BasicFunc)) - basicFuncReturnTypeArray(): Vec { + basicFuncReturnTypeArray: query([], Vec(BasicFunc), () => { return [ - new BasicFunc(Principal.fromText('aaaaa-aa'), 'create_canister'), - new BasicFunc(Principal.fromText('aaaaa-aa'), 'update_settings'), - new BasicFunc(Principal.fromText('aaaaa-aa'), 'install_code') + [Principal.fromText('aaaaa-aa'), 'create_canister'], + [Principal.fromText('aaaaa-aa'), 'update_settings'], + [Principal.fromText('aaaaa-aa'), 'install_code'] ]; - } + }), - @query([ComplexFunc], ComplexFunc) - complexFuncParam(complexFunc: ComplexFunc): ComplexFunc { + complexFuncParam: query([ComplexFunc], ComplexFunc, (complexFunc) => { return complexFunc; - } + }), - @query([], ComplexFunc) - complexFuncReturnType(): ComplexFunc { + complexFuncReturnType: query([], ComplexFunc, () => { return [Principal.fromText('aaaaa-aa'), 'stop_canister']; - } + }), - @update([], NotifierFunc) - async getNotifierFromNotifiersCanister(): Promise { - const notifiersCanister: Notifier = new Notifier( + getNotifierFromNotifiersCanister: update([], NotifierFunc, async () => { + const notifiersCanister = Notifier( Principal.fromText( process.env.NOTIFIERS_PRINCIPAL ?? ic.trap('process.env.NOTIFIERS_PRINCIPAL is undefined') @@ -123,5 +107,5 @@ export default class extends Service { ); return await ic.call(notifiersCanister.getNotifier); - } -} + }) +}); diff --git a/examples/func_types/canisters/notifiers/index.did b/examples/func_types/canisters/notifiers/index.did index 9ea58c8334..72c0545dc8 100644 --- a/examples/func_types/canisters/notifiers/index.did +++ b/examples/func_types/canisters/notifiers/index.did @@ -1,3 +1,3 @@ service: () -> { - getNotifier: () -> (func (vec nat8) -> () oneway) query; -} + getNotifier: () -> (func (vec nat8) -> () oneway) query; +} \ No newline at end of file diff --git a/examples/func_types/canisters/notifiers/index.ts b/examples/func_types/canisters/notifiers/index.ts index ddfc393c19..204c3135e1 100644 --- a/examples/func_types/canisters/notifiers/index.ts +++ b/examples/func_types/canisters/notifiers/index.ts @@ -1,17 +1,15 @@ -import { ic, Principal, query, blob, Func, Service, Void, func } from 'azle'; +import { Canister, ic, Principal, query, blob, Func, Void } from 'azle'; -@func([blob], Void, 'oneway') -export class NotifierFunc extends Func {} +export const NotifierFunc = Func([blob], Void, 'oneway'); -export default class extends Service { - @query([], NotifierFunc) - getNotifier(): NotifierFunc { - return new NotifierFunc( +export default Canister({ + getNotifier: query([], NotifierFunc, () => { + return [ Principal.fromText( process.env.NOTIFIERS_PRINCIPAL ?? ic.trap('process.env.NOTIFIERS_PRINCIPAL is undefined') ), 'notify' - ); - } -} + ]; + }) +}); diff --git a/examples/func_types/dfx.json b/examples/func_types/dfx.json index ea939ee18b..dcaaa7abbe 100644 --- a/examples/func_types/dfx.json +++ b/examples/func_types/dfx.json @@ -5,7 +5,8 @@ "main": "canisters/func_types/index.ts", "build": "npx azle func_types", "candid": "canisters/func_types/index.did", - "wasm": ".azle/func_types/func_types.wasm.gz", + "wasm": ".azle/func_types/func_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/func_types", "node_compatibility": true @@ -17,7 +18,8 @@ "main": "canisters/notifiers/index.ts", "build": "npx azle notifiers", "candid": "canisters/notifiers/index.did", - "wasm": ".azle/notifiers/notifiers.wasm.gz", + "wasm": ".azle/notifiers/notifiers.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/notifiers", "node_compatibility": true diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index 8acf82da85..343e1d32fd 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -104,7 +104,7 @@ export function toParamIDLTypes( export function toReturnIDLType( returnIdl: ReturnCandidClass, - parents: Parent[] + parents: Parent[] = [] ): IDL.Type[] { const idlType = toIDLType(returnIdl, parents); From 6e0adf893893342ae29cd23fa40307ca642178d2 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 15:18:37 -0600 Subject: [PATCH 23/37] update tuple types example --- .github/workflows/test.yml | 2 +- examples/tuple_types/dfx.json | 7 +- examples/tuple_types/src/index.did | 36 +++ examples/tuple_types/src/index.ts | 292 +++++++++++++++++++++ examples/tuple_types/src/tuple_types.did | 57 ---- examples/tuple_types/src/tuple_types.ts | 319 ----------------------- examples/tuple_types/test/tests.ts | 23 +- 7 files changed, 335 insertions(+), 401 deletions(-) create mode 100644 examples/tuple_types/src/index.did create mode 100644 examples/tuple_types/src/index.ts delete mode 100644 examples/tuple_types/src/tuple_types.did delete mode 100644 examples/tuple_types/src/tuple_types.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72d3a2c862..f670959845 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,6 @@ # "examples/generics", # "examples/motoko_examples/superheroes", # blocked by recursive # "examples/run_time_errors", -# "examples/tuple_types", name: Azle Tests on: @@ -123,6 +122,7 @@ jobs: "examples/stable_memory", "examples/stable_structures", "examples/timers", + "examples/tuple_types", "examples/update" ] END diff --git a/examples/tuple_types/dfx.json b/examples/tuple_types/dfx.json index be52556ed9..a05d8d80cc 100644 --- a/examples/tuple_types/dfx.json +++ b/examples/tuple_types/dfx.json @@ -2,10 +2,11 @@ "canisters": { "tuple_types": { "type": "custom", - "main": "src/tuple_types.ts", + "main": "src/index.ts", "build": "npx azle tuple_types", - "candid": "src/tuple_types.did", - "wasm": ".azle/tuple_types/tuple_types.wasm.gz", + "candid": "src/index.did", + "wasm": ".azle/tuple_types/tuple_types.wasm", + "gzip": true, "declarations": { "output": "test/dfx_generated/tuple_types", "node_compatibility": true diff --git a/examples/tuple_types/src/index.did b/examples/tuple_types/src/index.did new file mode 100644 index 0000000000..ba4796e0e0 --- /dev/null +++ b/examples/tuple_types/src/index.did @@ -0,0 +1,36 @@ +type rec_72 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_72}; Good}; +type rec_75 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_75}; Good}; +type rec_68 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_68}; Good}; +type rec_60 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_60}; Good}; +type rec_63 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_63}; Good}; +type rec_56 = variant {Bad:record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_56}; Good}; +service: () -> { + complexOneTupleInlineParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; + complexOneTupleInlineReturnType: () -> (record {record {text; nat64}}) query; + complexOneTupleParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; + complexOneTupleReturnType: () -> (record {record {text; nat64}}) query; + complexThreeTupleInlineParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_72}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_75}) query; + complexThreeTupleInlineReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_68}) query; + complexThreeTupleParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_60}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_63}) query; + complexThreeTupleReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}; rec_56}) query; + complexTwoTupleInlineParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleInlineReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleParam: (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + complexTwoTupleReturnType: () -> (record {record {text; nat64}; record {id:text; primitiveTwoTuple:record {text; nat64}}}) query; + nestedTupleQuery: (record {record {text; record {nat8; nat8}}; int}) -> (record {record {text; record {nat8; nat8}}; int}) query; + primitiveOneTupleInlineParam: (record {text}) -> (record {text}) query; + primitiveOneTupleInlineReturnType: () -> (record {text}) query; + primitiveOneTupleParam: (record {text}) -> (record {text}) query; + primitiveOneTupleReturnType: () -> (record {text}) query; + primitiveThreeTupleInlineParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; + primitiveThreeTupleInlineReturnType: () -> (record {text; nat64; principal}) query; + primitiveThreeTupleParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; + primitiveThreeTupleReturnType: () -> (record {text; nat64; principal}) query; + primitiveTwoTupleInlineParam: (record {text; text}) -> (record {text; text}) query; + primitiveTwoTupleInlineReturnType: () -> (record {text; text}) query; + primitiveTwoTupleParam: (record {text; nat64}) -> (record {text; nat64}) query; + primitiveTwoTupleReturnType: () -> (record {text; nat64}) query; + tupleArrayParamsAndReturnType: (vec record {text; text}) -> (vec record {text; text}) query; + tupleArrayRecordField: () -> (record {headers:vec record {text; text}}) query; + tupleArrayVariantField: () -> (variant {WithHeaders:vec record {text; text}; WithoutHeaders}) query; +} \ No newline at end of file diff --git a/examples/tuple_types/src/index.ts b/examples/tuple_types/src/index.ts new file mode 100644 index 0000000000..5f7ffa2d74 --- /dev/null +++ b/examples/tuple_types/src/index.ts @@ -0,0 +1,292 @@ +import { + query, + // CallResult, + int, + nat64, + nat8, + Null, + Principal, + Record, + // Service, + // serviceUpdate, + text, + Tuple, + Variant, + Vec, + Void, + Recursive, + Canister +} from 'azle'; + +// TODO maybe we should write tests for canister and stable storage? +// TODO for now we at least know the canister compiles +// type CanisterTuple1 = Tuple<[text, nat64]>; +// type CanisterTuple2 = Tuple<[text, CanisterTuple1]>; + +// class TestCanister extends Service { +// @serviceUpdate +// test: (param: CanisterTuple1) => CallResult; +// } + +const PrimitiveOneTuple = Tuple(text); +const PrimitiveTwoTuple = Tuple(text, nat64); +const PrimitiveThreeTuple = Tuple(text, nat64, Principal); + +const User = Record({ + id: text, + primitiveTwoTuple: PrimitiveTwoTuple +}); + +const Header = Tuple(text, text); + +const StreamingCallbackType = Variant({ + WithHeaders: Vec(Header), + WithoutHeaders: Null +}); + +const Reaction = Recursive(() => + Variant({ + Good: Null, + Bad: ComplexThreeTuple + }) +); + +const ComplexOneTuple = Tuple(PrimitiveTwoTuple); +const ComplexTwoTuple = Tuple(PrimitiveTwoTuple, User); +const ComplexThreeTuple = Tuple(PrimitiveTwoTuple, User, Reaction); + +const HttpResponse = Record({ + headers: Vec(Header) +}); + +export default Canister({ + primitiveOneTupleReturnType: query([], PrimitiveOneTuple, () => { + return ['Hello']; + }), + + primitiveOneTupleParam: query( + [PrimitiveOneTuple], + PrimitiveOneTuple, + (param) => { + return param; + } + ), + + primitiveOneTupleInlineReturnType: query([], Tuple(text), () => { + return ['Greenland']; + }), + + primitiveOneTupleInlineParam: query([Tuple(text)], Tuple(text), (param) => { + return param; + }), + + primitiveTwoTupleReturnType: query([], PrimitiveTwoTuple, () => { + return ['Content-Type', 64n]; + }), + + primitiveTwoTupleParam: query( + [PrimitiveTwoTuple], + PrimitiveTwoTuple, + (param) => { + return param; + } + ), + + primitiveTwoTupleInlineReturnType: query([], Tuple(text, text), () => { + return ['Fun', 'Times']; + }), + + primitiveTwoTupleInlineParam: query( + [Tuple(text, text)], + Tuple(text, text), + (param: Tuple<[text, text]>) => { + return param; + } + ), + + primitiveThreeTupleReturnType: query([], PrimitiveThreeTuple, () => { + return [ + 'Good', + 454n, + Principal.fromText('rrkah-fqaaa-aaaaa-aaaaq-cai') + ]; + }), + + primitiveThreeTupleParam: query( + [PrimitiveThreeTuple], + PrimitiveThreeTuple, + (param) => { + return param; + } + ), + + primitiveThreeTupleInlineReturnType: query( + [], + Tuple(text, nat64, Principal), + () => { + return ['Fun', 101n, Principal.fromText('aaaaa-aa')]; + } + ), + + primitiveThreeTupleInlineParam: query( + [Tuple(text, nat64, Principal)], + Tuple(text, nat64, Principal), + (param) => { + return param; + } + ), + + complexOneTupleReturnType: query([], ComplexOneTuple, () => { + return [['Hello', 0n]]; + }), + + complexOneTupleParam: query([ComplexOneTuple], ComplexOneTuple, (param) => { + return param; + }), + + complexOneTupleInlineReturnType: query([], Tuple(PrimitiveTwoTuple), () => { + return [['Candy', 56n]]; + }), + + complexOneTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple)], + Tuple(PrimitiveTwoTuple), + (param) => { + return param; + } + ), + + complexTwoTupleReturnType: query([], ComplexTwoTuple, () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + } + ]; + }), + + complexTwoTupleParam: query([ComplexTwoTuple], ComplexTwoTuple, (param) => { + return param; + }), + + complexTwoTupleInlineReturnType: query( + [], + Tuple(PrimitiveTwoTuple, User), + () => { + return [ + ['Content-Type', 644n], + { + id: '444', + primitiveTwoTuple: ['Content-Type', 6_422n] + } + ]; + } + ), + + complexTwoTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple, User)], + Tuple(PrimitiveTwoTuple, User), + (param) => { + return param; + } + ), + + complexThreeTupleReturnType: query([], ComplexThreeTuple, () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Bad: [ + ['Content-Type', 64n], + { + id: '1', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Good: null + } + ] + } + ]; + }), + + complexThreeTupleParam: query( + [ComplexThreeTuple], + ComplexThreeTuple, + (param) => { + return param; + } + ), + + complexThreeTupleInlineReturnType: query( + [], + Tuple(PrimitiveTwoTuple, User, Reaction), + () => { + return [ + ['Content-Type', 64n], + { + id: '0', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Bad: [ + ['Content-Type', 64n], + { + id: '1', + primitiveTwoTuple: ['Content-Type', 64n] + }, + { + Good: null + } + ] + } + ]; + } + ), + + complexThreeTupleInlineParam: query( + [Tuple(PrimitiveTwoTuple, User, Reaction)], + Tuple(PrimitiveTwoTuple, User, Reaction), + (param) => { + return param; + } + ), + + tupleArrayParamsAndReturnType: query( + [Vec(Header)], + Vec(Header), + (headers) => { + return headers; + } + ), + + tupleArrayRecordField: query([], HttpResponse, () => { + return { + headers: [ + ['Content-Type', 'application/json'], + ['Accept-Ranges', 'bytes'] + ] + }; + }), + + tupleArrayVariantField: query([], StreamingCallbackType, () => { + return { + WithHeaders: [ + ['Content-Type', 'application/json'], + ['Accept-Ranges', 'bytes'] + ] + }; + }), + + nestedTupleQuery: query( + [Tuple(Tuple(text, Tuple(nat8, nat8)), int)], + Tuple(Tuple(text, Tuple(nat8, nat8)), int), + (param) => { + return param; + } + ) +}); diff --git a/examples/tuple_types/src/tuple_types.did b/examples/tuple_types/src/tuple_types.did deleted file mode 100644 index a15978cd8b..0000000000 --- a/examples/tuple_types/src/tuple_types.did +++ /dev/null @@ -1,57 +0,0 @@ -type rec_0 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_1 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_2 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_3 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_4 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_5 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_6 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_8 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_7 = variant {Bad:record {record {text; nat64}; rec_8; rec_7}; Good}; -type rec_9 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_11 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_10 = variant {Bad:record {record {text; nat64}; rec_11; rec_10}; Good}; -type rec_12 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_14 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_13 = variant {Bad:record {record {text; nat64}; rec_14; rec_13}; Good}; -type rec_15 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_17 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_16 = variant {Bad:record {record {text; nat64}; rec_17; rec_16}; Good}; -type rec_18 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_20 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_19 = variant {Bad:record {record {text; nat64}; rec_20; rec_19}; Good}; -type rec_21 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_23 = record {id:text; primitiveTwoTuple:record {text; nat64}}; -type rec_22 = variant {Bad:record {record {text; nat64}; rec_23; rec_22}; Good}; -type rec_24 = record {headers:vec record {text; text}}; -type rec_25 = variant {WithHeaders:vec record {text; text}; WithoutHeaders}; -service: () -> { - primitiveOneTupleReturnType: () -> (record {text}) query; - primitiveOneTupleParam: (record {text}) -> (record {text}) query; - primitiveOneTupleInlineReturnType: () -> (record {text}) query; - primitiveOneTupleInlineParam: (record {text}) -> (record {text}) query; - primitiveTwoTupleReturnType: () -> (record {text; nat64}) query; - primitiveTwoTupleParam: (record {text; nat64}) -> (record {text; nat64}) query; - primitiveTwoTupleInlineReturnType: () -> (record {text; text}) query; - primitiveTwoTupleInlineParam: (record {text; text}) -> (record {text; text}) query; - primitiveThreeTupleReturnType: () -> (record {text; nat64; principal}) query; - primitiveThreeTupleParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; - primitiveThreeTupleInlineReturnType: () -> (record {text; nat64; principal}) query; - primitiveThreeTupleInlineParam: (record {text; nat64; principal}) -> (record {text; nat64; principal}) query; - complexOneTupleReturnType: () -> (record {record {text; nat64}}) query; - complexOneTupleParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; - complexOneTupleInlineReturnType: () -> (record {record {text; nat64}}) query; - complexOneTupleInlineParam: (record {record {text; nat64}}) -> (record {record {text; nat64}}) query; - complexTwoTupleReturnType: () -> (record {record {text; nat64}; rec_0}) query; - complexTwoTupleParam: (record {record {text; nat64}; rec_1}) -> (record {record {text; nat64}; rec_2}) query; - complexTwoTupleInlineReturnType: () -> (record {record {text; nat64}; rec_3}) query; - complexTwoTupleInlineParam: (record {record {text; nat64}; rec_4}) -> (record {record {text; nat64}; rec_5}) query; - complexThreeTupleReturnType: () -> (record {record {text; nat64}; rec_6; rec_7}) query; - complexThreeTupleParam: (record {record {text; nat64}; rec_9; rec_10}) -> (record {record {text; nat64}; rec_12; rec_13}) query; - complexThreeTupleInlineReturnType: () -> (record {record {text; nat64}; rec_15; rec_16}) query; - complexThreeTupleInlineParam: (record {record {text; nat64}; rec_18; rec_19}) -> (record {record {text; nat64}; rec_21; rec_22}) query; - tupleArrayParamsAndReturnType: (vec record {text; text}) -> (vec record {text; text}) query; - tupleArrayRecordField: () -> (rec_24) query; - tupleArrayVariantField: () -> (rec_25) query; - twoTupleWithInlineRecords: (record {record {hello:nat64}; record {goodbye:nat64}}) -> (record {record {hello:nat64}; record {goodbye:nat64}}) query; - nestedTupleQuery: (record {record {text; record {nat8; nat8}}; int}) -> (record {record {text; record {nat8; nat8}}; int}) query; -} diff --git a/examples/tuple_types/src/tuple_types.ts b/examples/tuple_types/src/tuple_types.ts deleted file mode 100644 index b146834a4a..0000000000 --- a/examples/tuple_types/src/tuple_types.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { - query, - // CallResult, - int, - nat64, - nat8, - Null, - Principal, - Record, - // Service, - // serviceUpdate, - text, - Tuple, - Variant, - Vec, - Void, - candid, - principal -} from 'azle'; - -import { IDL } from '@dfinity/candid'; - -// TODO maybe we should write tests for canister and stable storage? -// TODO for now we at least know the canister compiles -// type CanisterTuple1 = Tuple<[text, nat64]>; -// type CanisterTuple2 = Tuple<[text, CanisterTuple1]>; - -// class TestCanister extends Service { -// @serviceUpdate -// test: (param: CanisterTuple1) => CallResult; -// } - -type PrimitiveOneTuple = Tuple<[text]>; -const PrimitiveOneTuple = Tuple(text); -type PrimitiveTwoTuple = Tuple<[text, nat64]>; -const PrimitiveTwoTuple = Tuple(text, nat64); -type PrimitiveThreeTuple = Tuple<[text, nat64, Principal]>; -const PrimitiveThreeTuple = Tuple(text, nat64, principal); - -class User extends Record { - @candid(text) - id: text; - - @candid(PrimitiveTwoTuple) - primitiveTwoTuple: PrimitiveTwoTuple; -} - -type Header = Tuple<[text, text]>; -const Header = Tuple(text, text); - -class StreamingCallbackType extends Variant { - @candid(Vec(Header)) - WithHeaders?: Vec
; - - @candid(Null) - WithoutHeaders?: Null; -} - -class Reaction extends Variant { - @candid(Null) - Good?: Null; - - @candid(Tuple(PrimitiveTwoTuple, User, Reaction)) - Bad?: ComplexThreeTuple; -} - -type ComplexOneTuple = Tuple<[PrimitiveTwoTuple]>; -const ComplexOneTuple = Tuple(PrimitiveTwoTuple); -type ComplexTwoTuple = Tuple<[PrimitiveTwoTuple, User]>; -const ComplexTwoTuple = Tuple(PrimitiveTwoTuple, User); -type ComplexThreeTuple = [PrimitiveTwoTuple, User, Reaction]; -const ComplexThreeTuple = Tuple(PrimitiveTwoTuple, User, Reaction); - -class HttpResponse extends Record { - @candid(Vec(Header)) - headers: Vec
; -} - -export default class { - @query([], PrimitiveOneTuple) - primitiveOneTupleReturnType(): PrimitiveOneTuple { - return ['Hello']; - } - - @query([PrimitiveOneTuple], PrimitiveOneTuple) - primitiveOneTupleParam(param: PrimitiveOneTuple): PrimitiveOneTuple { - return param; - } - - @query([], Tuple(text)) - primitiveOneTupleInlineReturnType(): Tuple<[text]> { - return ['Greenland']; - } - - @query([Tuple(text)], Tuple(text)) - primitiveOneTupleInlineParam(param: Tuple<[text]>): Tuple<[text]> { - return param; - } - - @query([], PrimitiveTwoTuple) - primitiveTwoTupleReturnType(): PrimitiveTwoTuple { - return ['Content-Type', 64n]; - } - - @query([PrimitiveTwoTuple], PrimitiveTwoTuple) - primitiveTwoTupleParam(param: PrimitiveTwoTuple): PrimitiveTwoTuple { - return param; - } - - @query([], Tuple(text, text)) - primitiveTwoTupleInlineReturnType(): Tuple<[text, text]> { - return ['Fun', 'Times']; - } - - @query([Tuple(text, text)], Tuple(text, text)) - primitiveTwoTupleInlineParam( - param: Tuple<[text, text]> - ): Tuple<[text, text]> { - return param; - } - - @query([], PrimitiveThreeTuple) - primitiveThreeTupleReturnType(): PrimitiveThreeTuple { - return [ - 'Good', - 454n, - Principal.fromText('rrkah-fqaaa-aaaaa-aaaaq-cai') - ]; - } - - @query([PrimitiveThreeTuple], PrimitiveThreeTuple) - primitiveThreeTupleParam(param: PrimitiveThreeTuple): PrimitiveThreeTuple { - return param; - } - - @query([], Tuple(text, nat64, principal)) - primitiveThreeTupleInlineReturnType(): Tuple<[text, nat64, Principal]> { - return ['Fun', 101n, Principal.fromText('aaaaa-aa')]; - } - - @query([Tuple(text, nat64, principal)], Tuple(text, nat64, principal)) - primitiveThreeTupleInlineParam( - param: Tuple<[text, nat64, Principal]> - ): Tuple<[text, nat64, Principal]> { - return param; - } - - @query([], ComplexOneTuple) - complexOneTupleReturnType(): ComplexOneTuple { - return [['Hello', 0n]]; - } - - @query([ComplexOneTuple], ComplexOneTuple) - complexOneTupleParam(param: ComplexOneTuple): ComplexOneTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple)) - complexOneTupleInlineReturnType(): Tuple<[PrimitiveTwoTuple]> { - return [['Candy', 56n]]; - } - - @query([Tuple(PrimitiveTwoTuple)], Tuple(PrimitiveTwoTuple)) - complexOneTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple]> - ): Tuple<[PrimitiveTwoTuple]> { - return param; - } - - @query([], ComplexTwoTuple) - complexTwoTupleReturnType(): ComplexTwoTuple { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }) - ]; - } - - @query([ComplexTwoTuple], ComplexTwoTuple) - complexTwoTupleParam(param: ComplexTwoTuple): ComplexTwoTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple, User)) - complexTwoTupleInlineReturnType(): Tuple<[PrimitiveTwoTuple, User]> { - return [ - ['Content-Type', 644n], - User.create({ - id: '444', - primitiveTwoTuple: ['Content-Type', 6_422n] - }) - ]; - } - - @query([Tuple(PrimitiveTwoTuple, User)], Tuple(PrimitiveTwoTuple, User)) - complexTwoTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple, User]> - ): Tuple<[PrimitiveTwoTuple, User]> { - return param; - } - - @query([], ComplexThreeTuple) - complexThreeTupleReturnType(): ComplexThreeTuple { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Bad: [ - ['Content-Type', 64n], - User.create({ - id: '1', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Good: null - }) - ] - }) - ]; - } - - @query([ComplexThreeTuple], ComplexThreeTuple) - complexThreeTupleParam(param: ComplexThreeTuple): ComplexThreeTuple { - return param; - } - - @query([], Tuple(PrimitiveTwoTuple, User, Reaction)) - complexThreeTupleInlineReturnType(): Tuple< - [PrimitiveTwoTuple, User, Reaction] - > { - return [ - ['Content-Type', 64n], - User.create({ - id: '0', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Bad: [ - ['Content-Type', 64n], - User.create({ - id: '1', - primitiveTwoTuple: ['Content-Type', 64n] - }), - Reaction.create({ - Good: null - }) - ] - }) - ]; - } - - @query( - [Tuple(PrimitiveTwoTuple, User, Reaction)], - Tuple(PrimitiveTwoTuple, User, Reaction) - ) - complexThreeTupleInlineParam( - param: Tuple<[PrimitiveTwoTuple, User, Reaction]> - ): Tuple<[PrimitiveTwoTuple, User, Reaction]> { - return param; - } - - @query([Vec(Header)], Vec(Header)) - tupleArrayParamsAndReturnType(headers: Vec
): Vec
{ - return headers; - } - - @query([], HttpResponse) - tupleArrayRecordField(): HttpResponse { - return { - headers: [ - ['Content-Type', 'application/json'], - ['Accept-Ranges', 'bytes'] - ] - }; - } - - @query([], StreamingCallbackType) - tupleArrayVariantField(): StreamingCallbackType { - return { - WithHeaders: [ - ['Content-Type', 'application/json'], - ['Accept-Ranges', 'bytes'] - ] - }; - } - - @query( - [ - Tuple( - IDL.Record({ hello: IDL.Nat64 }), - IDL.Record({ goodbye: IDL.Nat64 }) - ) - ], - Tuple( - IDL.Record({ hello: IDL.Nat64 }), - IDL.Record({ goodbye: IDL.Nat64 }) - ) - ) - twoTupleWithInlineRecords( - param: Tuple<[{ [hello: string]: nat64 }, { [goodbye: string]: nat64 }]> - ): Tuple<[{ [hello: string]: nat64 }, { [goodbye: string]: nat64 }]> { - return param; - } - - @query( - [Tuple(Tuple(text, Tuple(nat8, nat8)), int)], - Tuple(Tuple(text, Tuple(nat8, nat8)), int) - ) - nestedTupleQuery( - param: Tuple<[Tuple<[text, Tuple<[nat8, nat8]>]>, int]> - ): Tuple<[Tuple<[text, Tuple<[nat8, nat8]>]>, int]> { - return param; - } -} diff --git a/examples/tuple_types/test/tests.ts b/examples/tuple_types/test/tests.ts index d9dd74d680..b5f3a15819 100644 --- a/examples/tuple_types/test/tests.ts +++ b/examples/tuple_types/test/tests.ts @@ -466,24 +466,6 @@ export function getTests(tupleTypesCanister: ActorSubclass<_SERVICE>): Test[] { }; } }, - { - name: 'twoTupleWithInlineRecords', - test: async () => { - const result = - await tupleTypesCanister.twoTupleWithInlineRecords([ - { - hello: 0n - }, - { - goodbye: 1n - } - ]); - - return { - Ok: result[0].hello === 0n && result[1].goodbye === 1n - }; - } - }, { name: 'nested tuple test', test: async () => { @@ -491,9 +473,8 @@ export function getTests(tupleTypesCanister: ActorSubclass<_SERVICE>): Test[] { ['hello', [5, 10]], 123n ]; - const result = await tupleTypesCanister.nestedTupleQuery( - expectedResult - ); + const result = + await tupleTypesCanister.nestedTupleQuery(expectedResult); return { Ok: From d15fabe97342842c283c04595b392d3b2cdf77ee Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 15:25:46 -0600 Subject: [PATCH 24/37] change superheros to preferred recursive syntax --- .github/workflows/test.yml | 2 +- .../src/declarations/superheroes.did | 22 +++++------ .../src/declarations/superheroes.did.d.ts | 22 ++++++----- .../src/declarations/superheroes.did.js | 39 ++++++++++++++----- .../superheroes/src/superheroes/index.did | 22 +++++------ .../superheroes/src/superheroes/index.ts | 5 +-- 6 files changed, 62 insertions(+), 50 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f670959845..c7638d1d07 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,6 @@ # All Examples TODO restore when https://github.com/demergent-labs/azle/issues/1192 is resolved # "examples/generics", -# "examples/motoko_examples/superheroes", # blocked by recursive # "examples/run_time_errors", name: Azle Tests @@ -103,6 +102,7 @@ jobs: "examples/motoko_examples/phone-book", "examples/motoko_examples/quicksort", "examples/motoko_examples/simple-to-do", + "examples/motoko_examples/superheroes", "examples/motoko_examples/threshold_ecdsa", "examples/motoko_examples/whoami", "examples/notify_raw", diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did b/examples/motoko_examples/superheroes/src/declarations/superheroes.did index 0ecec61832..3770e592a2 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did @@ -1,13 +1,9 @@ -type Superhero = record { - "name": text; - "superpowers": opt List; -}; - -type List = record { text; opt List }; - -service: { - read: (nat32) -> (opt Superhero) query; - create: (Superhero) -> (nat32); - update: (nat32, Superhero) -> (bool); - delete_hero: (nat32) -> (bool); -} +type rec_28 = record {text; opt rec_28}; +type rec_33 = record {text; opt rec_33}; +type rec_36 = record {text; opt rec_36}; +service: () -> { + create: (record {superpowers:opt rec_28; name:text}) -> (nat32) ; + deleteHero: (nat32) -> (bool) ; + read: (nat32) -> (opt record {superpowers:opt rec_33; name:text}) query; + update: (nat32, record {superpowers:opt rec_36; name:text}) -> (bool) ; +} \ No newline at end of file diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts index fbb471d2dc..fe81f1b8a5 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.d.ts @@ -1,14 +1,18 @@ import type { Principal } from '@dfinity/principal'; import type { ActorMethod } from '@dfinity/agent'; -export type List = [string, [] | [List]]; -export interface Superhero { - superpowers: [] | [List]; - name: string; -} +export type rec_28 = [string, [] | [rec_28]]; +export type rec_33 = [string, [] | [rec_33]]; +export type rec_36 = [string, [] | [rec_36]]; export interface _SERVICE { - create: ActorMethod<[Superhero], number>; - delete_hero: ActorMethod<[number], boolean>; - read: ActorMethod<[number], [] | [Superhero]>; - update: ActorMethod<[number, Superhero], boolean>; + create: ActorMethod<[{ superpowers: [] | [rec_28]; name: string }], number>; + deleteHero: ActorMethod<[number], boolean>; + read: ActorMethod< + [number], + [] | [{ superpowers: [] | [rec_33]; name: string }] + >; + update: ActorMethod< + [number, { superpowers: [] | [rec_36]; name: string }], + boolean + >; } diff --git a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js index abff0d95de..4a110b6606 100644 --- a/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js +++ b/examples/motoko_examples/superheroes/src/declarations/superheroes.did.js @@ -1,15 +1,34 @@ export const idlFactory = ({ IDL }) => { - const List = IDL.Rec(); - List.fill(IDL.Tuple(IDL.Text, IDL.Opt(List))); - const Superhero = IDL.Record({ - superpowers: IDL.Opt(List), - name: IDL.Text - }); + const rec_28 = IDL.Rec(); + const rec_33 = IDL.Rec(); + const rec_36 = IDL.Rec(); + rec_28.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_28))); + rec_33.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_33))); + rec_36.fill(IDL.Tuple(IDL.Text, IDL.Opt(rec_36))); return IDL.Service({ - create: IDL.Func([Superhero], [IDL.Nat32], []), - delete_hero: IDL.Func([IDL.Nat32], [IDL.Bool], []), - read: IDL.Func([IDL.Nat32], [IDL.Opt(Superhero)], ['query']), - update: IDL.Func([IDL.Nat32, Superhero], [IDL.Bool], []) + create: IDL.Func( + [IDL.Record({ superpowers: IDL.Opt(rec_28), name: IDL.Text })], + [IDL.Nat32], + [] + ), + deleteHero: IDL.Func([IDL.Nat32], [IDL.Bool], []), + read: IDL.Func( + [IDL.Nat32], + [ + IDL.Opt( + IDL.Record({ superpowers: IDL.Opt(rec_33), name: IDL.Text }) + ) + ], + ['query'] + ), + update: IDL.Func( + [ + IDL.Nat32, + IDL.Record({ superpowers: IDL.Opt(rec_36), name: IDL.Text }) + ], + [IDL.Bool], + [] + ) }); }; export const init = ({ IDL }) => { diff --git a/examples/motoko_examples/superheroes/src/superheroes/index.did b/examples/motoko_examples/superheroes/src/superheroes/index.did index 0ecec61832..3770e592a2 100644 --- a/examples/motoko_examples/superheroes/src/superheroes/index.did +++ b/examples/motoko_examples/superheroes/src/superheroes/index.did @@ -1,13 +1,9 @@ -type Superhero = record { - "name": text; - "superpowers": opt List; -}; - -type List = record { text; opt List }; - -service: { - read: (nat32) -> (opt Superhero) query; - create: (Superhero) -> (nat32); - update: (nat32, Superhero) -> (bool); - delete_hero: (nat32) -> (bool); -} +type rec_28 = record {text; opt rec_28}; +type rec_33 = record {text; opt rec_33}; +type rec_36 = record {text; opt rec_36}; +service: () -> { + create: (record {superpowers:opt rec_28; name:text}) -> (nat32) ; + deleteHero: (nat32) -> (bool) ; + read: (nat32) -> (opt record {superpowers:opt rec_33; name:text}) query; + update: (nat32, record {superpowers:opt rec_36; name:text}) -> (bool) ; +} \ No newline at end of file diff --git a/examples/motoko_examples/superheroes/src/superheroes/index.ts b/examples/motoko_examples/superheroes/src/superheroes/index.ts index a46342a215..1f4f20e5d9 100644 --- a/examples/motoko_examples/superheroes/src/superheroes/index.ts +++ b/examples/motoko_examples/superheroes/src/superheroes/index.ts @@ -17,10 +17,7 @@ import { export type SuperheroId = nat32; const SuperheroId = nat32; -const List = Tuple( - text, - Recursive(() => Opt(List)) -); +const List = Recursive(() => Tuple(text, Opt(List))); // The type of a superhero. const Superhero = Record({ From e852e0fbdcac9f24e1a7e80ef360f95ab3b20191 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 18:17:22 -0600 Subject: [PATCH 25/37] fix init params --- examples/motoko_examples/whoami/src/index.did | 6 +- .../candid/reference/service.ts | 5 +- src/lib_new/visitors/did_visitor.ts | 103 ++++++++++++++++-- 3 files changed, 99 insertions(+), 15 deletions(-) diff --git a/examples/motoko_examples/whoami/src/index.did b/examples/motoko_examples/whoami/src/index.did index e1800ff5cf..938102e04d 100644 --- a/examples/motoko_examples/whoami/src/index.did +++ b/examples/motoko_examples/whoami/src/index.did @@ -1,7 +1,7 @@ service: (principal) -> { - installer: () -> (principal) query; argument: () -> (principal) query; - whoami: () -> (principal); id: () -> (principal); idQuick: () -> (principal) query; -} + installer: () -> (principal) query; + whoami: () -> (principal); +} \ No newline at end of file diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index 1d7da177ff..f0cce8545c 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -228,10 +228,7 @@ export function Canister( parents ); - const annotations = - functionInfo(parentOrUndefined).mode === 'update' - ? [] - : ['query']; + const annotations = [functionInfo(parentOrUndefined).mode]; return { ...accumulator, diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 8d330c9499..1415c8f9bc 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -58,19 +58,104 @@ export function extractCandid( export class DidVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { - const stuff = t._fields.map(([_name, func]) => - func.accept(this, { ...data, isOnService: true }) + // To get all of the candid types we need to look at all of the methods + const isOtherFunction = (func: IDL.FuncClass) => { + return ( + !func.annotations.includes('update') && + !func.annotations.includes('query') && + !func.annotations.includes('init') && + !func.annotations.includes('postUpgrade') + ); + }; + const otherCandidTypes = extractCandid( + t._fields + .filter(([_name, func]) => isOtherFunction(func)) + .map(([_name, func]) => + func.accept(this, { ...data, isOnService: true }) + ) + )[1]; + + const isQueryOrUpdateFunction = (func: IDL.FuncClass) => { + return ( + func.annotations.includes('update') || + func.annotations.includes('query') + ); + }; + // To get all of the canister methods we need to only look at update and query + const canisterMethods = extractCandid( + t._fields + .filter(([_name, func]) => isQueryOrUpdateFunction(func)) + .map(([_name, func]) => + func.accept(this, { ...data, isOnService: true }) + ) + ); + const canisterMethodsNames = t._fields + .filter(([_name, func]) => isQueryOrUpdateFunction(func)) + .map(([name, _func]) => name); + + const isInitFunction = (func: IDL.FuncClass) => + func.annotations.includes('init'); + const isPostUpgradeFunction = (func: IDL.FuncClass) => + func.annotations.includes('postUpgrade'); + // To get the service params we need to look at the init function + const initMethod = extractCandid( + t._fields + .filter(([_name, func]) => isInitFunction(func)) + .map(([_name, initFunc]) => + initFunc.accept(this, { ...data, isOnService: true }) + ) + ); + const postMethod = extractCandid( + t._fields + .filter(([_name, func]) => isPostUpgradeFunction(func)) + .map(([_name, initFunc]) => + initFunc.accept(this, { ...data, isOnService: true }) + ) ); - const candid = extractCandid(stuff); - const funcStrings = candid[0] + const initMethodCandidString = initMethod[0]; + const postMethodCandidString = postMethod[0]; + function getFunctionParams( + initFuncString: string[], + postFuncString: string[] + ) { + if (initFuncString.length === 0) { + if (postFuncString.length === 0) { + return '()'; + } + const parts = postFuncString[0].split('->'); + if (parts.length >= 2) { + return parts[0].trim(); + } + } + const parts = initFuncString[0].split('->'); + if (parts.length >= 2) { + return parts[0].trim(); + } + } + const canisterParamsString = getFunctionParams( + initMethodCandidString, + postMethodCandidString + ); + + const candidTypes = { + ...otherCandidTypes, + ...canisterMethods[1], + ...initMethod[1], + ...postMethod[1] + }; + + const funcStrings = canisterMethods[0] .map((value, index) => { - return `\t${t._fields[index][0]}: ${value};`; + return ` ${canisterMethodsNames[index]}: ${value};`; }) .join('\n'); if (data.isFirstService) { - return [`service: () -> {\n${funcStrings}\n}`, candid[1]]; + return [ + `service: ${canisterParamsString} -> {\n${funcStrings}\n}`, + candidTypes + ]; } - return [`service {\n${funcStrings}\n}`, candid[1]]; + return [`service {\n${funcStrings}\n}`, candidTypes]; } visitPrimitive( t: IDL.PrimitiveType, @@ -116,7 +201,9 @@ export class DidVisitor extends IDL.Visitor { const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); const rets = candidRets[0].join(', '); - const annon = ' ' + t.annotations.join(' '); + const annon = t.annotations.includes('update') + ? '' + : ' ' + t.annotations.join(' '); return [ `${data.isOnService ? '' : 'func '}(${args}) -> (${rets})${annon}`, { ...candidArgs[1], ...candidRets[1] } From 9f3116efaad8f182067987b451eebee67df884c7 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 18:32:35 -0600 Subject: [PATCH 26/37] make who am i recursive again --- examples/motoko_examples/whoami/src/index.ts | 87 ++++++++++---------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/examples/motoko_examples/whoami/src/index.ts b/examples/motoko_examples/whoami/src/index.ts index 7d5188ee22..16387afade 100644 --- a/examples/motoko_examples/whoami/src/index.ts +++ b/examples/motoko_examples/whoami/src/index.ts @@ -5,54 +5,55 @@ import { postUpgrade, Principal, query, - update + Recursive, + update, + Void } from 'azle'; // We use the zero principal but any principal could be used. let install: Principal = Principal.fromText('aaaaa-aa'); let someone: Principal = Principal.fromText('aaaaa-aa'); -const whoami = update([], Principal, () => { - return ic.caller(); -}); +const WhoAmI = Recursive(() => + Canister({ + // Manually save the calling principal and argument for later access. + init: init([Principal], (somebody) => { + install = ic.caller(); + someone = somebody; + }), + // Manually re-save these variables after new deploys. + postUpgrade: postUpgrade([Principal], (somebody) => { + install = ic.caller(); + someone = somebody; + }), + // Return the principal identifier of the wallet canister that installed this + // canister. + installer: query([], Principal, () => { + return install; + }), + // Return the principal identifier that was provided as an installation + // argument to this canister. + argument: query([], Principal, () => { + return someone; + }), + // Return the principal identifier of the caller of this method. + whoami: update([], Principal, () => { + return ic.caller(); + }), + // Return the principal identifier of this canister. + id: update([], Principal, async () => { + const self = WhoAmI(ic.id()); -export default Canister({ - // Manually save the calling principal and argument for later access. - init: init([Principal], (somebody) => { - install = ic.caller(); - someone = somebody; - }), - // Manually re-save these variables after new deploys. - postUpgrade: postUpgrade([Principal], (somebody) => { - install = ic.caller(); - someone = somebody; - }), - // Return the principal identifier of the wallet canister that installed this - // canister. - installer: query([], Principal, () => { - return install; - }), - // Return the principal identifier that was provided as an installation - // argument to this canister. - argument: query([], Principal, () => { - return someone; - }), - // Return the principal identifier of the caller of this method. - whoami, - // Return the principal identifier of this canister. - id: update([], Principal, async () => { - // TODO This is not an ideal solution but will work for now - const self = Canister({ - whoami - })(ic.id()); - - return await ic.call(self.whoami); - }), - // Return the principal identifier of this canister via the global `ic` object. - // This is much quicker than `id()` above because it isn't making a cross- - // canister call to itself. Additionally, it can now be a `Query` which means it - // doesn't have to go through consensus. - idQuick: query([], Principal, () => { - return ic.id(); + return await ic.call(self.whoami); + }), + // Return the principal identifier of this canister via the global `ic` object. + // This is much quicker than `id()` above because it isn't making a cross- + // canister call to itself. Additionally, it can now be a `Query` which means it + // doesn't have to go through consensus. + idQuick: query([], Principal, () => { + return ic.id(); + }) }) -}); +); + +export default WhoAmI; From 20871cbacbe4558d60aeef5e2159a7410f8d820b Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Fri, 29 Sep 2023 21:35:53 -0600 Subject: [PATCH 27/37] fix principal check --- src/lib_functional/candid/reference/service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index f0cce8545c..a175a37372 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -37,7 +37,7 @@ export function Canister( let result = (parentOrPrincipal: any) => { const originalPrincipal = parentOrPrincipal; const parentOrUndefined = - parentOrPrincipal instanceof Principal + parentOrPrincipal !== undefined && parentOrPrincipal._isPrincipal ? undefined : parentOrPrincipal; const callbacks = Object.entries(serviceOptions).reduce( @@ -245,7 +245,7 @@ export function Canister( return IDL.Service(record); }; - if (originalPrincipal instanceof Principal) { + if (originalPrincipal !== undefined && originalPrincipal._isPrincipal) { return returnFunction(originalPrincipal); } From a6d7cc2586a942f0fee4e66829b1a4cf06e033d6 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 06:41:01 -0600 Subject: [PATCH 28/37] fix candid files --- examples/bitcoin/src/index.did | 5 +- .../src/canister1/index.did | 15 +++-- .../src/canister2/index.did | 16 ++--- examples/ethereum_json_rpc/src/index.did | 7 +-- .../src/ledger_canister/index.did | 62 +++---------------- examples/management_canister/src/index.did | 22 +++---- .../threshold_ecdsa/src/index.did | 6 +- examples/outgoing_http_requests/src/index.did | 15 +---- src/lib_new/visitors/did_visitor.ts | 2 +- 9 files changed, 39 insertions(+), 111 deletions(-) diff --git a/examples/bitcoin/src/index.did b/examples/bitcoin/src/index.did index b74fa19ac0..043bb7c09d 100644 --- a/examples/bitcoin/src/index.did +++ b/examples/bitcoin/src/index.did @@ -1,9 +1,6 @@ -type rec_14 = record {txid:vec nat8; vout:nat32}; -type rec_13 = record {height:nat32; value:nat64; outpoint:rec_14}; -type rec_12 = record {next_page:opt vec nat8; tip_height:nat32; tip_block_hash:vec nat8; utxos:vec rec_13}; service: () -> { getBalance: (text) -> (nat64); getCurrentFeePercentiles: () -> (vec nat64); - getUtxos: (text) -> (rec_12); + getUtxos: (text) -> (record {next_page:opt vec nat8; tip_height:nat32; tip_block_hash:vec nat8; utxos:vec record {height:nat32; value:nat64; outpoint:record {txid:vec nat8; vout:nat32}}}); sendTransaction: (vec nat8) -> (bool); } diff --git a/examples/cross_canister_calls/src/canister1/index.did b/examples/cross_canister_calls/src/canister1/index.did index 8485841545..6b20dd1de2 100644 --- a/examples/cross_canister_calls/src/canister1/index.did +++ b/examples/cross_canister_calls/src/canister1/index.did @@ -1,9 +1,8 @@ service: () -> { - account: (record {id:text}) -> (opt record {id:text; balance:nat64}) ; - accounts: () -> (vec record {id:text; balance:nat64}) ; - balance: (text) -> (nat64) ; - init: () -> () query; - sendNotification: () -> () ; - transfer: (text, text, nat64) -> (nat64) ; - trap: () -> (text) ; -} \ No newline at end of file + account: (record {id:text}) -> (opt record {id:text; balance:nat64}); + accounts: () -> (vec record {id:text; balance:nat64}); + balance: (text) -> (nat64); + sendNotification: () -> (); + transfer: (text, text, nat64) -> (nat64); + trap: () -> (text); +} diff --git a/examples/cross_canister_calls/src/canister2/index.did b/examples/cross_canister_calls/src/canister2/index.did index 81034884ad..25c20581d3 100644 --- a/examples/cross_canister_calls/src/canister2/index.did +++ b/examples/cross_canister_calls/src/canister2/index.did @@ -1,9 +1,9 @@ service: () -> { - account: (record {id:text}) -> (opt record {id:text; balance:nat64}) query; - accounts: () -> (vec record {id:text; balance:nat64}) query; - balance: (text) -> (nat64) query; - getNotification: () -> (text) query; - receiveNotification: (text) -> () ; - transfer: (text, text, nat64) -> (nat64) ; - trap: () -> (text) query; -} \ No newline at end of file + account: (record {id:text}) -> (opt record {id:text; balance:nat64}) query; + accounts: () -> (vec record {id:text; balance:nat64}) query; + balance: (text) -> (nat64) query; + getNotification: () -> (text) query; + receiveNotification: (text) -> (); + transfer: (text, text, nat64) -> (nat64); + trap: () -> (text) query; +} diff --git a/examples/ethereum_json_rpc/src/index.did b/examples/ethereum_json_rpc/src/index.did index 76ed21ee25..fbffd45803 100644 --- a/examples/ethereum_json_rpc/src/index.did +++ b/examples/ethereum_json_rpc/src/index.did @@ -1,10 +1,5 @@ -type rec_25 = record {value:text; name:text}; -type rec_24 = record {status:nat; body:vec nat8; headers:vec rec_25}; -type rec_23 = record {context:vec nat8; response:rec_24}; -type rec_27 = record {value:text; name:text}; -type rec_26 = record {status:nat; body:vec nat8; headers:vec rec_27}; service: (text) -> { ethGetBalance: (text) -> (text); ethGetBlockByNumber: (nat32) -> (text); - ethTransform: (rec_23) -> (rec_26) query; + ethTransform: (record {context:vec nat8; response:record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}}) -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}) query; } diff --git a/examples/ledger_canister/src/ledger_canister/index.did b/examples/ledger_canister/src/ledger_canister/index.did index fa9bf09b34..b782e58e0e 100644 --- a/examples/ledger_canister/src/ledger_canister/index.did +++ b/examples/ledger_canister/src/ledger_canister/index.did @@ -1,57 +1,11 @@ -type rec_116 = record {allowed_window_nanos:nat64}; -type rec_113 = record {e8s:nat64}; -type rec_112 = record {expected_fee:rec_113}; -type rec_117 = record {duplicate_of:nat64}; -type rec_115 = record {e8s:nat64}; -type rec_114 = record {balance:rec_115}; -type rec_111 = variant {TxTooOld:rec_116; BadFee:rec_112; TxDuplicate:rec_117; TxCreatedInFuture; InsufficientFunds:rec_114}; -type rec_110 = variant {Ok:nat64; Err:rec_111}; -type rec_118 = record {e8s:nat64}; -type rec_120 = record {e8s:nat64}; -type rec_119 = record {transfer_fee:rec_120}; -type rec_121 = record {start:nat64; length:nat64}; -type rec_129 = record {e8s:nat64}; -type rec_128 = record {from:vec nat8; amount:rec_129}; -type rec_127 = record {e8s:nat64}; -type rec_126 = record {to:vec nat8; amount:rec_127}; -type rec_132 = record {e8s:nat64}; -type rec_131 = record {e8s:nat64}; -type rec_130 = record {to:vec nat8; fee:rec_132; from:vec nat8; amount:rec_131}; -type rec_125 = variant {Burn:rec_128; Mint:rec_126; Transfer:rec_130}; -type rec_133 = record {timestamp_nanos:nat64}; -type rec_124 = record {memo:nat64; operation:opt rec_125; created_at_time:rec_133}; -type rec_134 = record {timestamp_nanos:nat64}; -type rec_123 = record {transaction:rec_124; timestamp:rec_134; parent_hash:opt vec nat8}; -type rec_136 = record {start:nat64; length:nat64}; -type rec_145 = record {e8s:nat64}; -type rec_144 = record {from:vec nat8; amount:rec_145}; -type rec_143 = record {e8s:nat64}; -type rec_142 = record {to:vec nat8; amount:rec_143}; -type rec_148 = record {e8s:nat64}; -type rec_147 = record {e8s:nat64}; -type rec_146 = record {to:vec nat8; fee:rec_148; from:vec nat8; amount:rec_147}; -type rec_141 = variant {Burn:rec_144; Mint:rec_142; Transfer:rec_146}; -type rec_149 = record {timestamp_nanos:nat64}; -type rec_140 = record {memo:nat64; operation:opt rec_141; created_at_time:rec_149}; -type rec_150 = record {timestamp_nanos:nat64}; -type rec_139 = record {transaction:rec_140; timestamp:rec_150; parent_hash:opt vec nat8}; -type rec_138 = record {blocks:vec rec_139}; -type rec_152 = record {requested_index:nat64; first_valid_index:nat64}; -type rec_153 = record {error_message:text; error_code:nat64}; -type rec_151 = variant {BadFirstBlockIndex:rec_152; Other:rec_153}; -type rec_137 = variant {Ok:rec_138; Err:rec_151}; -type rec_135 = record {callback:func (rec_136) -> (rec_137) query; start:nat64; length:nat64}; -type rec_122 = record {certificate:opt vec nat8; blocks:vec rec_123; chain_length:nat64; first_block_index:nat64; archived_blocks:vec rec_135}; -type rec_155 = record {canister_id:principal}; -type rec_154 = record {archives:vec rec_155}; service: () -> { - executeTransfer: (text, nat64, nat64, opt nat64) -> (rec_110); - getAccountBalance: (text) -> (rec_118); - getTransferFee: () -> (rec_119); - getBlocks: (rec_121) -> (rec_122); - getSymbol: () -> (text); - getName: () -> (text); - getDecimals: () -> (nat32); - getArchives: () -> (rec_154); + executeTransfer: (text, nat64, nat64, opt nat64) -> (variant {Ok:nat64; Err:variant {TxTooOld:record {allowed_window_nanos:nat64}; BadFee:record {expected_fee:record {e8s:nat64}}; TxDuplicate:record {duplicate_of:nat64}; TxCreatedInFuture; InsufficientFunds:record {balance:record {e8s:nat64}}}}) ; + getAccountBalance: (text) -> (record {e8s:nat64}) ; getAddressFromPrincipal: (principal) -> (text) query; + getArchives: () -> (record {archives:vec record {canister_id:principal}}) ; + getBlocks: (record {start:nat64; length:nat64}) -> (record {certificate:opt vec nat8; blocks:vec record {transaction:record {memo:nat64; operation:opt variant {Burn:record {from:vec nat8; amount:record {e8s:nat64}}; Mint:record {to:vec nat8; amount:record {e8s:nat64}}; Transfer:record {to:vec nat8; fee:record {e8s:nat64}; from:vec nat8; amount:record {e8s:nat64}}}; created_at_time:record {timestamp_nanos:nat64}}; timestamp:record {timestamp_nanos:nat64}; parent_hash:opt vec nat8}; chain_length:nat64; first_block_index:nat64; archived_blocks:vec record {callback:func (record {start:nat64; length:nat64}) -> (variant {Ok:record {blocks:vec record {transaction:record {memo:nat64; operation:opt variant {Burn:record {from:vec nat8; amount:record {e8s:nat64}}; Mint:record {to:vec nat8; amount:record {e8s:nat64}}; Transfer:record {to:vec nat8; fee:record {e8s:nat64}; from:vec nat8; amount:record {e8s:nat64}}}; created_at_time:record {timestamp_nanos:nat64}}; timestamp:record {timestamp_nanos:nat64}; parent_hash:opt vec nat8}}; Err:variant {BadFirstBlockIndex:record {requested_index:nat64; first_valid_index:nat64}; Other:record {error_message:text; error_code:nat64}}}) query; start:nat64; length:nat64}}) ; + getDecimals: () -> (nat32) ; + getName: () -> (text) ; + getSymbol: () -> (text) ; + getTransferFee: () -> (record {transfer_fee:record {e8s:nat64}}) ; } diff --git a/examples/management_canister/src/index.did b/examples/management_canister/src/index.did index dc30cc1319..1c11a82a54 100644 --- a/examples/management_canister/src/index.did +++ b/examples/management_canister/src/index.did @@ -1,21 +1,15 @@ -type rec_43 = record {canister_id:principal}; -type rec_44 = record {canister_id:principal}; -type rec_46 = variant {stopped; stopping; running}; -type rec_47 = record {freezing_threshold:nat; controllers:vec principal; memory_allocation:nat; compute_allocation:nat}; -type rec_45 = record {status:rec_46; memory_size:nat; cycles:nat; settings:rec_47; module_hash:opt vec nat8}; -type rec_48 = record {canister_id:principal}; service: () -> { - executeCreateCanister: () -> (rec_43); - executeUpdateSettings: (principal) -> (bool); + executeCreateCanister: () -> (record {canister_id:principal}); + executeDeleteCanister: (principal) -> (bool); + executeDepositCycles: (principal) -> (bool); executeInstallCode: (principal, vec nat8) -> (bool); - executeUninstallCode: (principal) -> (bool); executeStartCanister: (principal) -> (bool); executeStopCanister: (principal) -> (bool); - getCanisterStatus: (rec_44) -> (rec_45); - executeDeleteCanister: (principal) -> (bool); - executeDepositCycles: (principal) -> (bool); + executeUninstallCode: (principal) -> (bool); + executeUpdateSettings: (principal) -> (bool); + getCanisterStatus: (record {canister_id:principal}) -> (record {status:variant {stopped; stopping; running}; memory_size:nat; cycles:nat; settings:record {freezing_threshold:nat; controllers:vec principal; memory_allocation:nat; compute_allocation:nat}; module_hash:opt vec nat8}); + getCreatedCanisterId: () -> (principal) query; getRawRand: () -> (vec nat8); - provisionalCreateCanisterWithCycles: () -> (rec_48); + provisionalCreateCanisterWithCycles: () -> (record {canister_id:principal}); provisionalTopUpCanister: (principal, nat) -> (bool); - getCreatedCanisterId: () -> (principal) query; } diff --git a/examples/motoko_examples/threshold_ecdsa/src/index.did b/examples/motoko_examples/threshold_ecdsa/src/index.did index 69a1c2bb9b..74f57782b3 100644 --- a/examples/motoko_examples/threshold_ecdsa/src/index.did +++ b/examples/motoko_examples/threshold_ecdsa/src/index.did @@ -1,6 +1,4 @@ -type rec_51 = record {publicKey:vec nat8}; -type rec_52 = record {signature:vec nat8}; service: () -> { - publicKey: () -> (rec_51); - sign: (vec nat8) -> (rec_52); + publicKey: () -> (record {publicKey:vec nat8}); + sign: (vec nat8) -> (record {signature:vec nat8}); } diff --git a/examples/outgoing_http_requests/src/index.did b/examples/outgoing_http_requests/src/index.did index b329d2a5dd..bd5b328ba0 100644 --- a/examples/outgoing_http_requests/src/index.did +++ b/examples/outgoing_http_requests/src/index.did @@ -1,14 +1,5 @@ -type rec_52 = record {value:text; name:text}; -type rec_51 = record {status:nat; body:vec nat8; headers:vec rec_52}; -type rec_54 = record {value:text; name:text}; -type rec_53 = record {status:nat; body:vec nat8; headers:vec rec_54}; -type rec_57 = record {value:text; name:text}; -type rec_56 = record {status:nat; body:vec nat8; headers:vec rec_57}; -type rec_55 = record {context:vec nat8; response:rec_56}; -type rec_59 = record {value:text; name:text}; -type rec_58 = record {status:nat; body:vec nat8; headers:vec rec_59}; service: () -> { - xkcd: () -> (rec_51); - xkcdRaw: () -> (rec_53); - xkcdTransform: (rec_55) -> (rec_58) query; + xkcd: () -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}); + xkcdRaw: () -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}); + xkcdTransform: (record {context:vec nat8; response:record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}}) -> (record {status:nat; body:vec nat8; headers:vec record {value:text; name:text}}) query; } diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 1415c8f9bc..bc6f877167 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -23,7 +23,7 @@ export const DEFAULT_VISITOR_DATA: VisitorData = { export function DidResultToCandidString(result: VisitorResult): string { const [candid, candidTypeDefs] = result; const candidTypesString = newTypeToCandidString(candidTypeDefs); - return candidTypesString + candid; + return candidTypesString + candid + '\n'; } function newTypeToCandidString(newTypes: CandidTypesDefs): string { From c63286f317abb187c448df540c42b7402d2bde13 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 09:11:14 -0600 Subject: [PATCH 29/37] pass init and post upgrade params to did visitor --- examples/canister/src/index.did | 11 +- examples/canister/src/some_canister.did | 2 +- examples/complex_init/dfx.json | 16 ++- .../complex_init/src/complex_init/index.did | 3 + .../src/{ => complex_init}/index.ts | 0 examples/complex_init/src/index.did | 4 - examples/complex_init/src/rec_init/index.did | 4 + examples/complex_init/src/rec_init/index.ts | 27 +++++ examples/complex_init/test/pretest.ts | 15 +++ examples/complex_init/test/test.ts | 18 +++- examples/complex_init/test/tests.ts | 22 +++- .../generate_candid_and_canister_methods.ts | 15 +-- .../candid/reference/service.ts | 70 +++++++++--- src/lib_new/utils.ts | 3 + src/lib_new/visitors/did_visitor.ts | 100 ++++++++---------- src/lib_new/visitors/encode_decode/index.ts | 23 ++-- 16 files changed, 230 insertions(+), 103 deletions(-) create mode 100644 examples/complex_init/src/complex_init/index.did rename examples/complex_init/src/{ => complex_init}/index.ts (100%) delete mode 100644 examples/complex_init/src/index.did create mode 100644 examples/complex_init/src/rec_init/index.did create mode 100644 examples/complex_init/src/rec_init/index.ts diff --git a/examples/canister/src/index.did b/examples/canister/src/index.did index dc020cd99a..4d7160845f 100644 --- a/examples/canister/src/index.did +++ b/examples/canister/src/index.did @@ -1,8 +1,7 @@ -type rec_0 = record {someCanister:service {query1:() -> (bool) query; update1:() -> (text) }}; service: () -> { - canisterParam: (service {query1:() -> (bool) query; update1:() -> (text) }) -> (service {query1:() -> (bool) query; update1:() -> (text) }) query; - canisterReturnType: () -> (service {query1:() -> (bool) query; update1:() -> (text) }) query; - canisterNestedReturnType: () -> (rec_0); - canisterList: (vec service {query1:() -> (bool) query; update1:() -> (text) }) -> (vec service {query1:() -> (bool) query; update1:() -> (text) }); - canisterCrossCanisterCall: (service {query1:() -> (bool) query; update1:() -> (text) }) -> (text); + canisterCrossCanisterCall: (service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (text) ; + canisterList: (vec service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (vec service {query1: () -> (bool) query; update1: () -> (text) ;}) ; + canisterNestedReturnType: () -> (record {someCanister:service {query1: () -> (bool) query; update1: () -> (text) ;}}) ; + canisterParam: (service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (service {query1: () -> (bool) query; update1: () -> (text) ;}) query; + canisterReturnType: () -> (service {query1: () -> (bool) query; update1: () -> (text) ;}) query; } diff --git a/examples/canister/src/some_canister.did b/examples/canister/src/some_canister.did index f61de65f9f..5352637a43 100644 --- a/examples/canister/src/some_canister.did +++ b/examples/canister/src/some_canister.did @@ -1,4 +1,4 @@ service: () -> { query1: () -> (bool) query; - update1: () -> (text); + update1: () -> (text) ; } diff --git a/examples/complex_init/dfx.json b/examples/complex_init/dfx.json index 4e133518fa..d0d1e9bb68 100644 --- a/examples/complex_init/dfx.json +++ b/examples/complex_init/dfx.json @@ -2,15 +2,27 @@ "canisters": { "complex_init": { "type": "custom", - "main": "src/index.ts", + "main": "src/complex_init/index.ts", "build": "npx azle complex_init", - "candid": "src/index.did", + "candid": "src/complex_init/index.did", "wasm": ".azle/complex_init/complex_init.wasm", "gzip": true, "declarations": { "output": "test/dfx_generated/complex_init", "node_compatibility": true } + }, + "rec_init": { + "type": "custom", + "main": "src/rec_init/index.ts", + "build": "npx azle rec_init", + "candid": "src/rec_init/index.did", + "wasm": ".azle/rec_init/rec_init.wasm", + "gzip": true, + "declarations": { + "output": "test/dfx_generated/rec_init", + "node_compatibility": true + } } } } diff --git a/examples/complex_init/src/complex_init/index.did b/examples/complex_init/src/complex_init/index.did new file mode 100644 index 0000000000..fe1b700ef7 --- /dev/null +++ b/examples/complex_init/src/complex_init/index.did @@ -0,0 +1,3 @@ +service: (record {text; record {id:text}}) -> { + greetUser: () -> (text) query; +} diff --git a/examples/complex_init/src/index.ts b/examples/complex_init/src/complex_init/index.ts similarity index 100% rename from examples/complex_init/src/index.ts rename to examples/complex_init/src/complex_init/index.ts diff --git a/examples/complex_init/src/index.did b/examples/complex_init/src/index.did deleted file mode 100644 index c5e0ff4181..0000000000 --- a/examples/complex_init/src/index.did +++ /dev/null @@ -1,4 +0,0 @@ -type rec_0 = record {id:text}; -service: (record {text; rec_0}) -> { - greetUser: () -> (text) query; -} diff --git a/examples/complex_init/src/rec_init/index.did b/examples/complex_init/src/rec_init/index.did new file mode 100644 index 0000000000..b59721ecf3 --- /dev/null +++ b/examples/complex_init/src/rec_init/index.did @@ -0,0 +1,4 @@ +type rec_14 = variant {Leaf; Branch:rec_14}; +service: (rec_14) -> { + countBranches: () -> (nat) query; +} diff --git a/examples/complex_init/src/rec_init/index.ts b/examples/complex_init/src/rec_init/index.ts new file mode 100644 index 0000000000..f889a630c7 --- /dev/null +++ b/examples/complex_init/src/rec_init/index.ts @@ -0,0 +1,27 @@ +import { Canister, init, Null, query, Recursive, Variant, nat } from 'azle'; + +const Node = Recursive(() => + Variant({ + Leaf: Null, + Branch: Node + }) +); + +let tree: typeof Node = { Leaf: null }; + +export default Canister({ + init: init([Node], (node) => { + tree = node; + return undefined; + }), + countBranches: query([], nat, () => { + return countBranches(tree); + }) +}); + +function countBranches(node: typeof Node): nat { + if (node.Leaf !== undefined) { + return 1n; + } + return countBranches(node.Branch); +} diff --git a/examples/complex_init/test/pretest.ts b/examples/complex_init/test/pretest.ts index aec765eb9a..75fdf71c25 100644 --- a/examples/complex_init/test/pretest.ts +++ b/examples/complex_init/test/pretest.ts @@ -7,6 +7,10 @@ async function pretest() { stdio: 'inherit' }); + execSync(`dfx canister uninstall-code rec_init || true`, { + stdio: 'inherit' + }); + execSync( `dfx deploy complex_init --argument 'record {"Oh hello there user"; record { id = "1" }}'`, { @@ -14,9 +18,20 @@ async function pretest() { } ); + execSync( + `dfx deploy rec_init --argument 'variant {Branch = variant {Leaf}}'`, + { + stdio: 'inherit' + } + ); + execSync(`dfx generate complex_init`, { stdio: 'inherit' }); + + execSync(`dfx generate rec_init`, { + stdio: 'inherit' + }); } pretest(); diff --git a/examples/complex_init/test/test.ts b/examples/complex_init/test/test.ts index 360b581f45..a8d214f6d3 100644 --- a/examples/complex_init/test/test.ts +++ b/examples/complex_init/test/test.ts @@ -1,11 +1,21 @@ import { getCanisterId, runTests } from 'azle/test'; -import { createActor } from '../test/dfx_generated/complex_init'; -import { get_tests } from './tests'; +import { createActor as createComplexActor } from '../test/dfx_generated/complex_init'; +import { createActor as createRecActor } from '../test/dfx_generated/rec_init'; +import { get_rec_tests, get_tests } from './tests'; -const complexInitCanister = createActor(getCanisterId('complex_init'), { +const complexInitCanister = createComplexActor(getCanisterId('complex_init'), { agentOptions: { host: 'http://127.0.0.1:8000' } }); -runTests(get_tests(complexInitCanister)); +const recInitCanister = createRecActor(getCanisterId('rec_init'), { + agentOptions: { + host: 'http://127.0.0.1:8000' + } +}); + +runTests([ + ...get_tests(complexInitCanister), + ...get_rec_tests(recInitCanister) +]); diff --git a/examples/complex_init/test/tests.ts b/examples/complex_init/test/tests.ts index ccf00753b8..cf96b8917d 100644 --- a/examples/complex_init/test/tests.ts +++ b/examples/complex_init/test/tests.ts @@ -1,9 +1,10 @@ import { ActorSubclass } from '@dfinity/agent'; import { Test } from 'azle/test'; -import { _SERVICE } from './dfx_generated/complex_init/complex_init.did'; +import { _SERVICE as _COMPLEX_SERVICE } from './dfx_generated/complex_init/complex_init.did'; +import { _SERVICE as _REC_SERVICE } from './dfx_generated/rec_init/rec_init.did'; export function get_tests( - complex_init_canister: ActorSubclass<_SERVICE> + complex_init_canister: ActorSubclass<_COMPLEX_SERVICE> ): Test[] { return [ { @@ -18,3 +19,20 @@ export function get_tests( } ]; } + +export function get_rec_tests( + rec_init_canister: ActorSubclass<_REC_SERVICE> +): Test[] { + return [ + { + name: 'count branches', + test: async () => { + const result = await rec_init_canister.countBranches(); + + return { + Ok: result === 1n + }; + } + } + ]; +} diff --git a/src/compiler/generate_candid_and_canister_methods.ts b/src/compiler/generate_candid_and_canister_methods.ts index deb63c621b..54179f049a 100644 --- a/src/compiler/generate_candid_and_canister_methods.ts +++ b/src/compiler/generate_candid_and_canister_methods.ts @@ -34,15 +34,16 @@ export function generateCandidAndCanisterMethods(mainJs: string): { const script = new vm.Script(mainJs); script.runInContext(context); - const candidInfo = (sandbox.exports as any).canisterMethods - .getIDL([]) - .accept(new DidVisitor(), { - ...DEFAULT_VISITOR_DATA, - isFirstService: true - }); + const canisterMethods = (sandbox.exports as any).canisterMethods; + + const candidInfo = canisterMethods.getIDL([]).accept(new DidVisitor(), { + ...DEFAULT_VISITOR_DATA, + isFirstService: true, + systemFuncs: canisterMethods.getSystemFunctionIDLs() + }); return { candid: DidResultToCandidString(candidInfo), - canisterMethods: (sandbox.exports as any).canisterMethods + canisterMethods: canisterMethods }; } diff --git a/src/lib_functional/candid/reference/service.ts b/src/lib_functional/candid/reference/service.ts index a175a37372..e7fed94b2d 100644 --- a/src/lib_functional/candid/reference/service.ts +++ b/src/lib_functional/candid/reference/service.ts @@ -214,11 +214,19 @@ export function Canister( returnFunction.queries = queries; returnFunction.updates = updates; returnFunction.callbacks = callbacks; - returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { + (returnFunction.getSystemFunctionIDLs = ( + parents: Parent[] + ): IDL.FuncClass[] => { const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - const record = Object.entries(serviceFunctionInfo).reduce( - (accumulator, [methodName, functionInfo]) => { + return Object.entries(serviceFunctionInfo).reduce( + (accumulator, [_methodName, functionInfo]) => { + const mode = functionInfo(parentOrUndefined).mode; + if (mode === 'update' || mode === 'query') { + // We don't want init, post upgrade, etc showing up in the idl + return accumulator; + } + const paramRealIdls = toParamIDLTypes( functionInfo(parentOrUndefined).paramsIdls, parents @@ -227,23 +235,53 @@ export function Canister( functionInfo(parentOrUndefined).returnIdl, parents ); - - const annotations = [functionInfo(parentOrUndefined).mode]; - - return { + return [ ...accumulator, - [methodName]: IDL.Func( - paramRealIdls, - returnRealIdl, - annotations - ) - }; + IDL.Func(paramRealIdls, returnRealIdl, [mode]) + ]; }, - {} as Record + [] as IDL.FuncClass[] ); + }), + (returnFunction.getIDL = (parents: Parent[]): IDL.ServiceClass => { + const serviceFunctionInfo: ServiceFunctionInfo = serviceOptions; - return IDL.Service(record); - }; + const record = Object.entries(serviceFunctionInfo).reduce( + (accumulator, [methodName, functionInfo]) => { + const paramRealIdls = toParamIDLTypes( + functionInfo(parentOrUndefined).paramsIdls, + parents + ); + const returnRealIdl = toReturnIDLType( + functionInfo(parentOrUndefined).returnIdl, + parents + ); + + const mode = functionInfo(parentOrUndefined).mode; + let annotations: string[] = []; + if (mode === 'update') { + // do nothing + } else if (mode === 'query') { + annotations = ['query']; + } else { + // We don't want init, post upgrade, etc showing up in the idl + return accumulator; + } + + return { + ...accumulator, + [methodName]: IDL.Func( + paramRealIdls, + returnRealIdl, + annotations + ) + }; + }, + {} as Record + ); + + return IDL.Service(record); + }); if (originalPrincipal !== undefined && originalPrincipal._isPrincipal) { return returnFunction(originalPrincipal); diff --git a/src/lib_new/utils.ts b/src/lib_new/utils.ts index 343e1d32fd..2255869811 100644 --- a/src/lib_new/utils.ts +++ b/src/lib_new/utils.ts @@ -89,6 +89,9 @@ export function toIDLType(idl: CandidClass, parents: Parent[]): IDL.Type { } return idl.getIDL(parents); } + if (idl._azleIsCanister) { + return toIDLType(idl(), parents); + } // if (idl.display === undefined || idl.getIDL === undefined) { // throw Error(`${JSON.stringify(idl)} is not a candid type`); // } diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index bc6f877167..519012cfb1 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -4,6 +4,7 @@ type VisitorData = { usedRecClasses: IDL.RecClass[]; isOnService: boolean; isFirstService: boolean; + systemFuncs: IDL.FuncClass[]; }; type VisitorResult = [CandidDef, CandidTypesDefs]; @@ -17,7 +18,8 @@ type VisitorResult = [CandidDef, CandidTypesDefs]; export const DEFAULT_VISITOR_DATA: VisitorData = { usedRecClasses: [], isOnService: false, - isFirstService: false + isFirstService: false, + systemFuncs: [] }; export function DidResultToCandidString(result: VisitorResult): string { @@ -56,42 +58,24 @@ export function extractCandid( return [paramCandid, candidTypeDefs]; } +function hch(value: any) { + if (value._azleIsCanister) { + return value().getIDL(); + } + return value; +} + export class DidVisitor extends IDL.Visitor { visitService(t: IDL.ServiceClass, data: VisitorData): VisitorResult { - // To get all of the candid types we need to look at all of the methods - const isOtherFunction = (func: IDL.FuncClass) => { - return ( - !func.annotations.includes('update') && - !func.annotations.includes('query') && - !func.annotations.includes('init') && - !func.annotations.includes('postUpgrade') - ); - }; - const otherCandidTypes = extractCandid( - t._fields - .filter(([_name, func]) => isOtherFunction(func)) - .map(([_name, func]) => - func.accept(this, { ...data, isOnService: true }) - ) - )[1]; - - const isQueryOrUpdateFunction = (func: IDL.FuncClass) => { - return ( - func.annotations.includes('update') || - func.annotations.includes('query') - ); - }; - // To get all of the canister methods we need to only look at update and query const canisterMethods = extractCandid( - t._fields - .filter(([_name, func]) => isQueryOrUpdateFunction(func)) - .map(([_name, func]) => - func.accept(this, { ...data, isOnService: true }) - ) + t._fields.map(([_name, func]) => + func.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) + ) ); - const canisterMethodsNames = t._fields - .filter(([_name, func]) => isQueryOrUpdateFunction(func)) - .map(([name, _func]) => name); const isInitFunction = (func: IDL.FuncClass) => func.annotations.includes('init'); @@ -99,17 +83,25 @@ export class DidVisitor extends IDL.Visitor { func.annotations.includes('postUpgrade'); // To get the service params we need to look at the init function const initMethod = extractCandid( - t._fields - .filter(([_name, func]) => isInitFunction(func)) - .map(([_name, initFunc]) => - initFunc.accept(this, { ...data, isOnService: true }) + data.systemFuncs + .filter((func) => isInitFunction(func)) + .map((initFunc) => + initFunc.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) ) ); const postMethod = extractCandid( - t._fields - .filter(([_name, func]) => isPostUpgradeFunction(func)) - .map(([_name, initFunc]) => - initFunc.accept(this, { ...data, isOnService: true }) + data.systemFuncs + .filter((func) => isPostUpgradeFunction(func)) + .map((initFunc) => + initFunc.accept(this, { + ...data, + isOnService: true, + isFirstService: false + }) ) ); const initMethodCandidString = initMethod[0]; @@ -138,24 +130,26 @@ export class DidVisitor extends IDL.Visitor { ); const candidTypes = { - ...otherCandidTypes, ...canisterMethods[1], ...initMethod[1], ...postMethod[1] }; + const tab = data.isFirstService ? ' ' : ''; + const func_separator = data.isFirstService ? '\n' : ' '; + const funcStrings = canisterMethods[0] .map((value, index) => { - return ` ${canisterMethodsNames[index]}: ${value};`; + return `${tab}${t._fields[index][0]}: ${value};`; }) - .join('\n'); + .join(func_separator); if (data.isFirstService) { return [ `service: ${canisterParamsString} -> {\n${funcStrings}\n}`, candidTypes ]; } - return [`service {\n${funcStrings}\n}`, candidTypes]; + return [`service {${funcStrings}}`, candidTypes]; } visitPrimitive( t: IDL.PrimitiveType, @@ -169,7 +163,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const fields = components.map((value) => - value.accept(this, { ...data, isOnService: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(fields); return [`record {${candid[0].join('; ')}}`, candid[1]]; @@ -179,7 +173,7 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, isOnService: false }); + const candid = hch(ty).accept(this, { ...data, isOnService: false }); return [`opt ${candid[0]}`, candid[1]]; } visitVec( @@ -187,16 +181,16 @@ export class DidVisitor extends IDL.Visitor { ty: IDL.Type, data: VisitorData ): VisitorResult { - const candid = ty.accept(this, { ...data, isOnService: false }); + const candid = hch(ty).accept(this, { ...data, isOnService: false }); return [`vec ${candid[0]}`, candid[1]]; } visitFunc(t: IDL.FuncClass, data: VisitorData): VisitorResult { const argsTypes = t.argTypes.map((value) => - value.accept(this, { ...data, isOnService: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candidArgs = extractCandid(argsTypes); const retsTypes = t.retTypes.map((value) => - value.accept(this, { ...data, isOnService: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); @@ -220,7 +214,7 @@ export class DidVisitor extends IDL.Visitor { // Everything else will just be the normal inline candid def const usedRecClasses = data.usedRecClasses; if (!usedRecClasses.includes(t)) { - const candid = ty.accept(this, { + const candid = hch(ty).accept(this, { usedRecClasses: [...usedRecClasses, t], isOnService: false, isFirstService: false @@ -237,7 +231,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, isOnService: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const field_strings = fields.map( @@ -251,7 +245,7 @@ export class DidVisitor extends IDL.Visitor { data: VisitorData ): VisitorResult { const candidFields = fields.map(([key, value]) => - value.accept(this, { ...data, isOnService: false }) + hch(value).accept(this, { ...data, isOnService: false }) ); const candid = extractCandid(candidFields); const fields_string = fields.map( diff --git a/src/lib_new/visitors/encode_decode/index.ts b/src/lib_new/visitors/encode_decode/index.ts index b2119a5dd9..bda98a20a3 100644 --- a/src/lib_new/visitors/encode_decode/index.ts +++ b/src/lib_new/visitors/encode_decode/index.ts @@ -22,13 +22,20 @@ export type VisitorResult = any; * is extracted into these helper methods. */ +function hch(value: any) { + if (value._azleIsCanister) { + return value().getIDL(); + } + return value; +} + export function visitTuple( visitor: DecodeVisitor | EncodeVisitor, components: IDL.Type[], data: VisitorData ): VisitorResult { const fields = components.map((value, index) => - value.accept(visitor, { + hch(value).accept(visitor, { js_data: data.js_data[index], js_class: data.js_class._azleTypes[index] }) @@ -44,7 +51,7 @@ export function visitOpt( if (data.js_data.length === 0) { return data.js_data; } - const candid = ty.accept(visitor, { + const candid = hch(ty).accept(visitor, { js_data: data.js_data[0], js_class: data.js_class._azleType }); @@ -60,7 +67,7 @@ export function visitVec( return data.js_data; } return data.js_data.map((array_elem: any) => { - return ty.accept(visitor, { + return hch(ty).accept(visitor, { js_data: array_elem, js_class: data.js_class._azleType }); @@ -78,7 +85,7 @@ export function visitRecord( return { ...acc, - [memberName]: memberIdl.accept(visitor, { + [memberName]: hch(memberIdl).accept(visitor, { js_data: fieldData, js_class: fieldClass }) @@ -100,7 +107,7 @@ export function visitVariant( const okClass = data.js_class._azleOk; return Result.Ok( - okField[1].accept(visitor, { + hch(okField[1]).accept(visitor, { js_data: okData, js_class: okClass }) @@ -111,7 +118,7 @@ export function visitVariant( const errData = data.js_data['Err']; const errClass = data.js_class._azleErr; return Result.Err( - errField[1].accept(visitor, { + hch(errField[1]).accept(visitor, { js_data: errData, js_class: errClass }) @@ -127,7 +134,7 @@ export function visitVariant( } return { ...acc, - [memberName]: memberIdl.accept(visitor, { + [memberName]: hch(memberIdl).accept(visitor, { js_class: fieldClass, js_data: fieldData }) @@ -146,7 +153,7 @@ export function visitRec( if (js_class._azleIsCanister) { js_class = js_class([]); } - return ty.accept(visitor, { + return hch(ty).accept(visitor, { ...data, js_class }); From 64c322c24c06561a62606b06f0c891491195b1c7 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 09:37:32 -0600 Subject: [PATCH 30/37] update rec visitor to pass the rest of the data --- examples/recursion/src/recursion/index.did | 70 +++++++++------------- src/lib_new/visitors/did_visitor.ts | 1 + 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index 1b3b308f39..cb764937a7 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,3 +1,5 @@ +type rec_397 = service {myQuery: (rec_397) -> (rec_397) query;}; +type rec_400 = service {myQuery: (rec_400) -> (rec_400) query;}; type rec_365 = func (rec_365) -> (rec_365) query; type rec_368 = func (rec_368) -> (rec_368) query; type rec_373 = func (rec_373) -> (rec_373) query; @@ -10,27 +12,11 @@ type rec_337 = record {myVar:variant {num:int8; varRec:rec_337}}; type rec_289 = record {myVecRecords:vec rec_289}; type rec_292 = record {myVecRecords:vec rec_292}; type rec_333 = record {myVecRecords:vec rec_333}; -type rec_385 = service { - myQuery: (rec_385) -> (rec_385) query; -}; -type rec_388 = service { - myQuery: (rec_388) -> (rec_388) query; -}; -type rec_397 = service { - myQuery: (rec_397) -> (rec_397) query; -}; -type rec_400 = service { - myQuery: (rec_400) -> (rec_400) query; -}; -type rec_393 = service { - myQuery: (rec_393) -> (rec_393) query; -}; -type rec_377 = service { - myQuery: (rec_377) -> (rec_377) query; -}; -type rec_380 = service { - myQuery: (rec_380) -> (rec_380) query; -}; +type rec_385 = service {myQuery: (rec_385) -> (rec_385) query;}; +type rec_388 = service {myQuery: (rec_388) -> (rec_388) query;}; +type rec_393 = service {myQuery: (rec_393) -> (rec_393) query;}; +type rec_377 = service {myQuery: (rec_377) -> (rec_377) query;}; +type rec_380 = service {myQuery: (rec_380) -> (rec_380) query;}; type rec_313 = record {opt rec_313; opt rec_313}; type rec_316 = record {opt rec_316; opt rec_316}; type rec_345 = record {opt rec_345; opt rec_345}; @@ -44,24 +30,24 @@ type rec_305 = variant {num:int8; recVariant:rec_305}; type rec_308 = variant {num:int8; recVariant:rec_308}; type rec_341 = variant {num:int8; recVariant:rec_341}; service: () -> { - testRecFunc: (rec_365) -> (rec_368) query; - testRecFuncReturn: () -> (rec_373) query; - testRecRecordWithOpt: (rec_281) -> (rec_284) query; - testRecRecordWithOptReturn: () -> (rec_329) query; - testRecRecordWithVariant: (rec_297) -> (rec_300) query; - testRecRecordWithVariantReturn: () -> (rec_337) query; - testRecRecordWithVec: (rec_289) -> (rec_292) query; - testRecRecordWithVecReturn: () -> (rec_333) query; - testRecService: (rec_385) -> (rec_388) query; - testRecServiceCall: (rec_397) -> (rec_400) ; - testRecServiceReturn: () -> (rec_393) query; - testRecServiceSimple: (rec_377) -> (rec_380) query; - testRecTupleWithOpt: (rec_313) -> (rec_316) query; - testRecTupleWithOptReturn: () -> (rec_345) query; - testRecTupleWithVariant: (rec_353) -> (rec_356) query; - testRecTupleWithVariantReturn: () -> (rec_361) query; - testRecTupleWithVec: (rec_321) -> (rec_324) query; - testRecTupleWithVecReturn: () -> (rec_349) query; - testRecVariant: (rec_305) -> (rec_308) query; - testRecVariantReturn: () -> (rec_341) query; -} \ No newline at end of file + testRecFunc: (rec_365) -> (rec_368) query; + testRecFuncReturn: () -> (rec_373) query; + testRecRecordWithOpt: (rec_281) -> (rec_284) query; + testRecRecordWithOptReturn: () -> (rec_329) query; + testRecRecordWithVariant: (rec_297) -> (rec_300) query; + testRecRecordWithVariantReturn: () -> (rec_337) query; + testRecRecordWithVec: (rec_289) -> (rec_292) query; + testRecRecordWithVecReturn: () -> (rec_333) query; + testRecService: (rec_385) -> (rec_388) query; + testRecServiceCall: (rec_397) -> (rec_400) ; + testRecServiceReturn: () -> (rec_393) query; + testRecServiceSimple: (rec_377) -> (rec_380) query; + testRecTupleWithOpt: (rec_313) -> (rec_316) query; + testRecTupleWithOptReturn: () -> (rec_345) query; + testRecTupleWithVariant: (rec_353) -> (rec_356) query; + testRecTupleWithVariantReturn: () -> (rec_361) query; + testRecTupleWithVec: (rec_321) -> (rec_324) query; + testRecTupleWithVecReturn: () -> (rec_349) query; + testRecVariant: (rec_305) -> (rec_308) query; + testRecVariantReturn: () -> (rec_341) query; +} diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index 519012cfb1..c51e8e2151 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -215,6 +215,7 @@ export class DidVisitor extends IDL.Visitor { const usedRecClasses = data.usedRecClasses; if (!usedRecClasses.includes(t)) { const candid = hch(ty).accept(this, { + ...data, usedRecClasses: [...usedRecClasses, t], isOnService: false, isFirstService: false From c09d6b8c8d6187d93631d4a0773b67aa5aeeeeb1 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 11:28:17 -0600 Subject: [PATCH 31/37] remove unsused type --- src/lib_functional/canister_methods/update.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_functional/canister_methods/update.ts b/src/lib_functional/canister_methods/update.ts index 303aac69e4..11340a057a 100644 --- a/src/lib_functional/canister_methods/update.ts +++ b/src/lib_functional/canister_methods/update.ts @@ -6,7 +6,7 @@ import { createParents, executeMethod } from '.'; -import { CandidType, RecursiveType, TypeMapping } from '../candid'; +import { CandidType, TypeMapping } from '../candid'; import { toParamIDLTypes, toReturnIDLType } from '../../lib_new/utils'; export function update< From 3aee75c371c4c3bae727899317b51982a0bb60ae Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 12:15:01 -0600 Subject: [PATCH 32/37] finish recursive test example --- examples/recursion/dfx.json | 3 +- examples/recursion/src/recursion/index.did | 4 +- examples/recursion/src/recursion/index.ts | 8 +- .../src/recursive_canister/index.did | 12 +-- examples/recursion/test/pretest.ts | 22 +++++- examples/recursion/test/tests.ts | 74 +++++++++++++++++-- 6 files changed, 102 insertions(+), 21 deletions(-) diff --git a/examples/recursion/dfx.json b/examples/recursion/dfx.json index 62f13159eb..05f3c8b1e0 100644 --- a/examples/recursion/dfx.json +++ b/examples/recursion/dfx.json @@ -10,7 +10,8 @@ "declarations": { "output": "test/dfx_generated/recursion", "node_compatibility": true - } + }, + "env": ["MY_CANISTER_PRINCIPAL"] }, "recursive_canister": { "type": "custom", diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index cb764937a7..adf313f9ee 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -1,5 +1,3 @@ -type rec_397 = service {myQuery: (rec_397) -> (rec_397) query;}; -type rec_400 = service {myQuery: (rec_400) -> (rec_400) query;}; type rec_365 = func (rec_365) -> (rec_365) query; type rec_368 = func (rec_368) -> (rec_368) query; type rec_373 = func (rec_373) -> (rec_373) query; @@ -14,6 +12,8 @@ type rec_292 = record {myVecRecords:vec rec_292}; type rec_333 = record {myVecRecords:vec rec_333}; type rec_385 = service {myQuery: (rec_385) -> (rec_385) query;}; type rec_388 = service {myQuery: (rec_388) -> (rec_388) query;}; +type rec_397 = service {myQuery: (rec_397) -> (rec_397) query;}; +type rec_400 = service {myQuery: (rec_400) -> (rec_400) query;}; type rec_393 = service {myQuery: (rec_393) -> (rec_393) query;}; type rec_377 = service {myQuery: (rec_377) -> (rec_377) query;}; type rec_380 = service {myQuery: (rec_380) -> (rec_380) query;}; diff --git a/examples/recursion/src/recursion/index.ts b/examples/recursion/src/recursion/index.ts index 221f39079d..4959221a93 100644 --- a/examples/recursion/src/recursion/index.ts +++ b/examples/recursion/src/recursion/index.ts @@ -117,9 +117,11 @@ export default Canister({ testRecService: query([MyFullCanister], MyFullCanister, (param) => param), testRecServiceReturn: query([], MyFullCanister, () => { return MyFullCanister( - // Principal.fromText(process.env.MY_CANISTER_PRINCIPAL) ?? - Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? - ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + Principal.fromText( + process.env.MY_CANISTER_PRINCIPAL ?? + // Principal.fromText('asrmz-lmaaa-aaaaa-qaaeq-cai') ?? + ic.trap('process.env.MY_CANISTER_PRINCIPAL is undefined') + ) ); }), testRecServiceCall: update( diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did index b2f5f7c53e..fdb2aad9a1 100644 --- a/examples/recursion/src/recursive_canister/index.did +++ b/examples/recursion/src/recursive_canister/index.did @@ -1,9 +1,5 @@ -type rec_20 = service { - myQuery: (rec_20) -> (rec_20) query; -}; -type rec_23 = service { - myQuery: (rec_23) -> (rec_23) query; -}; +type rec_20 = service {myQuery: (rec_20) -> (rec_20) query;}; +type rec_23 = service {myQuery: (rec_23) -> (rec_23) query;}; service: () -> { - myQuery: (rec_20) -> (rec_23) query; -} \ No newline at end of file + myQuery: (rec_20) -> (rec_23) query; +} diff --git a/examples/recursion/test/pretest.ts b/examples/recursion/test/pretest.ts index fd6c38f77a..5c1d628c8c 100644 --- a/examples/recursion/test/pretest.ts +++ b/examples/recursion/test/pretest.ts @@ -1,16 +1,34 @@ import { execSync } from 'child_process'; +import { getCanisterId } from 'azle/test'; async function pretest() { await new Promise((resolve) => setTimeout(resolve, 5000)); - execSync(`dfx canister uninstall-code recursion || true`, { + execSync(`dfx canister uninstall-code recursive_canister || true`, { stdio: 'inherit' }); - execSync(`dfx deploy recursion`, { + execSync(`dfx deploy recursive_canister`, { stdio: 'inherit' }); + execSync(`dfx generate recursive_canister`, { + stdio: 'inherit' + }); + + execSync(`dfx canister uninstall-code recursion || true`, { + stdio: 'inherit' + }); + + execSync( + `MY_CANISTER_PRINCIPAL=${getCanisterId( + 'recursive_canister' + )} dfx deploy recursion`, + { + stdio: 'inherit' + } + ); + execSync(`dfx generate recursion`, { stdio: 'inherit' }); diff --git a/examples/recursion/test/tests.ts b/examples/recursion/test/tests.ts index f6bc1e3fff..73eafbf247 100644 --- a/examples/recursion/test/tests.ts +++ b/examples/recursion/test/tests.ts @@ -1,12 +1,15 @@ -import { Test } from 'azle/test'; +import { Test, getCanisterId } from 'azle/test'; import { _SERVICE, - rec_10, - rec_8 + rec_313, + rec_321 } from './dfx_generated/recursion/recursion.did'; import { ActorSubclass } from '@dfinity/agent'; import { Principal } from '@dfinity/principal'; +import { execSync } from 'child_process'; +// TODO these tests should be rewritten to use @dfinity/agent once this issue is resolved: https://github.com/dfinity/agent-js/issues/702 +// TODO this issue also needs to be resolved: https://forum.dfinity.org/t/services-wont-deserialize-properly-if-functions-arent-in-alphabetical-order/20885 export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { return [ { @@ -179,7 +182,7 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { { name: 'recursive tuples with vec', test: async () => { - const input: rec_10 = [[[[], [[[], []]]]], []]; + const input: rec_321 = [[[[], [[[], []]]]], []]; const result = await recursion_canister.testRecTupleWithVec(input); @@ -211,7 +214,7 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { { name: 'recursive tuples with opt', test: async () => { - const input: rec_8 = [[[[], [[[], []]]]], []]; + const input: rec_313 = [[[[], [[[], []]]]], []]; const result = await recursion_canister.testRecTupleWithOpt(input); @@ -309,6 +312,67 @@ export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { result[1].varTuple[1].varTuple[1].num === 10 }; } + }, + { + name: 'test rec service simple', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceSimple '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecService '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service return', + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceReturn` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } + }, + { + name: 'test rec service call', + skip: true, // TODO waiting for azle.encode and azle.decode to be implemented + test: async () => { + const principalId = getCanisterId('recursive_canister'); + const result = execSync( + `dfx canister call recursion testRecServiceCall '(service "${principalId}")'` + ) + .toString() + .trim(); + + return { + Ok: result === `(service "${principalId}")` + }; + } } ]; } From 2ae79e11a8fc67899e0f59b87e68b38655e90950 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 12:27:13 -0600 Subject: [PATCH 33/37] pr fixes --- examples/canister/src/index.did | 10 +++++----- examples/canister/src/some_canister.did | 2 +- src/lib_new/visitors/did_visitor.ts | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/canister/src/index.did b/examples/canister/src/index.did index 4d7160845f..2a6e359468 100644 --- a/examples/canister/src/index.did +++ b/examples/canister/src/index.did @@ -1,7 +1,7 @@ service: () -> { - canisterCrossCanisterCall: (service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (text) ; - canisterList: (vec service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (vec service {query1: () -> (bool) query; update1: () -> (text) ;}) ; - canisterNestedReturnType: () -> (record {someCanister:service {query1: () -> (bool) query; update1: () -> (text) ;}}) ; - canisterParam: (service {query1: () -> (bool) query; update1: () -> (text) ;}) -> (service {query1: () -> (bool) query; update1: () -> (text) ;}) query; - canisterReturnType: () -> (service {query1: () -> (bool) query; update1: () -> (text) ;}) query; + canisterCrossCanisterCall: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (text); + canisterList: (vec service {query1: () -> (bool) query; update1: () -> (text);}) -> (vec service {query1: () -> (bool) query; update1: () -> (text);}); + canisterNestedReturnType: () -> (record {someCanister:service {query1: () -> (bool) query; update1: () -> (text);}}); + canisterParam: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (service {query1: () -> (bool) query; update1: () -> (text);}) query; + canisterReturnType: () -> (service {query1: () -> (bool) query; update1: () -> (text);}) query; } diff --git a/examples/canister/src/some_canister.did b/examples/canister/src/some_canister.did index 5352637a43..f61de65f9f 100644 --- a/examples/canister/src/some_canister.did +++ b/examples/canister/src/some_canister.did @@ -1,4 +1,4 @@ service: () -> { query1: () -> (bool) query; - update1: () -> (text) ; + update1: () -> (text); } diff --git a/src/lib_new/visitors/did_visitor.ts b/src/lib_new/visitors/did_visitor.ts index c51e8e2151..3207d3b59e 100644 --- a/src/lib_new/visitors/did_visitor.ts +++ b/src/lib_new/visitors/did_visitor.ts @@ -195,9 +195,8 @@ export class DidVisitor extends IDL.Visitor { const candidRets = extractCandid(retsTypes); const args = candidArgs[0].join(', '); const rets = candidRets[0].join(', '); - const annon = t.annotations.includes('update') - ? '' - : ' ' + t.annotations.join(' '); + const annon = + t.annotations.length === 0 ? '' : ' ' + t.annotations.join(' '); return [ `${data.isOnService ? '' : 'func '}(${args}) -> (${rets})${annon}`, { ...candidArgs[1], ...candidRets[1] } From 17f9ac8d3888af624abb8152c174c39d521b15b9 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 12:41:19 -0600 Subject: [PATCH 34/37] make composite queries recursive --- .../composite_queries/src/canister1/index.did | 14 ++++++------ .../composite_queries/src/canister1/index.ts | 22 +++++++++---------- .../composite_queries/src/canister2/index.did | 4 ++-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/examples/composite_queries/src/canister1/index.did b/examples/composite_queries/src/canister1/index.did index c62ac41a3b..c06801e6f2 100644 --- a/examples/composite_queries/src/canister1/index.did +++ b/examples/composite_queries/src/canister1/index.did @@ -1,12 +1,12 @@ service: () -> { - simpleCompositeQuery: () -> (text) query; - manualQuery: () -> (text) query; - totallyManualQuery: () -> (text) query; deepQuery: () -> (text) query; - updateQuery: () -> (text) query; - simpleQuery: () -> (text) query; - simpleUpdate: () -> (text); - incCounter: () -> (nat) query; incCanister1: () -> (nat) query; incCanister2: () -> (nat) query; + incCounter: () -> (nat) query; + manualQuery: () -> (text) query; + simpleCompositeQuery: () -> (text) query; + simpleQuery: () -> (text) query; + simpleUpdate: () -> (text); + totallyManualQuery: () -> (text) query; + updateQuery: () -> (text) query; } diff --git a/examples/composite_queries/src/canister1/index.ts b/examples/composite_queries/src/canister1/index.ts index 309cabb66c..a186c4994f 100644 --- a/examples/composite_queries/src/canister1/index.ts +++ b/examples/composite_queries/src/canister1/index.ts @@ -14,13 +14,7 @@ import Canister2 from '../canister2'; let canister2: typeof Canister2; let counter: nat = 0n; -const incCounter = query([], nat, async () => { - counter += 1n; - - return counter; -}); - -export default Canister({ +const CompQueryCanister = Canister({ init: init([], () => { canister2 = Canister2( Principal.fromText( @@ -63,17 +57,19 @@ export default Canister({ return await ic.call(canister2.deepQuery); }), // Composite query that modifies the state. Should revert after the call is done - incCounter, + incCounter: query([], nat, async () => { + counter += 1n; + + return counter; + }), // Composite query calling queries on the same canister incCanister1: query([], nat, async () => { // TODO This is not an ideal solution but will work for now - const self = Canister({ - incCounter - })(ic.id()); + const self: any = CompQueryCanister(ic.id()); counter += 1n; - const canister1AResult = await ic.call(self.incCounter); + const canister1AResult: any = await ic.call(self.incCounter); const canister1BResult = await ic.call(self.incCounter); return counter + canister1AResult + canister1BResult; @@ -88,3 +84,5 @@ export default Canister({ return counter + canister2AResult + canister2BResult; }) }); + +export default CompQueryCanister; diff --git a/examples/composite_queries/src/canister2/index.did b/examples/composite_queries/src/canister2/index.did index 779ccf764d..01f39353d7 100644 --- a/examples/composite_queries/src/canister2/index.did +++ b/examples/composite_queries/src/canister2/index.did @@ -1,7 +1,7 @@ service: () -> { + deepQuery: () -> (text) query; incCounter: () -> (nat) query; + manualQuery: () -> (text) query; simpleQuery: () -> (text) query; updateQuery: () -> (text); - manualQuery: () -> (text) query; - deepQuery: () -> (text) query; } From 8534ee24685806e4cd47a2615511edff6200a951 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 12:48:48 -0600 Subject: [PATCH 35/37] complex type pr fixes --- .../index.ts => candid_types.ts} | 7 --- examples/complex_types/src/index.ts | 8 +-- examples/complex_types/src/posts.ts | 51 ++++++++++--------- 3 files changed, 29 insertions(+), 37 deletions(-) rename examples/complex_types/src/{candid_types/index.ts => candid_types.ts} (99%) diff --git a/examples/complex_types/src/candid_types/index.ts b/examples/complex_types/src/candid_types.ts similarity index 99% rename from examples/complex_types/src/candid_types/index.ts rename to examples/complex_types/src/candid_types.ts index 0294f5880d..fe1f2d1469 100644 --- a/examples/complex_types/src/candid_types/index.ts +++ b/examples/complex_types/src/candid_types.ts @@ -19,24 +19,17 @@ export const User = Recursive(() => export const Post = Recursive(() => Record({ id: text, - author: User, - reactions: Vec(Reaction), - text: text, - thread: Thread }) ); export const Thread = Record({ id: text, - author: User, - posts: Vec(Post), - title: text }); diff --git a/examples/complex_types/src/index.ts b/examples/complex_types/src/index.ts index eb63d4e197..7a23d4cd26 100644 --- a/examples/complex_types/src/index.ts +++ b/examples/complex_types/src/index.ts @@ -6,13 +6,7 @@ import { createThread, getAllThreads } from './threads'; import { createUser, getAllUsers } from './users'; export default Canister({ - createPost: update( - [text, text, text, nat32], - Post, - (authorId, text, threadId, joinDepth) => { - return createPost(authorId, text, threadId, joinDepth); - } - ), + createPost, getAllPosts: query([nat32], Vec(Post), (joinDepth) => { return getAllPosts(joinDepth); diff --git a/examples/complex_types/src/posts.ts b/examples/complex_types/src/posts.ts index 1af1125a3c..850e82b764 100644 --- a/examples/complex_types/src/posts.ts +++ b/examples/complex_types/src/posts.ts @@ -1,36 +1,41 @@ -import { nat32, Vec } from 'azle'; +import { nat32, text, update, Vec } from 'azle'; import { Post } from './candid_types'; import { getReactionFromStateReaction } from './reactions'; import { state, StatePost, StateThread, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; import { getUserFromStateUser } from './users'; -export function createPost( - authorId: string, - text: string, - threadId: string, - joinDepth: nat32 -): typeof Post { - const id = Object.keys(state.posts).length.toString(); +export const createPost = update( + [text, text, text, nat32], + Post, + (authorId, text, threadId, joinDepth) => { + const id = Object.keys(state.posts).length.toString(); - const statePost: StatePost = { - id, - authorId, - reactionIds: [], - text, - threadId - }; - const updatedStateAuthor = getUpdatedStateAuthor(authorId, statePost.id); - const updatedStateThread = getUpdatedStateThread(threadId, statePost.id); + const statePost: StatePost = { + id, + authorId, + reactionIds: [], + text, + threadId + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + statePost.id + ); + const updatedStateThread = getUpdatedStateThread( + threadId, + statePost.id + ); - state.posts[id] = statePost; - state.users[authorId] = updatedStateAuthor; - state.threads[threadId] = updatedStateThread; + state.posts[id] = statePost; + state.users[authorId] = updatedStateAuthor; + state.threads[threadId] = updatedStateThread; - const post = getPostFromStatePost(statePost, joinDepth); + const post = getPostFromStatePost(statePost, joinDepth); - return post; -} + return post; + } +); export function getAllPosts(joinDepth: nat32): (typeof Post)[] { return Object.values(state.posts).map((statePost) => From 6f5cd4d3c102fc9f20179ca33f71b9c6859ae229 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 13:08:33 -0600 Subject: [PATCH 36/37] add init test for recursive canisters --- examples/recursion/src/recursion/index.did | 12 ++++++------ .../recursion/src/recursive_canister/index.did | 9 +++++---- .../recursion/src/recursive_canister/index.ts | 10 ++++++++-- examples/recursion/test/pretest.ts | 2 +- examples/recursion/test/test.ts | 17 +++++++++++++++-- examples/recursion/test/tests.ts | 17 +++++++++++++++++ 6 files changed, 52 insertions(+), 15 deletions(-) diff --git a/examples/recursion/src/recursion/index.did b/examples/recursion/src/recursion/index.did index adf313f9ee..0b3b6b0e80 100644 --- a/examples/recursion/src/recursion/index.did +++ b/examples/recursion/src/recursion/index.did @@ -10,11 +10,11 @@ type rec_337 = record {myVar:variant {num:int8; varRec:rec_337}}; type rec_289 = record {myVecRecords:vec rec_289}; type rec_292 = record {myVecRecords:vec rec_292}; type rec_333 = record {myVecRecords:vec rec_333}; -type rec_385 = service {myQuery: (rec_385) -> (rec_385) query;}; -type rec_388 = service {myQuery: (rec_388) -> (rec_388) query;}; -type rec_397 = service {myQuery: (rec_397) -> (rec_397) query;}; -type rec_400 = service {myQuery: (rec_400) -> (rec_400) query;}; -type rec_393 = service {myQuery: (rec_393) -> (rec_393) query;}; +type rec_385 = service {getMessage: () -> (text) query; myQuery: (rec_385) -> (rec_385) query;}; +type rec_388 = service {getMessage: () -> (text) query; myQuery: (rec_388) -> (rec_388) query;}; +type rec_397 = service {getMessage: () -> (text) query; myQuery: (rec_397) -> (rec_397) query;}; +type rec_400 = service {getMessage: () -> (text) query; myQuery: (rec_400) -> (rec_400) query;}; +type rec_393 = service {getMessage: () -> (text) query; myQuery: (rec_393) -> (rec_393) query;}; type rec_377 = service {myQuery: (rec_377) -> (rec_377) query;}; type rec_380 = service {myQuery: (rec_380) -> (rec_380) query;}; type rec_313 = record {opt rec_313; opt rec_313}; @@ -39,7 +39,7 @@ service: () -> { testRecRecordWithVec: (rec_289) -> (rec_292) query; testRecRecordWithVecReturn: () -> (rec_333) query; testRecService: (rec_385) -> (rec_388) query; - testRecServiceCall: (rec_397) -> (rec_400) ; + testRecServiceCall: (rec_397) -> (rec_400); testRecServiceReturn: () -> (rec_393) query; testRecServiceSimple: (rec_377) -> (rec_380) query; testRecTupleWithOpt: (rec_313) -> (rec_316) query; diff --git a/examples/recursion/src/recursive_canister/index.did b/examples/recursion/src/recursive_canister/index.did index fdb2aad9a1..c13cc9540d 100644 --- a/examples/recursion/src/recursive_canister/index.did +++ b/examples/recursion/src/recursive_canister/index.did @@ -1,5 +1,6 @@ -type rec_20 = service {myQuery: (rec_20) -> (rec_20) query;}; -type rec_23 = service {myQuery: (rec_23) -> (rec_23) query;}; -service: () -> { - myQuery: (rec_20) -> (rec_23) query; +type rec_18 = service {getMessage: () -> (text) query; myQuery: (rec_18) -> (rec_18) query;}; +type rec_21 = service {getMessage: () -> (text) query; myQuery: (rec_21) -> (rec_21) query;}; +service: (text) -> { + getMessage: () -> (text) query; + myQuery: (rec_18) -> (rec_21) query; } diff --git a/examples/recursion/src/recursive_canister/index.ts b/examples/recursion/src/recursive_canister/index.ts index 7ca4594c33..dc76437737 100644 --- a/examples/recursion/src/recursive_canister/index.ts +++ b/examples/recursion/src/recursive_canister/index.ts @@ -1,8 +1,14 @@ -import { query, Canister, Recursive } from 'azle'; +import { query, Canister, Recursive, text, init } from 'azle'; + +let myMessage = ''; const MyCanister = Recursive(() => Canister({ - myQuery: query([MyCanister], MyCanister, (param) => param) + init: init([text], (message) => { + myMessage = message; + }), + myQuery: query([MyCanister], MyCanister, (param) => param), + getMessage: query([], text, () => myMessage) }) ); diff --git a/examples/recursion/test/pretest.ts b/examples/recursion/test/pretest.ts index 5c1d628c8c..2f2023274f 100644 --- a/examples/recursion/test/pretest.ts +++ b/examples/recursion/test/pretest.ts @@ -8,7 +8,7 @@ async function pretest() { stdio: 'inherit' }); - execSync(`dfx deploy recursive_canister`, { + execSync(`dfx deploy recursive_canister --argument '("hello")'`, { stdio: 'inherit' }); diff --git a/examples/recursion/test/test.ts b/examples/recursion/test/test.ts index e3a18cf29f..34e97ee022 100644 --- a/examples/recursion/test/test.ts +++ b/examples/recursion/test/test.ts @@ -1,6 +1,7 @@ import { getCanisterId, runTests } from 'azle/test'; import { createActor } from './dfx_generated/recursion'; -import { getTests } from './tests'; +import { createActor as createRecursiveActor } from './dfx_generated/recursive_canister'; +import { getRecursiveCanisterTests, getTests } from './tests'; const recursionCanister = createActor(getCanisterId('recursion'), { agentOptions: { @@ -8,4 +9,16 @@ const recursionCanister = createActor(getCanisterId('recursion'), { } }); -runTests(getTests(recursionCanister)); +const recursiveCanister = createRecursiveActor( + getCanisterId('recursive_canister'), + { + agentOptions: { + host: 'http://127.0.0.1:8000' + } + } +); + +runTests([ + ...getTests(recursionCanister), + ...getRecursiveCanisterTests(recursiveCanister) +]); diff --git a/examples/recursion/test/tests.ts b/examples/recursion/test/tests.ts index 73eafbf247..f901177a10 100644 --- a/examples/recursion/test/tests.ts +++ b/examples/recursion/test/tests.ts @@ -4,12 +4,29 @@ import { rec_313, rec_321 } from './dfx_generated/recursion/recursion.did'; +import { _SERVICE as _REC_SERVICE } from './dfx_generated/recursive_canister/recursive_canister.did'; import { ActorSubclass } from '@dfinity/agent'; import { Principal } from '@dfinity/principal'; import { execSync } from 'child_process'; // TODO these tests should be rewritten to use @dfinity/agent once this issue is resolved: https://github.com/dfinity/agent-js/issues/702 // TODO this issue also needs to be resolved: https://forum.dfinity.org/t/services-wont-deserialize-properly-if-functions-arent-in-alphabetical-order/20885 +export function getRecursiveCanisterTests( + recursive_canister: ActorSubclass<_REC_SERVICE> +): Test[] { + return [ + { + name: 'test recursive canister init method', + test: async () => { + const result = await recursive_canister.getMessage(); + + return { + Ok: result === 'hello' + }; + } + } + ]; +} export function getTests(recursion_canister: ActorSubclass<_SERVICE>): Test[] { return [ { From ff9653c19391d06d8a9e55910d1d8b4782c628d3 Mon Sep 17 00:00:00 2001 From: Benjamin DeMann Date: Sat, 30 Sep 2023 13:20:38 -0600 Subject: [PATCH 37/37] clean up complex types pr fix --- examples/complex_types/src/index.did | 18 ++++----- examples/complex_types/src/index.ts | 46 ++++----------------- examples/complex_types/src/posts.ts | 6 +-- examples/complex_types/src/reactions.ts | 53 ++++++++++++------------- examples/complex_types/src/threads.ts | 45 +++++++++++---------- examples/complex_types/src/users.ts | 10 ++--- 6 files changed, 75 insertions(+), 103 deletions(-) diff --git a/examples/complex_types/src/index.did b/examples/complex_types/src/index.did index bee0f6b3f1..d75ebcf4b6 100644 --- a/examples/complex_types/src/index.did +++ b/examples/complex_types/src/index.did @@ -47,12 +47,12 @@ type rec_617 = record {id:text; text:text; author:rec_616; thread:record {id:tex type rec_618 = record {id:text; text:text; author:rec_616; thread:record {id:text; title:text; author:rec_616; posts:vec rec_618}; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; type rec_616 = record {id:text; username:text; threads:vec record {id:text; title:text; author:rec_616; posts:vec rec_619}; posts:vec rec_617; reactions:vec record {id:text; post:rec_618; author:rec_616; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}}; service: () -> { - createPost: (text, text, text, nat32) -> (rec_440) ; - createReaction: (text, text, variant {Fire; ThumbsDown; ThumbsUp}, nat32) -> (record {id:text; post:rec_484; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) ; - createThread: (text, text, nat32) -> (record {id:text; title:text; author:rec_544; posts:vec rec_548}) ; - createUser: (text, nat32) -> (rec_600) ; - getAllPosts: (nat32) -> (vec rec_456) query; - getAllReactions: (nat32) -> (vec record {id:text; post:rec_516; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) query; - getAllThreads: (nat32) -> (vec record {id:text; title:text; author:rec_576; posts:vec rec_580}) query; - getAllUsers: (nat32) -> (vec rec_616) query; -} \ No newline at end of file + createPost: (text, text, text, nat32) -> (rec_440); + createReaction: (text, text, variant {Fire; ThumbsDown; ThumbsUp}, nat32) -> (record {id:text; post:rec_484; author:rec_480; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}); + createThread: (text, text, nat32) -> (record {id:text; title:text; author:rec_544; posts:vec rec_548}); + createUser: (text, nat32) -> (rec_600); + getAllPosts: (nat32) -> (vec rec_456) query; + getAllReactions: (nat32) -> (vec record {id:text; post:rec_516; author:rec_512; reactionType:variant {Fire; ThumbsDown; ThumbsUp}}) query; + getAllThreads: (nat32) -> (vec record {id:text; title:text; author:rec_576; posts:vec rec_580}) query; + getAllUsers: (nat32) -> (vec rec_616) query; +} diff --git a/examples/complex_types/src/index.ts b/examples/complex_types/src/index.ts index 7a23d4cd26..e6fcf675f6 100644 --- a/examples/complex_types/src/index.ts +++ b/examples/complex_types/src/index.ts @@ -1,5 +1,4 @@ -import { nat32, query, Canister, text, update, Vec } from 'azle'; -import { Post, Reaction, ReactionType, Thread, User } from './candid_types'; +import { Canister } from 'azle'; import { createPost, getAllPosts } from './posts'; import { createReaction, getAllReactions } from './reactions'; import { createThread, getAllThreads } from './threads'; @@ -7,40 +6,11 @@ import { createUser, getAllUsers } from './users'; export default Canister({ createPost, - - getAllPosts: query([nat32], Vec(Post), (joinDepth) => { - return getAllPosts(joinDepth); - }), - - createReaction: update( - [text, text, ReactionType, nat32], - Reaction, - (authorId, postId, reactionType, joinDepth) => { - return createReaction(authorId, postId, reactionType, joinDepth); - } - ), - - getAllReactions: query([nat32], Vec(Reaction), (joinDepth) => { - return getAllReactions(joinDepth); - }), - - createThread: update( - [text, text, nat32], - Thread, - (title, authorId, joinDepth) => { - return createThread(title, authorId, joinDepth); - } - ), - - getAllThreads: query([nat32], Vec(Thread), (joinDepth) => { - return getAllThreads(joinDepth); - }), - - createUser: update([text, nat32], User, (username, joinDepth) => { - return createUser(username, joinDepth); - }), - - getAllUsers: query([nat32], Vec(User), (joinDepth) => { - return getAllUsers(joinDepth); - }) + getAllPosts, + createReaction, + getAllReactions, + createThread, + getAllThreads, + createUser, + getAllUsers }); diff --git a/examples/complex_types/src/posts.ts b/examples/complex_types/src/posts.ts index 850e82b764..1aae042d59 100644 --- a/examples/complex_types/src/posts.ts +++ b/examples/complex_types/src/posts.ts @@ -1,4 +1,4 @@ -import { nat32, text, update, Vec } from 'azle'; +import { nat32, query, text, update, Vec } from 'azle'; import { Post } from './candid_types'; import { getReactionFromStateReaction } from './reactions'; import { state, StatePost, StateThread, StateUser } from './state'; @@ -37,11 +37,11 @@ export const createPost = update( } ); -export function getAllPosts(joinDepth: nat32): (typeof Post)[] { +export const getAllPosts = query([nat32], Vec(Post), (joinDepth) => { return Object.values(state.posts).map((statePost) => getPostFromStatePost(statePost, joinDepth) ); -} +}); export function getPostFromStatePost( statePost: StatePost, diff --git a/examples/complex_types/src/reactions.ts b/examples/complex_types/src/reactions.ts index fb5aa95948..5820d501e1 100644 --- a/examples/complex_types/src/reactions.ts +++ b/examples/complex_types/src/reactions.ts @@ -1,43 +1,42 @@ -import { nat32, Vec } from 'azle'; +import { nat32, query, text, update, Vec } from 'azle'; import { Reaction, ReactionType } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StatePost, StateReaction, StateUser } from './state'; import { getUserFromStateUser } from './users'; -export function createReaction( - authorId: string, - postId: string, - reactionType: typeof ReactionType, - joinDepth: nat32 -): typeof Reaction { - const id = Object.keys(state.reactions).length.toString(); +export const createReaction = update( + [text, text, ReactionType, nat32], + Reaction, + (authorId, postId, reactionType, joinDepth) => { + const id = Object.keys(state.reactions).length.toString(); - const stateReaction: StateReaction = { - id, - authorId, - postId, - reactionType - }; - const updatedStateAuthor = getUpdatedStateAuthor( - authorId, - stateReaction.id - ); - const updatedStatePost = getUpdatedStatePost(postId, stateReaction.id); + const stateReaction: StateReaction = { + id, + authorId, + postId, + reactionType + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + stateReaction.id + ); + const updatedStatePost = getUpdatedStatePost(postId, stateReaction.id); - state.reactions[id] = stateReaction; - state.users[authorId] = updatedStateAuthor; - state.posts[postId] = updatedStatePost; + state.reactions[id] = stateReaction; + state.users[authorId] = updatedStateAuthor; + state.posts[postId] = updatedStatePost; - const reaction = getReactionFromStateReaction(stateReaction, joinDepth); + const reaction = getReactionFromStateReaction(stateReaction, joinDepth); - return reaction; -} + return reaction; + } +); -export function getAllReactions(joinDepth: nat32): (typeof Reaction)[] { +export const getAllReactions = query([nat32], Vec(Reaction), (joinDepth) => { return Object.values(state.reactions).map((stateReaction) => getReactionFromStateReaction(stateReaction, joinDepth) ); -} +}); export function getReactionFromStateReaction( stateReaction: StateReaction, diff --git a/examples/complex_types/src/threads.ts b/examples/complex_types/src/threads.ts index 6bea9fd903..e4a358bed5 100644 --- a/examples/complex_types/src/threads.ts +++ b/examples/complex_types/src/threads.ts @@ -1,37 +1,40 @@ -import { nat32, Vec } from 'azle'; +import { nat32, query, text, update, Vec } from 'azle'; import { Thread } from './candid_types'; import { getPostFromStatePost } from './posts'; import { state, StateThread, StateUser } from './state'; import { getUserFromStateUser } from './users'; -export function createThread( - title: string, - authorId: string, - joinDepth: nat32 -): typeof Thread { - const id = Object.keys(state.threads).length.toString(); +export const createThread = update( + [text, text, nat32], + Thread, + (title, authorId, joinDepth) => { + const id = Object.keys(state.threads).length.toString(); - const stateThread: StateThread = { - id, - authorId, - postIds: [], - title - }; - const updatedStateAuthor = getUpdatedStateAuthor(authorId, stateThread.id); + const stateThread: StateThread = { + id, + authorId, + postIds: [], + title + }; + const updatedStateAuthor = getUpdatedStateAuthor( + authorId, + stateThread.id + ); - state.threads[id] = stateThread; - state.users[authorId] = updatedStateAuthor; + state.threads[id] = stateThread; + state.users[authorId] = updatedStateAuthor; - const thread = getThreadFromStateThread(stateThread, joinDepth); + const thread = getThreadFromStateThread(stateThread, joinDepth); - return thread; -} + return thread; + } +); -export function getAllThreads(joinDepth: nat32): (typeof Thread)[] { +export const getAllThreads = query([nat32], Vec(Thread), (joinDepth) => { return Object.values(state.threads).map((stateThread) => getThreadFromStateThread(stateThread, joinDepth) ); -} +}); export function getThreadFromStateThread( stateThread: StateThread, diff --git a/examples/complex_types/src/users.ts b/examples/complex_types/src/users.ts index 9c98ed25f2..4b9096c9e3 100644 --- a/examples/complex_types/src/users.ts +++ b/examples/complex_types/src/users.ts @@ -1,11 +1,11 @@ -import { nat32, Vec } from 'azle'; +import { nat32, query, text, update, Vec } from 'azle'; import { User } from './candid_types'; import { getPostFromStatePost } from './posts'; import { getReactionFromStateReaction } from './reactions'; import { state, StateUser } from './state'; import { getThreadFromStateThread } from './threads'; -export function createUser(username: string, joinDepth: nat32): typeof User { +export const createUser = update([text, nat32], User, (username, joinDepth) => { const id = Object.keys(state.users).length.toString(); const stateUser: StateUser = { @@ -21,13 +21,13 @@ export function createUser(username: string, joinDepth: nat32): typeof User { const user = getUserFromStateUser(stateUser, joinDepth); return user; -} +}); -export function getAllUsers(joinDepth: nat32): (typeof User)[] { +export const getAllUsers = query([nat32], Vec(User), (joinDepth) => { return Object.values(state.users).map((stateUser) => getUserFromStateUser(stateUser, joinDepth) ); -} +}); export function getUserFromStateUser( stateUser: StateUser,