#101 Re: mORMot 1 » Generates Cross-Platform mORMot Clients » 2014-08-18 21:09:42

probably the series of /../../../ ..

who knows where they take you, if you change the base path

now I fix with a root path

#102 Re: mORMot 1 » Generates Cross-Platform mORMot Clients » 2014-08-18 19:36:34

hello AB.

I am trying to make changes to the project 14 to generate the client for android.

unit Project14Interface;

interface

type
  TTagList = packed record
    Base: widestring;
    L: array of packed record
     name: WideString;
     age: integer;
    end;
  end;


  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FF}']
    function Add(n1,n2: integer): integer;
    function Sub(n1b,n2b: integer): integer;
    procedure list(tag:string;var tagList:TTaglist);
  end;

const
  ROOT_NAME = 'root';
  PORT_NAME = '888';
  APPLICATION_NAME = 'RestService';

implementation

end.
program Project14ServerHttp;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes,
  SynCommons,
  mORMot,
  mORMotHttpServer,
  mORMotWrappers,
  Project14Interface in 'Project14Interface.pas';

type

  TServiceCalculator = class(TInterfacedObject, ICalculator)
  public
    function Add(n1,n2: integer): integer;
    function Sub(n1b,n2b: integer): integer;
    procedure list(tag:string;var tagList:TTaglist);
  end;

function TServiceCalculator.Add(n1, n2: integer): integer;
begin
  result := n1+n2;
end;

function TServiceCalculator.Sub(n1b, n2b: integer): integer;
begin
  result := n1b-n2b;
end;

procedure TServiceCalculator.list(tag:string;var tagList:TTaglist);
begin
  //
end;

var
  aModel: TSQLModel;
  aServer: TSQLRestServer;
  aHTTPServer: TSQLHttpServer;
