#1 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-11-26 15:56:47

I think you need to report a bug to @ab

#2 Re: mORMot 1 » PHP with sample 16 » 2018-11-24 09:42:07

I think you need to write a mORMot client in PHP if the server has authentication.

If there is no authentication then you can use something like the following code.
Note : I don't have PHP now to test this code.

<?php

list($rseOleDB, $rseODBC, $rseOracle, $rseSQlite3, $rseJet, $rseMSSQL) = [0,1,2,3,4,5];

function _callFunction($funcName, $params){
    $mServer = "http://www.your-server.com:888/root";

    $opts = array( 
        'http' => array( 
            'method'=>"POST", 'header'=>"Content-Type: application/json; charset=UTF-8",
            'content'=> json_encode($params)
        ) 
    );       

    $context = stream_context_create($opts); 

    $url = "$mServer/RemoteSQL/$funcName";  //Or $url = "$mServer/RemoteSQL.$funcName";
    return @file_get_contents($url , false, $context); 
}


function connect($engine, $aServerName, $aDatabaseName,  $aUserID, $aPassWord){
   return  _callFunction("Connect", [$engine, $aServerName, $aDatabaseName,  $aUserID, $aPassWord]);
}

function getTables(){
   return  _callFunction("GetTableNames", []);
}

function execute($aSQL, $aExpectResults, $aExpanded){
   return  _callFunction("Execute", [$aSQL, $aExpectResults, $aExpanded]);
}

?>

#3 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-11-21 04:38:40

Hi mohsenti

In the help of the function it says :
note that any inherited classes will be serialized as the parent class

   .....................................................

    // - note that any inherited classes will be serialized as the parent class
    // - this method is thread-safe, but should be called before any serialization
    class procedure RegisterCustomSerializerFieldNames(aClass: TClass;
      const aClassFields, aJsonFields: array of ShortString);

I think this mean that your last TJSONSerializer.RegisterCustomSerializerFieldNames only applied.

I noticed also that JsonString content in your example is not valid since you called RegisterCustomSerializerFieldNames

  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type_":"TYPE"},"Object2":{"Name":"C2","class_":"CLASS"}}';

//It must be

  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type":"TYPE"},"Object2":{"Name":"C2","class":"CLASS"}}';

I hope ab, can find some time to implement it.

#4 Re: mORMot 1 » Browser server folders from client on MVC application » 2018-11-05 01:51:11

You can't browse the server but you can emulate it. Get the directories list and send them to the browser, then the browser display them as a tree for the user to select a folder.

To get the directories tree in Windows you can use something like this :

Procedure GetDirTree(SearchDir:String; RList: TStrings; SubDir:Boolean = True; Lvl:Integer= 0 );
var
  Path, Tmp :String ;
  SearchRec: TSearchRec;
