/// remote access to a mORMot server using SmartMobileStudio {{#uri}} // - retrieved from {{protocol}}://{{host}}/{{uri}} // at {{time}} using "{{templateName}}" template {{/uri}} {{^uri}} // - generated at {{time}} {{/uri}} unit {{fileName}}; { WARNING: This unit has been generated by a mORMot {{mORMotVersion}} server. Any manual modification of this file may be lost after regeneration. Synopse mORMot framework. Copyright (C) {{year}} Arnaud Bouchez Synopse Informatique - http://synopse.info This unit is released under a MPL/GPL/LGPL tri-license, and therefore may be freely included in any application. This unit would work on Smart Mobile Studio 2.1.1 and later. } interface uses SmartCL.System, System.Types, SynCrossPlatformSpecific, SynCrossPlatformREST; {{! recursive partials used to write records type definition}} {{writerec}}{{nestedIdentation}} end;{{/nestedRecord}}{{#nestedSimpleArray}}array of {{typePascal}};{{/nestedSimpleArray}}{{#nestedRecordArray}}array of {{>writerec}}{{nestedIdentation}} end;{{/nestedRecordArray}} {{/fields}}{{/writerec}} {{#withEnumerates}} type // define some enumeration types, used below {{#enumerates}} {{name}} = ({{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}); {{/enumerates}} {{/withEnumerates}} {{#withSets}} type // define some set types, used below {{#sets}} {{name}} = set of({{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}); {{/sets}} {{/withSets}} {{#withRecords}} type // define some record types, used as properties below {{#records}} {{name}} = {{>writerec}} end; {{/records}} {{/withRecords}} {{#withArrays}} type // define some dynamic array types, used as properties below {{#arrays}} {{name}} = array of {{typeSource}}; {{/arrays}} {{/withArrays}} type{{methodAsynch}} {{verb}} {{>methodSynch}} {{/methods}} end; {{/soa.services}} const /// the server port{{#uri}}, corresponding to {{protocol}}://{{host}}{{/uri}} SERVER_PORT = {{port}}; /// the server model root name{{#uri}}, corresponding to {{protocol}}://{{host}}/{{root}}{{/uri}} SERVER_ROOT = '{{root}}'; /// return the database Model corresponding to this server function GetModel(aRoot: string=SERVER_ROOT): TSQLModel; /// create a TSQLRestClientHTTP instance and connect to the server // - it will use by default port {{port}} over root '{{root}}'{{#host}}, corresponding // to {{protocol}}://{{host}}/{{root}}{{/host}} {{#authClass}} // - secure connection will be established via {{.}} // with the supplied credentials {{/authClass}} // - request will be asynchronous, and trigger onSuccess or onError event procedure GetClient(const aServerAddress{{#authClass}}, aUserName,aPassword{{/authClass}}: string; onSuccess, onError: TSQLRestEvent; aServerPort: integer=SERVER_PORT; aServerRoot: string=SERVER_ROOT; aHttps: boolean={{#https}}true{{/https}}{{^https}}false{{/https}}); {{#withHelpers}} // publish some low-level helpers for variant conversion // - used internally: you should not need those functions in your end-user code {{#enumerates}} function Variant2{{name}}(const _variant: variant): {{name}}; function {{name}}ToText(const value: {{name}}): string; {{/enumerates}} {{#records}} function Variant2{{name}}(const Value: variant): {{name}}; function {{name}}2Variant(const Value: {{name}}): variant; {{/records}} {{#arrays}} function Variant2{{name}}(const _variant: variant): {{name}}; function {{name}}2Variant(const _array: {{name}}): variant; {{/arrays}} {{/withHelpers}} implementation {{setrec}}{{/nestedRecord}}{{#fromVariant}} result.{{fullPropName}} := {{fromVariant}}(Value.{{fullPropName}}); {{/fromVariant}}{{#nestedSimpleArray}} if VariantType(Value.{{fullPropName}})=jvArray then for var i := 0 to integer(Value.{{fullPropName}}.length)-1 do result.{{fullPropName}}.Add({{typePascal}}(Value.{{fullPropName}}[i])); {{/nestedSimpleArray}}{{#nestedRecordArray}} if VariantType(Value.{{fullPropName}})=jvArray then begin var tmp: {{name}}; tmp.{{propName}}.SetLength(1); for var n := 0 to integer(Value.{{fullPropName}}.length)-1 do begin var source := Value.{{fullPropName}}[n]; var dest := tmp.{{propName}}[0]; {{#fields}} dest.{{propName}} := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}source.{{propName}}{{#fromVariant}}){{/fromVariant}}; {{/fields}} result.{{fullPropName}}.Add(dest); end; end; {{/nestedRecordArray}}{{/fields}}{{/setrec}} {{getrec}}{{/nestedRecord}}{{#toVariant}} result.{{fullPropName}} := {{toVariant}}(Value.{{fullPropName}}); {{/toVariant}}{{#nestedSimpleArray}} result.{{fullPropName}} := variant(Value.{{fullPropName}}); {{/nestedSimpleArray}}{{#nestedRecordArray}} result.{{fullPropName}} := TVariant.CreateArray; for var source in Value.{{fullPropName}} do begin var dest: variant := new JObject; {{#fields}} dest.{{propName}} := {{#toVariant}}{{toVariant}}({{/toVariant}}source.{{propName}}{{#toVariant}}){{/toVariant}}; {{/fields}} result.{{fullPropName}}.push(dest); end; {{/nestedRecordArray}}{{/fields}}{{/getrec}} {{#withEnumerates}} { Some helpers for enumerates types } {$HINTS OFF} // for begin asm return ... end; end below // those functions will use the existing generated string array constant // defined by the SMS compiler for each enumeration {{#enumerates}} function Variant2{{name}}(const _variant: variant): {{name}}; begin asm return @VariantToEnum(@_variant,@{{name}}); end; end; function {{name}}ToText(const value: {{name}}): string; begin asm return @{{name}}[@value]; end; end; {{/enumerates}} {$HINTS ON} {{/withEnumerates}} {{#withRecords}} { Some helpers for record types: due to potential obfuscation of generated JavaScript, we can't assume that the JSON used for transmission would match record fields naming } {{#records}} function Variant2{{name}}(const Value: variant): {{name}}; begin {{>setrec}} end; function {{name}}2Variant(const Value: {{name}}): variant; begin result := new JObject; {{>getrec}} end; {{/records}} {{/withRecords}} {{#withArrays}} { Some helpers for dynamic array types } {{#arrays}} function Variant2{{name}}(const _variant: variant): {{name}}; var tmp: {{typeSource}}; begin if VariantType(_variant)=jvArray then for var i := 0 to integer(_variant.Length)-1 do begin tmp := {{#fromVariant}}{{fromVariant}}{{/fromVariant}}(_variant[i]); result.Add(tmp); end; end; function {{name}}2Variant(const _array: {{name}}): variant; var i: integer; begin result := TVariant.CreateArray; for i := 0 to high(_array) do result.push({{#toVariant}}{{toVariant}}{{/toVariant}}(_array[i])); end; {{/arrays}} {{/withArrays}} {{#orm}} {{^isInMormotPas}} { {{className}} } class function {{className}}.ComputeRTTI: TRTTIPropInfos; begin result := TRTTIPropInfos.Create( [{{#fields}}'{{name}}'{{comma}}{{/fields}}], [{{#fields}}{{typekindname}}{{comma}}{{/fields}}]); end; procedure {{className}}.SetProperty(FieldIndex: integer; const Value: variant); begin case FieldIndex of 0: fID := Value; {{#fields}} {{index}}: f{{name}} := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}Value{{#fromVariant}}){{/fromVariant}}; {{/fields}} end; end; function {{className}}.GetProperty(FieldIndex: integer): variant; begin case FieldIndex of 0: result := fID; {{#fields}} {{index}}: result := {{#toVariant}}{{toVariant}}({{/toVariant}}f{{name}}{{#toVariant}}){{/toVariant}}; {{/fields}} end; end; {{/isInMormotPas}} {{/orm}} function GetModel(aRoot: string): TSQLModel; begin result := TSQLModel.Create([{{#orm}}{{className}}{{comma}}{{/orm}}],aRoot); end; procedure GetClient(const aServerAddress{{#authClass}}, aUserName,aPassword{{/authClass}}: string; onSuccess, onError: TSQLRestEvent; aServerPort: integer; aServerRoot: string; aHttps: boolean); begin var client := TSQLRestClientHTTP.Create(aServerAddress,aServerPort, GetModel(aServerRoot),true,aHttps); // aOwnModel=true client.Connect( lambda try if client.ServerTimeStamp=0 then begin if Assigned(onError) then onError(client); exit; end; {{#authClass}} if not client.SetUser({{.}},aUserName,aPassword) then begin if Assigned(onError) then onError(client); exit; end; {{/authClass}} if Assigned(onSuccess) then onSuccess(client); except if Assigned(onError) then onError(client); end; end, onError); end; {{#soa.services}} { TService{{interfaceURI}} } constructor TService{{interfaceURI}}.Create(aClient: TSQLRestClientURI); begin fServiceName := '{{interfaceURI}}'; fServiceURI := '{{uri}}'; fInstanceImplementation := sic{{instanceCreationName}}; fContractExpected := '{{contractExpected}}'; inherited Create(aClient); end; {{#methods}} procedure TService{{interfaceURI}}.{{>methodAsynch}} begin fClient.CallRemoteServiceAsynch(self,'{{methodName}}',{{ArgsOutputCount}}, [{{#args}}{{#dirInput}}{{#toVariant}}{{toVariant}}({{argName}}){{/toVariant}}{{^toVariant}}{{argName}}{{/toVariant}}{{commaInSingle}}{{/dirInput}}{{/args}}], lambda (res: array of Variant) onSuccess({{#args}}{{#dirOutput}}{{#fromVariant}}{{fromVariant}}({{/fromVariant}}res[{{indexOutResult}}{{#fromVariant}}){{/fromVariant}}{{#commaOutResult}},{{/commaOutResult}}{{/dirOutput}}{{/args}}); end, onError{{#resultIsServiceCustomAnswer}}, true{{/resultIsServiceCustomAnswer}}); end; {{verb}} TService{{interfaceURI}}.{{>methodSynch}} begin var res := fClient.CallRemoteServiceSynch(self,'{{methodName}}',{{ArgsOutputCount}}, [{{#args}}{{#dirInput}}{{#toVariant}}{{toVariant}}({{argName}}){{/toVariant}}{{^toVariant}}{{argName}}{{/toVariant}}{{commaInSingle}}{{/dirInput}}{{/args}}]{{#resultIsServiceCustomAnswer}},true{{/resultIsServiceCustomAnswer}}); {{#args}}{{#dirOutput}} {{argName}} := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}res[{{indexOutResult}}{{#fromVariant}}){{/fromVariant}}; {{/dirOutput}}{{/args}}end; {{/methods}} {{/soa.services}} end.