begin
  // define the log level
  with TSQLLog.Family do begin
    Level := LOG_VERBOSE;
    EchoToConsole := LOG_VERBOSE; // log all events to the console
  end;
  // create a Data Model
  aModel := TSQLModel.Create([],ROOT_NAME);
  try
    // initialize a TObjectList-based database engine
    aServer := TSQLRestServerFullMemory.Create(aModel,'test.json',false,true);
    try
      // add the http://localhost:888/root/wrapper code generation web page
      AddToServerWrapperMethod(aServer,
        ['..\..\..\CrossPlatform\templates','..\..\..\..\CrossPlatform\templates']);


      // register our ICalculator service on the server side
      aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared);
      // launch the HTTP server
      aHTTPServer := TSQLHttpServer.Create(PORT_NAME,[aServer],'+',useHttpApiRegisteringURI);
      try
        aHTTPServer.AccessControlAllowOrigin := '*'; // for AJAX requests to work
        writeln(#10'Background server is running.'#10);
        writeln('Press [Enter] to close the server.'#10);
        readln;
      finally
        aHTTPServer.Free;
      end;
    finally
      aServer.Free;
    end;
  finally
    aModel.Free;
  end;
end.

but I get this error:

20140818 21284808 call      TSQLRestServerFullMemory(0035C020) Wrapper
20140818 21284808 srvr      GET root/wrapper ERROR=400 (Please copy some .mustache files in the expected folder (e.g. c:\xe.local\comp\CrossPlatform\templates))


in that folder obviously there are 3 files mustache


what's wrong ?

#103 Re: mORMot 1 » Generates Cross-Platform mORMot Clients » 2014-08-12 12:31:40

xe6 works ok

it's old xe2 update 4 hotfix 1 with bugs

#104 Re: mORMot 1 » Generates Cross-Platform mORMot Clients » 2014-08-11 23:32:38

I find solution....

I HATE delphi unicode!

from mormot.pas:

{$ifndef NOVARIANTS}
function TInterfaceFactory.ContextFromMethods(aRegisteredTypes: TRawUTF8List): variant;
const VERB_DELPHI: array[boolean] of string[9] = ('procedure','function');
      NULL_OR_COMMA: array[boolean] of RawUTF8 = ('null','","');
var methods,arguments: TDocVariantData;
    m,a,r: integer;
    arg: variant;
begin
  methods.Init(JSON_OPTIONS[true]);
  for m := 0 to fMethodsCount-1 do
  with fMethods[m] do begin
    r := 0;
    arguments.Init(JSON_OPTIONS[true]);
    for a := 1 to high(args) do begin // ignore self as a=0
      arg := args[a].ContextFromArguments(aRegisteredTypes);
      if (args[a].ValueDirection in [smdConst,smdVar]) and (a<ArgsInLast) then begin
        arg.commaIn := '; ';
        arg.commaInSingle := ',';   // <---------------------------------------------------------------------------------------
      end;
      if (args[a].ValueDirection in [smdVar,smdOut]) and (a<ArgsOutNotResultLast) then
        arg.commaOut := '; ';
      if args[a].ValueDirection in [smdVar,smdOut,smdResult] then begin
        arg.indexOutResult := UInt32ToUtf8(r)+']';
        inc(r);
        if a<ArgsOutLast then
          arg.commaOutResult := '; ';
      end;
      arguments.AddItem(arg);
    end;
    methods.AddItem(_ObjFast(['methodName',URI,'verb',VERB_DELPHI[ArgsResultIndex>=0],
      'args',variant(arguments),'argsOutputCount',r]));
    arguments.Clear;
  end;
  result := variant(methods);
end;
{$endif}



arg.commaInSingle is Variant and ',' is a char.

The solution is to force the type:         arg.commaInSingle := string(',');

automatic typecasting is EVIL

#105 Re: mORMot 1 » Generates Cross-Platform mORMot Clients » 2014-08-11 22:04:56

HI, I just test your big works.

but, using XE6, and following your instructions I tried to modify the sample 14..

Everything works perfectly, but there seems to be a small error output:

mormotclient.pas:

function TServiceCalculator.Add(const n1: integer; const n2: integer): integer;
var res: TVariantDynArray;
begin
  fClient.CallRemoteService(self,'Add',1, // raise EServiceException on error
    [n144n2],res); <------------------------- 44 ?   [n1,n2] I think 
  Result := res[0];
end;

44 is ord(',')

#106 Re: mORMot 1 » XE4 and FireMonkey » 2014-08-08 09:07:04

I found a conversion problem in SynCrossPlatformREST using FireMonkey on android.

I manually entered a very large ID 2147483647 + 1 ($ 7FFFFFFF + 1)

and I noticed that TSQLRecord.Fid as integer can not convert it.

I modified the code using int64 and the problem is gone.

  TSQLRecord = class(TPersistent)
  protected
    fID: int64;
    fInternalState: cardinal;

    fFill: TSQLTableJSON;
    {$ifdef ISSMS}
    class function GetRTTI: TRTTIPropInfos;
    /// you should override these methods
    class function ComputeRTTI: TRTTIPropInfos; virtual;
    procedure SetProperty(FieldIndex: integer; const Value: variant); virtual;
    function GetProperty(FieldIndex: integer): variant; virtual;
    {$endif}
  public
    /// this constructor initializes the record
    constructor Create; overload; virtual;
    /// this constructor loads a record from a REST instance from its ID
    constructor Create(aClient: TSQLRest; aID: integer;
      ForUpdate: boolean=false); overload;
    /// this constructor loads a record from a REST instance
    // - you can bind parameters by using ? in the SQLWhere clause
    // - FieldNames='' retrieve simple fields, '*' all fields, or as specified
    constructor Create(aClient: TSQLRest; const FieldNames, SQLWhere: string;
      const BoundsSQLWhere: array of const); overload;
    /// this constructor ask the server for a list of matching records
    // - you can bind parameters by using ? in the SQLWhere clause
    // - FieldNames='' retrieve simple fields, '*' all fields, or as specified
    // - then you can also loop through all rows with
    // ! while Rec.FillOne do
    // !   dosomethingwith(Rec);
    constructor CreateAndFillPrepare(aClient: TSQLRest; const FieldNames,
      SQLWhere: string; const BoundsSQLWhere: array of const);
    /// finalize the record memory
    destructor Destroy; override;
    /// fill the specified record from the supplied JSON
    function FromJSON(const aJSON: string): boolean;
    {$ifdef ISSMS}
    /// fill the specified record from Names/Values pairs
    function FromNamesValues(const Names: TStrArray; const Values: TVariantDynArray;
      ValuesStartIndex: integer): boolean;
    {$endif}
    /// fill all published properties of this object with the next available
    // row of data, as returned by CreateAndFillPrepare() constructor
    function FillOne: boolean;
    /// go to the first data row, as returned by CreateAndFillPrepare(),
    // then fill all published properties of this object
    // - you can use it e.g. as:
    // ! while Rec.FillOne do
    // !   dosomethingwith(Rec);
    // ! if Rec.FillRewind then
    // ! repeat
    // !   dosomeotherthingwith(Rec);
    // ! until not Rec.FillOne;
    function FillRewind: boolean;
    /// get the object properties as JSON
    // - FieldNames='' to retrieve simple fields, '*' all fields, or as specified
    function ToJSON(aModel: TSQLModel; aFieldNames: string=''): string;
    /// return the class type of this TSQLRecord
    function RecordClass: TSQLRecordClass;
      {$ifdef HASINLINE}inline;{$endif}
    /// contains the TSQLTableJSON instance after CreateAndFillPrepare()
    property FillTable: TSQLTableJSON read fFill;
    /// internal state counter of the mORMot server at last access time
    // - can be used to check if retrieved data may be out of date
    property InternalState: cardinal read fInternalState;
  published
    /// stores the record's primary key
    property ID: int64 read fID write fID;
  end;

What do you think of this correction?

#107 Re: mORMot 1 » XE4 and FireMonkey » 2014-08-07 23:04:13

Hi AB.

what is the right way to call a service-based interface as in example 14 from android application?

In crossplatform missing TSQLClientHTTP then:
  Client.ServiceRegister ([TypeInfo (ICalculator)], sicShared);

can not be translated.

You must use CallBackGet? but how?

Thank you

#108 Re: mORMot 1 » XE4 and FireMonkey » 2014-06-19 07:33:09

Thanks, but how to begin?

You can add in example 28, a version that uses the crossplatform, for the client?

#109 Re: mORMot 1 » XE4 and FireMonkey » 2014-06-18 21:40:32

Hello, I'm intruding ...

after reading the disappointment strategies embarcadero with strings.

I was wondering what was the state of development of FireMonkey / android / ios.

thanks

#110 Re: mORMot 1 » [mongodb] FindONe clarification » 2014-05-22 13:35:00

after formatUTF8:

'{Name:"{""$regex"": ""test.*"", $options: ""i""}"}'

#111 Re: mORMot 1 » [mongodb] FindONe clarification » 2014-05-22 13:30:37

Update. This is the string that blocks the parser:

doc:=Coll.FindDoc('{Name:?}',['{"$regex": "test.*", $options: "i"}']);

Your first

#112 Re: mORMot 1 » [mongodb] FindONe clarification » 2014-05-22 13:13:13

You are absolutely right.

But I'm a little concerned by the queries dynamically created with parts supplied by the user.

there is some function of input validation in this fantastic library?

#113 Re: mORMot 1 » [mongodb] FindONe clarification » 2014-05-22 07:52:05

    doc:=Coll.FindDoc('{Name:%}',['"$regex": "test.*", $options: "i"']); 


function TBSONWriter.BSONWriteDocFromJSON(JSON: PUTF8Char; aEndOfObject: PUTF8Char;
  out Kind: TBSONElementType; DoNotTryExtendedMongoSyntax: boolean): PUTF8Char;



in this point:

 '{': begin
    Kind := betDoc;
    Start := BSONDocumentBegin;
    repeat inc(JSON) until not(JSON^ in [#1..' ']);
    repeat
      // see http://docs.mongodb.org/manual/reference/mongodb-extended-json
      Name := GetJSONPropName(JSON); // BSON/JSON accepts "" as key name
      BSONWriteFromJSON(Name,JSON,@EndOfObject,DoNotTryExtendedMongoSyntax);
      if (JSON=nil) or (EndOfObject=#0) then
        exit; // invalid content
    until EndOfObject='}';
  end;

EndOfObject is always ':'

#114 mORMot 1 » [mongodb] FindONe clarification » 2014-05-22 07:39:03

Sabbiolina
Replies: 7

I thought that the two lines of code are equivalent, however it seems that the first is not interpreted correctly, the call does not return.


    doc:=Coll.FindDoc('{Name:?}',['{"$regex": "test.*", $options: "i"}']); // infinite loop 

    doc:=Coll.FindDoc('{Name:{"$regex": "test.*", $options: "i"}}',[]); // ok

#116 Re: mORMot 1 » [mongodb] FindONe and FindDoc » 2014-05-21 12:14:32

pre-solution:

I found the problem:

     finddoc function (Criteria: PUTF8Char; const Params: array of const;
       NumberToReturn: integer = maxInt; NumberToSkip: Integer = 0;
       Flags: TMongoQueryFlags = []): variant; overloaded;

maxint for NumberToReturn is wrong.

I solved this way:

doc -> docs
1 <-> maxint

     finddoc function (Criteria: PUTF8Char; const Params: array of const; NumberToReturn: integer = 1; NumberToSkip: Integer = 0;
       Flags: TMongoQueryFlags = []): variant; overloaded;

     FindDocs function (Criteria: PUTF8Char; const Params: array of const;
       NumberToReturn: integer = maxInt; NumberToSkip: Integer = 0;
       Flags: TMongoQueryFlags = []): variant; overloaded;


old finddoc must be convertitit in findDocs.

#117 mORMot 1 » [mongodb] FindONe and FindDoc » 2014-05-21 10:02:43

Sabbiolina
Replies: 4

hello, I'm trying mongodb library.

In the blog there was the example of searching for a document:
  doc: = Coll.FindDoc ('{_id:?}', [5]);
  doc: = Coll.FindOne (5); / / Same as previous

but doing a test, I noticed that the result is rather different:

FindOne: {"_id": "idtest", "Name", "test", "Number": 1000}
Finddoc: [{"_id": "idtest", "Name", "test", "Number": 1000}]

Finddoc returns an array.

is wanted or is it a bug?

Board footer

Powered by FluxBB