begin
  Path := CheckPathEnd(SearchDir);
  if FindFirst(Path + '*', faAnyFile, SearchRec)= 0 then begin
    Tmp := StringOfChar(#9, Lvl);
    repeat
      if ( (SearchRec.Attr and faDirectory)= faDirectory ) and (SearchRec.Name[1] <> '.') then begin
        RList.Add(Tmp + SearchRec.Name);
        if SubDir then GetDirTree(Path + SearchRec.Name, RList, True, Lvl+1);
      end;
    until (FindNext(SearchRec) <> 0);
    FindClose(SearchRec.FindHandle);
  end;
end;

#5 Re: mORMot 1 » Translate service to Javascript » 2018-10-20 04:21:28

Hi ab,
I have abandoned using the Mustache template. I used TSQLRestServerDB.Services to get the output I want.
I uploaded a sample at gulf-soft.com/e/files/Mormot_Sample.zip
In this sample I included my thought about making it easier for JavaScript programmer for consuming my services. Beside other things like simple Http server and using MySql.

Now if I have Interface like this:

  IClientRepository = interface(IBaseFactory)
    ['{31D143DB-9EED-4C00-940B-52C9BDB515D1}'] 
    function GetClient(Id : TId; out aClient: TSQLClient) : Cardinal;
    function SaveClient(var aClient: TSQLClient) : Cardinal	;
..............................
  end;

In JavaScript I will use some code like this:

  var clientRepository = new ClientRepository(_mc);
  var r = clientRepository.GetClient(Id);
  if(r.XHR.status == 200){
	workClient = r.responce.result[0];
	displayClent(workClient);
  }
  else
     alert(r.XHR.responseText);  

I hope this sample helps others and I get some comments to improve my knowledge in mORMot.

#6 Re: mORMot 1 » Translate service to Javascript » 2018-10-18 16:37:16

Hi ab,

ab wrote:

For the output/results parameters in javascript, I guess the most obvious could be to return an object with the output fields: {Items:[...],Result:1234}

My last question was about the output of Mustache template not javascript.
I don't want the Delphi method parameters of kind output to be appear in Mustache template output.

For example if I have the following interface:

  IAccountsChart = interface(IBaseFactory)
    ['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
    function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;
  end;

And I use the following template fragment for output method's name and parameter

{{<method}}this.{{methodName}}=function({{#args}}{{^dirResult}}{{argName}}{{#commaArg}}, {{/commaArg}}{{/dirResult}}{{/args}}){
      .......................................
    }{{/method}}

Mustache template output is :

  this.GetChartBranchData = function(Items, ItemId){
   .......................................
  }

But I want the template to output:

  this.GetChartBranchData = function(ItemId){
   .......................................
  }

Is that possible ?

#7 Re: mORMot 1 » Translate service to Javascript » 2018-10-17 02:04:54

Hi ab
I am new to mORMot.

ab wrote:

I would tend to use a mORMot-based service for this, with an in-memory cache of the js content.
Just re-use the content of procedure WrapperMethod() for your own method.

I didn't know what do you mean by "in-memory cache" and how to do that in mORMot, but I get that you advice me to save the content and reuse it. So I saved the js content to a file "Service.js". I did this  at server start so I can get the file later when a client need it at anytime. I used something like this:

  JsName := ExtractFileName(aJsFileName);
  Content:= WrapperFromModel(aServer, StringFromFile(aMustacheTemplate), JsName , 888);
  FileFromString(Content, aJsFileName);
ab wrote:

If you call the method js(Ctxt), then you will be able to parse what is after the root/js/.... method name from the Ctxt.URIAfterRoot value.

I'm using something like sample 09 - HttpApi web server to access the file from Javascript like this:

<script src="http://localhost:888/root/js/Services.js"></script>

This is enough for my learning purpose right now, but it is still advisable to learn from you and other mORMot experts. I want to share a full working sample (Server, Delphi client, web client and MySql database). I hope this may save some time for other newbie like me. I know the rules No long code in the forum. Can I upload it to my website and put the download link here?

There is another thing I need to do and I need your help to point me to the right direction as usual. smile

Delphi :
  function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;

Output Javascript :
  function GetChartBranchData(Items, ItemId)

I want to remove the out parameter(s) Items in this case. I don't want to confuse the Javascript programmer.
I want it to be like this:

Delphi :
  function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;

Output Javascript:
  function GetChartBranchData(ItemId)

#8 Re: mORMot 1 » Translate service to Javascript » 2018-10-16 12:43:48

Thanks ab
It works now after using

{{#commaArg}}, {{/commaArg}}

My template file name is "Js.pas.mustache" and I can call it from Javascript like this:

  <script src='http://localhost:888/root/wrapper/Js/mORMotClient.pas.txt'></script>

But I want to call it like this

  <script src='http://localhost:888/root/js/mORMotClient_Services.js'></script>
Or
  <script src='http://localhost:888/root/js/Services.js'></script>

Can you please point me to a solution to change
wrapper/Js/mORMotClient.pas.txt
to
js/mORMotClient_Services.js
?

#9 Re: mORMot 1 » Translate service to Javascript » 2018-10-16 09:55:48

Thanks ab for your quick response and pointing me to Mustache template.
I used a Mustache template and I got some results very close to what I need.
My problem now is I want a comma (,) not semicolon (;) in function parameters like the following

function GetChartBranchData(  Items;    ItemId    );

//I wanted it to be
//function GetChartBranchData(  Items,    ItemId    );

Can I use something else  instead of {{commaArg}} to produce a comma (,) not semicolon (;)?

This is the  template :

{{<method}}function {{methodName}}({{#args}} {{^dirResult}} {{argName}}{{commaArg}}{{/dirResult}} {{/args}} );{{/method}}
{{<member}}this.on{{methodName}} = null;{{/member}}
  {{#orm}}
  {{^isInMormotPas}}
  {{/isInMormotPas}}
  {{/orm}}
  {{#soa.services}}
  /* Definition of {{interfaceURI}} Object */
  // ------------------------------------
  function {{interfaceURI}}(mORMotClient){
    this.initialized=false;
    this.mORMotClient=mORMotClient;  
{{#methods}}
    {{>member}}
{{/methods}}

    var doCall = function(fnName, fnParam, callBack){
      funcName  = '{{interfaceURI}}.' + fnName;
      funcParam = '[' + ((! fnParam) ? '' : JSON.stringify(fnParam)) + ']';
      return mORMotClient.callFunc(funcName, funcParam, callBack, this);
    }

    this.Initialize = function(){
      doCall('_contract_', null, this.onInitialize);
    }

    this.onInitialize = function(req){
      var data = req.responce;
      if(data.error.errorNo == 0)
	req.owner.initialized = true;
    }
	
{{#methods}}
    {{>method}}
{{/methods}}
 }

  {{/soa.services}}

The result of this template is

  /* Definition of AccountsChart Object */
  // ------------------------------------
  function AccountsChart(mORMotClient){
    this.initialized=false;
    this.mORMotClient=mORMotClient;  
    this.onExportJScript=null;
    this.onFillDefaultChartData=null;
    this.onGetChartData=null;
    this.onGetChartBranchData=null;
    this.onInsertChartItem=null;
    this.onAddChartItem=null;
    this.onDelChartItem=null;
    this.onMoveChartItem=null;
    this.onUpdateChartItem=null;
    this.onGetChartItem=null;
    this.onChangeChartItemKind=null;

    var doCall = function(fnName, fnParam, callBack){
      funcName  = 'AccountsChart.' + fnName;
      var fnParams = [];
      for(var i=0; i < fnParam.length; i++) fnParams[i] = fnParam[i];
      return mORMotClient.callFunc(funcName, JSON.stringify(fnParams), callBack, this);
    }

    this.Initialize = function(){
      doCall('_contract_', null, this.onInitialize);
    }

    this.onInitialize = function(req){
      var data = req.responce;
      if(data.error.errorNo == 0)
	req.owner.initialized = true;
    }
	
    this.ExportJScript= function (   ){
      return doCall('ExportJScript', arguments, this.onExportJScript);
    };
    this.FillDefaultChartData= function (  Items;    ChartType    ){
      return doCall('FillDefaultChartData', arguments, this.onFillDefaultChartData);
    };
    this.GetChartData= function (  Items    ){
      return doCall('GetChartData', arguments, this.onGetChartData);
    };
    this.GetChartBranchData= function (  Items;    ItemId    ){
      return doCall('GetChartBranchData', arguments, this.onGetChartBranchData);
    };
    this.InsertChartItem= function (  Items;    ParentId;    Index    ){
      return doCall('InsertChartItem', arguments, this.onInsertChartItem);
    };
    this.AddChartItem= function (  Items;    ParentId    ){
      return doCall('AddChartItem', arguments, this.onAddChartItem);
    };
    this.DelChartItem= function (  Items;    ItemId    ){
      return doCall('DelChartItem', arguments, this.onDelChartItem);
    };
    this.MoveChartItem= function (  Items;    ItemId;    ParentId;    Index    ){
      return doCall('MoveChartItem', arguments, this.onMoveChartItem);
    };
    this.UpdateChartItem= function (  Item    ){
      return doCall('UpdateChartItem', arguments, this.onUpdateChartItem);
    };
    this.GetChartItem= function (  Item;    ItemId    ){
      return doCall('GetChartItem', arguments, this.onGetChartItem);
    };
    this.ChangeChartItemKind= function (  ItemId;    ItemKind    ){
      return doCall('ChangeChartItemKind', arguments, this.onChangeChartItemKind);
    };
 }

#10 Re: mORMot 1 » How to batch update with conditions? » 2018-10-15 12:52:31

Hi edwinsn,
I'm new to SQLite, but I know that you can't update any record inside the transaction.

But still that another user can save his modified version of record after the current user end his transaction.

#11 mORMot 1 » Translate service to Javascript » 2018-10-15 12:36:19

Ehab
Replies: 9

I reuse some Javascript code from Javascript authentication . Thanks for Ab, esmondb and RangerX.
I added more functions to mORMotClient in order to consume Interface based services. I will share it when done. But I still have one point and I need some help.
For example if I have an interface like this

  IAccountsChart = interface(IBaseFactory)
    ['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
    function GetChartData(out Items: TAccChartItems ): Integer;
    function InsertChartItem(out Items: TAccChartItems; ParentId: TId; Index : Integer): Integer;
    function DelChartItem(out Items: TAccChartItems; ItemId: TId): Integer;
    function MoveChartItem(out Items: TAccChartItems; ItemId, ParentId : TId; Index : Integer=-1): Integer;
    function UpdateChartItem(Item: TAccChartItemData): Integer;
  end;

I want to produce the following Javascript code for this interface so I can reflect new added functions to Javascript.

function AccountsChart(mORMotClient){
  this.onGetChartData= null;
  this.onInsertChartItem= null;
  this.onDelChartItem= null;
  this.onMoveChartItem= null;
  this.onUpdateChartItem= null;

  ........................
  
  this.GetChartData = function(){
    return doCall('GetChartData', null, this.onGetChartData);
  }
  this.InsertChartItem = function(Parent, Index){
    return doCall('InsertChartItem', Parent, Index, this.onInsertChartItem);
  }
  this.DelChartItem = function(ItemId){
    return doCall('DelChartItem', ItemId, this.onDelChartItem);
  }
  this.MoveChartItem = function(ItemId,Parent, Index){
    return doCall('MoveChartItem', ItemId,Parent, Index, this.onMoveChartItem);
  }
  this.UpdateChartItem = function(Item){
    return doCall('UpdateChartItem', Item, this.onUpdateChartItem);
  }
}

can I generate that Javascript at my mORMot server?
I want to call it directly from the browser like that :

<script src="http://localhost:888/root/GetJScript/AccountsChart"></script>
<script>
......................
  var accountsChart=New AccountsChart(mORMotClient);
  var chartData = accountsChart.GetChartData();
......................
</script>

#12 Re: mORMot 1 » Service inside dll » 2018-05-29 02:06:42

Thanks again ab not only for your response but also for sharing this great project.

My conclusion is to use any dll as service in mORMot is to make a unit contains interfaces that map interfaces inside dll. So no deal with RTTI inside dll.
Even if dll dose not have interfaces and only export functions I still have to make interfaces to map functions inside dll. So I can use the dll as it is.

#13 Re: mORMot 1 » Service inside dll » 2018-05-28 09:39:26

ab wrote:

And putting such logic within a dll sounds like a weird architecture choice to me.

This is an old project divided into some modules each of them in dll and I want to reuse them with minimum effort.

#14 Re: mORMot 1 » Service inside dll » 2018-05-28 09:13:32

Thanks ab for your quick response. I tried it but it failed, I think due to RTTI may be.

I introduced a mapping unit to load the dll and call the function inside it

if my dll contains the following interface

IdllItnf = interface()
  procedure DllProcA();
  procedure DllProcB();
end;  

then my server unit will contains the following code

IServiceItnf = interface(IInvokable)
['{CF3A7E2C-8189-43F7-AE34-35920D743ED3}']
  procedure SrvcProcA();
  procedure SrvcProcB();
end;  

TMyService = class(TInterfacedObject, IServiceItnf)
private
  FDllIntf : IdllItnf;
public
  procedure SrvcProcA();
  procedure SrvcProcB();
end;  
...............

procedure TMyService.SrvcProcA();
begin
  FDllIntf.DllProcA();
end;

Now I will use the introduced classes and interfaces as regular

#15 mORMot 1 » Service inside dll » 2018-05-28 00:37:48

Ehab
Replies: 6

Hi all,
I'm new-be to mORMot. My Question is it possible to have a service inside dll ?
My code in server will be something like :

var
  sc : IMyContainer;
  loder : IBluginLoader;
begin
  ......................
      aServer := TSQLRestServerDB.Create(aModel,ChangeFileExt(paramstr(0),'.db'),true);
//      aServer.ServiceDefine(TClientFactory,[IClientFactory],sicShared);

      loder := TBluginLoader.Create('MyDll.dll', 'CreateModuleObject'); //Load dll
      sc := IMyContainer(loder.GetBluginInterface());  // Run function "CreateModuleObject" and get result
      sc.RegisterFactory(aServer);   
 .......................
end;

My code in dll will be something like :

{ TMyContainer }

function TMyContainer.RegisterFactory(const aServer: TSQLRestServerDB): boolean;
begin
  aServer.ServiceDefine(TClientFactory,[IClientFactory],sicShared);
end;

initialization
  TInterfaceFactory.RegisterInterfaces([TypeInfo(IClientFactory)]);

thanks

Board footer

Powered by FluxBB