#1 mORMot 2 » Named Pipe server in mormort2? » 2024-01-14 22:40:28

AntonE
Replies: 1

Hi all,
I'm converting a mormot1/DelphiXE4 project to mormot2/Delphi11 and got almost everything refactored.
However I find no RestServer.ExportServerNamedPipe ?

How can I export NamedPipes from TRestServer/TRestHttpServer I'm M2?
Regards
Anton

#2 Re: mORMot 2 » JsonPath like queries from TDocVariant(Data)? » 2024-01-14 22:35:37

Thank you for the reply.
I somehow missed it; But now come back to this project and stumbled upon your reply searching for something else:)

I saw the RTL support, but since I use synopse json<>TDocVariantData almost exclusively, I hoped to avoid 'heavy' RTL classes.
I suspect the SQLite/JSON support will be good (i.t.o. fast/memory efficient) for large datasets so I'll try that in future and I'll probably have a look at the FPC implementation at some stage.

A way to query similar to JsonPath, (even just in code) will be very useful, especially if you can aggregate and group as well, but for now I just write queries by hand. smile

Thank you
Keep up the great work

#3 mORMot 2 » JsonPath like queries from TDocVariant(Data)? » 2023-11-25 03:26:35

AntonE
Replies: 2

Hi, I am more impressed by mORMot1&2 everytime I use it. Respect!

TDocVariantData is very powerful. I want to use it as an in-memory 'json object List' for classes (TOrm or others) that must constantly be marshalled but seldom changed.
E.g. a (mostly) lookup table of TOrm classes loaded into a TDocVariantData-Array, perhaps sorted by TID for FastFind.

However, something like https://jsonpath.com/ for TDocVariant(Data) can make a for a very powerful and versatile tool, especially in harmony with copyOnReference/ByValue.
E.g. server-side cache of data objects, sorted by some keyin a TDocVariantData array that is already quick to serialize to Json, but now to add ability to do on-the-fly basic 'queriesq to get subset of objects/fields (like sqlWhare/Args) in nested structures.

Or any utility/tool that can help me not write every json-query out by and as code will help,
thanks!

Anton

#4 mORMot 1 » QUIC from google » 2022-10-04 16:15:52

AntonE
Replies: 2

For high-performance library such as mORMot, this might be interesting in future :
https://www.chromium.org/quic/

https://youtu.be/VONSx_ftkz8

#5 Re: mORMot 1 » Javascript authentication » 2022-08-02 07:04:11

Hi Ab,
I somehow missed these messages...

ab wrote:

What is your feedback with Flutter?
Is it easy to work with?
Which tutorial do you recommend?


I think Dart and Flutter is amazing and getting better with updates almost every day.

The best tutorial I saw is on AppBrewery "The Complete 2021 Flutter Development Bootcamp with Dart", Flutter/Dart changed a bit since that course, especially with null-safety, but it's not to bad to figure out what need to change. Really good progression into Dart and Flutter, covering basic design all the way to using and writing APIs, Interfaces, Services (in Delphi-speak).
The whole idea of 'Widgets' in Flutter to dynamically build the UI elements (sometimes on each frame), seems weird at first, but it is so to create dynamic, multi-platform apps. Everything, even an Integer is an Object and everything in the UI is a Widget, so the language get really expressive and compact (sometimes).
I'm not turning back, no more expensive Delphi licenses, which I only need for client-side UI apps, but thanks to mORMot, not for server![8-}>

https://appbrewery.com/courses/enrolled/548873

I have not tested/deployed a full-blown non-debug app, to see performance, etc, yet; Almost...

Good luck!
Anton E

#6 Re: mORMot 1 » mORMot2 TObjectList RegisterClassForJSON » 2022-05-07 15:17:37

I have TJSONSerializer.RegisterClassForJSON(TObjectList) on Client app (XE4/mormot1) but had to comment that line out on server (D11/mormot2) as described in OP.
I pass the objectlist via Intertfaced based service method,e.g.

function CalList(var Lst:TObjectList):Boolean; 

Regards
AntonE

#7 mORMot 1 » mORMot2 TObjectList RegisterClassForJSON » 2022-05-05 12:47:26

AntonE
Replies: 2

As TObjectList is not a TPersistentClass it cannot be registered for JSON via Rtti.RegisterClass and TJSONSerializer.RegisterClassForJSON is not available anymore.
How can I register it as I use it extensively in mormot1 code migrated to mormot2

Thanks
AntonE

#8 Re: mORMot 1 » Javascript authentication » 2021-07-17 02:19:55

Happy to revive an old thread.
I've never worked with Javascript but started to use Flutter (Dart language) and I must say it's starting to grow on me.
I struggled to get authentication to a mORMot server working and almost posted here a few times.

Many thanks to the posters above, I couldn't have done it without you.
FWIW, if anyone need to auth to mORMot from Dart:

import 'dart:convert';
import 'package:archive/archive.dart';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart';

main() async {
  MORMOT_client http_client = MORMOT_client('http://10.1.1.200:8092/','main/');
  await http_client.login('User', 'synopse');

  final List<dynamic> products = await http_client.GetList('product');
  print(products);

  final Map<String,dynamic> product = await http_client.GetItem('product/106');
  print(product);
}

class MORMOT_client {
  MORMOT_client(String this.SERVER_URL,String this.SERVER_MODEL){}

  String SERVER_URL         = '';
  String SERVER_MODEL       = '';
  String SESSION_ID         = '';
  String SESSION_PRIVATEKEY = '';
  String SESSION_USERNAME   = '';
  int    SESSION_TICK_COUNT = 1;
  int    SESSION_START_TIME = 0;

  login(String userName, String userPass) async {
    String clientnonce    = '';
    String servernonce    = '';
    String password       = '';
    String hashedPassword = '';

    SESSION_ID            = '';
    SESSION_PRIVATEKEY    = '';
    SESSION_USERNAME      = userName;
    SESSION_TICK_COUNT    = 1;
    SESSION_START_TIME    = DateTime.now().millisecondsSinceEpoch;

    clientnonce = SHA256((DateTime.now().millisecondsSinceEpoch ~/ (1000 * 60 * 5)).toString()).toString();

    final Map<String, dynamic> sessionResult = await urlToMap(SERVER_URL+SERVER_MODEL+'auth?Username=$userName');
    if (sessionResult.isEmpty) {return;}

    servernonce    = sessionResult['result'];
    hashedPassword = SHA256('salt' + userPass).toString();
    password       = SHA256('main' + servernonce + clientnonce + userName + hashedPassword).toString();

    final Map<String, dynamic> authResult = await urlToMap(SERVER_URL+SERVER_MODEL+'auth?Username=$userName&Password=$password&ClientNonce=$clientnonce');
    if (authResult.isEmpty) {return;}

    String session_str = authResult['result'].toString();
    SESSION_ID         = int.parse(session_str.split('+')[0]).toRadixString(16).padLeft(8, '0');
    SESSION_PRIVATEKEY = session_str + hashedPassword;
    print('SID:$SESSION_ID');
    print('SPK:$SESSION_PRIVATEKEY');
  }

  String GetSessionSignature(String url) {
    String? prefix;
    String? nonce;
    String? keynonce;
    String? final_SIGN;

    SESSION_TICK_COUNT = DateTime.now().millisecondsSinceEpoch - SESSION_START_TIME;
    print('SessionTickCount:$SESSION_TICK_COUNT');

    nonce    = SESSION_TICK_COUNT.toRadixString(16).padLeft(8, '0');
    keynonce = getCrc32(utf8.encode(SESSION_PRIVATEKEY + nonce + SERVER_MODEL+url)).toRadixString(16).padLeft(8, '0');
    print('nonce   :$nonce');
    print('keynonce:$keynonce');
    return SESSION_ID + nonce + keynonce;
  }

  Future<List<dynamic>> GetList(String url)async{
    final String signature = GetSessionSignature(url);
    final String prefix    = (url.indexOf('?')>0) ? '&' : '?';
    final String theUrl    = SERVER_URL+SERVER_MODEL+url+prefix+'session_signature=$signature';
    print('URL:$theUrl');
    final List<dynamic> auth2 = await urlToList(theUrl);
    print(auth2);
    return auth2;
  }
  Future<Map<String,dynamic>> GetItem(String url)async{
    final String signature = GetSessionSignature(url);
    final String prefix    = (url.indexOf('?')>0) ? '&' : '?';
    final String theUrl    = SERVER_URL+SERVER_MODEL+url+prefix+'session_signature=$signature';
    print('URL:$theUrl');
    final Map<String,dynamic> item = await urlToMap(theUrl);
    print(item);
    return item;
  }
}

Digest SHA256(String value){
  var bytes = utf8.encode(value);
  return sha256.convert(bytes);
}

Future<Map<String,dynamic>> urlToMap(String url)async {
  Response r = await get(Uri.parse(url));
  if (r.statusCode != 200) {
    print(r.statusCode);
    print(r.body);
    final Map<String,dynamic> tmp = {};
    return tmp;
  }
  final Map<String, dynamic> res = jsonDecode(r.body);
  return res;
}
Future<List<dynamic>> urlToList(String url)async {
  Response r = await get(Uri.parse(url));
  if (r.statusCode != 200) {
    print(r.statusCode);
    print(r.body);
    final List<dynamic> tmp = [];
    return tmp;
  }
  final List<dynamic> res = jsonDecode(r.body);
  return res;
}

It is a very raw testing unit, needs exception handling etc.
Output an array(list) and object(map):
[{ID: 1}, {ID: 3}, {ID: 4}, {ID: 5}, {ID: 10},...

{ID: 106, Created: 0, Modified: 135522307659, CODE: SLUC40MBPS, DESCRIPTION: SLUC40MBPS...

#9 Re: mORMot 1 » mORMot2 examples » 2021-03-07 05:19:37

Thanks for the samples!

Testing Project04 Server&Client in Win64, Client compiles and run fine.
However trying to compile Project04InterfaceBasedServer for Win64:
In Delphi 10.4 : [dcc32 Fatal Error] F2092 Program or unit 'mormot.core.variants' recursively uses itself
In FPC 3.3.1    : mormot.core.json.pas(9217,32) Error: Wrong number of parameters specified for call to "<Procedure Variable>"

Changing said lines to :
    if not Assigned(OnMatch) or
       (not Assigned(@KeyCompare) and
        not Assigned(@ValueCompare)) then
      exit;

Compiles and run, but when sending a text msg from client app, get error:
{  "errorCode":406,  "errorText":"IExample.Add failed parsing ASample: TSample from input JSON"  }

#10 mORMot 1 » mORMot2 recommended FMX-Client(WS?) » 2021-03-03 03:43:58

AntonE
Replies: 4

Hi all,
SHORT:
Q1) Best server/client setup in mORMot2 for secure Server[Winx64]/Client[FMX Android].
Q2) How to wire-up 3rd party WebSocket client-component into mORMot2?

LONG:
Q1)I need to start a new multi-platform (Win/Android) Client app in Firemonkey, server running on Windows.
I've been trying to get WebSockets working with mORMot1 Android, installed Certificates and have bought latest scgWebsockets license for an Android WebSockets client.
Coming here for help, I discovered mORMot2! Congrats and thank you! So it makes me think if some new development might make a difference here.

The app's storage+network must be fully encrypted (preferably end-to-end for net) and async WebSockets would be ideal, with the usual mORMot TRest and InterfacedBasedServices.
All clients will be mORMot compiled for Win/Android/macOs.

What would be the recommended secure server/client setup be, especially for Android?
I've read before that one need to compile mORMot's WebSocket client in Larazus which can be used in Delphi FMX/Android? Is this still the case?

Q2) Alternatively; How can I 'wire-up' scgWebsocketClient in Android so the rest of my code work with a TRest mORMot class/intf as usual?

Thanks, hope it make sense.

#12 Re: mORMot 1 » Delphi 10.2 Android FMX client "Impossible to connect..." » 2017-06-02 11:52:29

Thank you,
my oversight,
the SSID my Android device was connecting to on my WiFi had Client-Isolation on, working fine now at least for a basic http connection.
Good bye datasnap for good!
AntonE

#13 mORMot 1 » Delphi 10.2 Android FMX client "Impossible to connect..." » 2017-06-02 04:21:03

AntonE
Replies: 2

Hi, I'm trying to get Delphi 10.2 Multi-device to work with mORMot.
I run the Project14ServerHttpWrapper project, then extract the mORMotClient.pas file, create a multi-device application with one button that does:

procedure TForm1.Button1Click(Sender: TObject);
var C : TSQLRestClientHTTP;
begin
 C:=mORMotClient.GetClient('192.168.0.13','User','synopse',8888);
 ShowMessage(TTimeLogToIso8601(C.ServerTimeStamp));
end;

On Win32 it works 100% from a remote PC(so firewall is no issue), but on Android I get "Impossible to connect to 192.168.0.13:8888 server."

I do not have older Delphi that can compile for Android so I cannot test if it's a Delphi 10.2 issue or not.

What can I do to further narrow down the issue or do I need to do something else Android-specific (https?).

Thanks!

Edit: I might add that the server side is compiled on XE4 but with same version mORMot library.
I also compiled the sample by Peter Evens from here https://synopse.info/forum/viewtopic.php?id=3418 (server and client in Delphi10.2) and I get the same error an Android, Win32 works fine.

#14 mORMot 1 » FormatSQLWhere for selecting multiple inputs » 2017-03-09 18:14:29

AntonE
Replies: 1

Hi,
I have a data object as such:

type
  TIPAddress : Cardinal;
type
  TSQLTrafficItem=class(TSQLRecord)
  private
    FIP         : TIPAddress;
    FDate       : TDateTime;
    FUL         : Int64;
    FDL         : Int64;
  published
    property IP            : TIPAddress     read FIP        write FIP       ;
    property DateSlot   : TDateTime      read FDate      write FDate     ;
    property UL           : Int64          read FUL        write FUL       ;
    property DL           : Int64          read FDL        write FDL       ;
  end;

But in my app, each client can have many IPs, in fact some IPs might be subnets, containing multiple IPs.
So to get some aggregated data, I used to pass a dynamic array :

type TIPsPair= record
                     IP:String;
                     IP1,IP2:Cardinal;
                    end;
     TIPsPairArr = Array of TIPsPair;

where IP is the text subnet, e.g. "10.1.2.0/24" and IP1 will then hold calculated cardinal value of 10.1.2.0 and IP2 will hold the cardinal value of 10.1.2.255 to indicate the range.
So passing a client with say these IPs:
10.2.2.2/32  (10.2.2.2-10.2.2.2) call these cardinal values IPA1-IPA2
10.3.3.0/30 (10.3.3.0-10.3.3.3) call these cardinal values IPB1-IPB2
10.4.4.0/24 (10.4.4.0-10.4.4.255) call these cardinal values IPC1-IPC2
I had to built a SQL query like so:

select * from TRAFFIC where DateSlot>=:DateF and DateSlot<:DateT and 
(
((IP>=IPA1)and(IP<=IPA2))or
((IP>=IPB1)and(IP<=IPB2))or
((IP>=IPC1)and(IP<=IPC2))
)

OFC values IPA1, IPA2,etc replaced with cardinal numbers in real query.

Is there a better, more efficient way to do it in mORMot to harness cached prepared statements where I can maybe create a larger 'flat' array of the required IPs, e.g.

Var Arr : Array of Cardinal;
Arr[0]:=IPStrToCardinal(10.2.2.2);
Arr[1]:=IPStrToCardinal(10.3.3.0);
Arr[2]:=IPStrToCardinal(10.3.3.1);
Arr[3]:=IPStrToCardinal(10.3.3.2);
....

Then use something like:

aList:=Server.RetrieveList<TSQLTrafficItem>(' IP IN ? AND DATESLOT>= ? AND DATESLOT < ?',[Arr,DateF,DateT]);

Or some other advice to make this query as efficient/fast as possible?

Thanks
AntonE

#15 mORMot 1 » ZEOS 7.2.1, TSQBDBConnectionProperties & multi-thread » 2017-02-16 16:22:28

AntonE
Replies: 0

Hi,
I'm busy migrating a legacy app and need to access some Firebird data in multiple threads.
First time Synopse library use for direct Firebird access.

(Very) Stripped down code is:

function GetUsageTotal(DB:TSQLDBConnectionProperties;DataParams:TDataParams):Int64;  (*Global function in a unit*)
var RES : ISQLDBROWS;
begin
  RES:=DB.Execute(SQL.Text,[]);
  if RES.Step
     then Result:=RES['Tot']
     else Result:=0;
end;

Type TCheckThread = class(TThread);

procedure TCheckThread.Execute;
begin
 DBCP:= TSQLDBZEOSConnectionProperties.Create(TSQLDBZEOSConnectionProperties.URI(dFirebird,IP),DB,UN,PW);
 while not Terminated do
  begin
    (* some other stuff, fetch task, back-off yield/sleep, etc *)
    Tot:=GetUsageTotal(DBCP,DataParams);
    (* some other stuff *)
  end;
 DBCP.Free;
end;

Is this in principle correct?
I initially had all threads share one TSQLDBZEOSConnectionProperties but got this error, so I made a copy for each thread and still get the issue.
If I run it in 1 thread there is no problem, but if I run multiple threads then I periodically get 'corrupt' results.
Error in ZDbcInterbase6Utils line 829, e.g. errors converting from DateTime '022/12/2016' or '02/16/201717'. (no typos)
I have other less-intensive simultaneous threads running with also TSQLDBConnectionProperties but they access different tables, this is the only place where I simultaneously need to access the same database table (many GBs big).

I have {$DEFINE ZEOS72UP} in zeos.inc but not sure if other changes need to be made there.

Using latest Zeos 7.2.1 & mORMot downloaded about two weeks ago. Firebird 3.0.1

If there is nothing obviously wrong here then I'll write a test case to try replicate it outside my code.

Thank you
AntonE

#16 mORMot 1 » MVC design question » 2016-11-10 14:12:28

AntonE
Replies: 1

Hi.
Looking at the MVC sample...

To segregate logical units of the app, can/should I create an IMVCApplication for each 'module' in the server? As one (not so good) example, in accounting app you can have billing, inventory, blog, etc. as separate logical 'modules'.
AntonE

#17 mORMot 1 » TDocVariant and IDispatch » 2015-04-02 20:06:13

AntonE
Replies: 1

I need to implement an IDispatch interface to be able to access TDocVariant 'properties' from scripts.
Has anyone done this before that care to share some code? smile

Regards
AntonE

#18 mORMot 1 » TSQLTableJSON create/add rows? » 2015-03-25 20:18:25

AntonE
Replies: 0

Hello.
I need to create a TSQLTableJSON on the fly with custom columns, i.e. not tied to a TSQLRecord class.
(Actually it must be created from custom fields derived from TDocVariant within a TSQLRecord variant property)
Is it possible to create the TSQLTableJSON with column types, then add rows or it it read-only?

If it is read-only, what would be the best way to create a table like this?
1) Create the whole resultset as a JSON string by using TTextWriter
2) Create TSQLTableJSON.CreateWithColumnTypes (so that TSQLTableToGrid can display nicely)?

Or is there maybe some other mORMot-magic method to get same result?

Thanks
AntonE

#19 Re: mORMot 1 » TransactionBegin problem » 2015-01-22 21:26:13

I looked at that.
One thing that caught my eye:

Most TSQLDBConnectionProperties will inherit from TSQLDBConnectionPropertiesThreadSafe, so will create one connection per thread. This is efficient, but some providers may have issues with it.

Do I need to create another connection to local SQLite db for each internal server thread?

Thank you for your reply.

BTW: aServer.AcquireExecutionMode[execORMWrite]=amLocked

#20 Re: mORMot 1 » TransactionBegin problem » 2015-01-22 18:20:13

Thanks. I'll definitely use that for some processes, but my problem is here that I need either:
1) Increment a value
2) Check if a record exists, if so, increment some fields, if not, create.
So I don't think a batch can work in this scenario?

I removed all but 1 usage of transactions so there can be no conflicting transactions and still I get the error after some random time.

I might be doing something else wrong...
e.g.:

   (*Update sites traffic*)
 while not Server.DB.TransactionBegin(TSQLWISPSite) do Sleep(50);
   Site:=TSQLWispSite.Create;
   for ID in SitesTouched.Keys do
    begin
     I64:=SitesTouched[ID];
     Server.DB.Retrieve(ID,Site);
     Site.CapUsed:=Site.CapUsed+I64;
     Server.DB.Update(Site,'CapUsed');
    end;
   Site.Free;
  Server.DB.Commit;
 (*Now flush results to DB*)
 while not Server.DB.TransactionBegin(TSQLWISPTraffic_IP) do Sleep(50);
 SQL_IP    :=TSQLWISPTraffic_IP.Create;
 for TrafficIP in ListIP do
  begin
   SQL_IP.FillPrepare(Server.DB,'Year = ? and Month = ? and Day = ? and Hour = ? and IP = ?',[Y,M,D,H,TrafficIP.IP]);
   if SQL_IP.FillOne
      then begin
            SQL_IP.UL:=SQL_IP.UL+TrafficIP.UL;
            SQL_IP.DL:=SQL_IP.DL+TrafficIP.DL;
            Server.DB.Update(SQL_IP);
           end
      else begin
            SQL_IP.ClearProperties;
            SQL_IP.Year    :=Y;
            SQL_IP.Month   :=M;
            SQL_IP.Day     :=D;
            SQL_IP.Hour    :=H;
            SQL_IP.CalcDate:=RecordDate;
            SQL_IP.IP      :=TrafficIP.IP;
            SQL_IP.UL      :=TrafficIP.UL;
            SQL_IP.DL      :=TrafficIP.DL;
            Server.DB.Add(SQL_IP,True);
           end;
  end;
 Server.DB.Commit;
 SQL_IP.Free;

I use it without transaction and performance is still very good with no problems:) but I'll have to see when app goes live and real data flows.

AntonE

#21 mORMot 1 » TransactionBegin problem » 2015-01-21 07:48:22

AntonE
Replies: 5

I have an app that run 2 threads in background that record and edit data.
They run relatively tight loops (<50ms each time) and I have at beginning and end of each:

   while not Server.DB.TransactionBegin(TSQLWISPSite) do
    Sleep(50);
...
   Server.DB.Commit;

With even no client connected, from time to time, I get  "SQLITE ERROR (1) -cannot rollback transaction - no transaction is active."
When it get that error, I never get a 'True' result from TransactionBegin and the server loops indefinately until I restart it.

Am I handling transactions wrong? Where are no errors between TransactionBegin and Commit.
In line 25117 in mORMot.pas , fTransactionActiveSession stays =1, so after initial error, TransactionBegin just always returns False without error.

Regards

PS: Am I right in assuming that SessionID is not relevant as only one transaction can be active at a time in anycase? Or should each call have a unique SessionID?

#22 Re: mORMot 1 » mORMot to Nested TClientdataset... and back again. ORMCDS unit » 2014-12-17 19:21:21

I'm afraid I'm still a bit in the dark with mORMot's Rtti. Using TSQLRecord is easy with PPropInfo, etc.
But how do I enumerate a record type similar to this with mORMot's built-in functions ?:

function EnumRecordType(ATypeInfo:PTypeInfo):RawUTF8;
var Ctx : TRttiContext;
    Rec : TRttiRecordType;
    Fld : TRttiField;
begin
 Ctx:=TRttiContext.Create;
 Rec:=TRttiRecordType(Ctx.GetType(ATypeInfo));
 for Fld in Rec.GetFields do
  Result:=Result+Fld.Name+' : '+Fld.FieldType.Handle^.Name+#13#10;
 Ctx.Free;
end;

Trying to use code below but do not know how to get record field names:

function EnumRecordType(ATypeInfo:PTypeInfo):RawUTF8;
var RecType  : PRecordType;
    RecField : PRecordField;
begin;
 RecType:=ATypeInfo^.RecordType;
 for I:=0 to Pred(RecType.Count) do
  begin
   RecField:=@RecType.Fields[i];
   (*How to get field name, not just type name*)
   Result:=Result+RecField^.TypeInfo^.{Field?}Name+' : '+RecField^.TypeInfo^.Name;
   case RecField^.TypeInfo^.Kind of
    tkDynArray   : begin

                   end;
   end;
  end;

TSQLPropInfoRecordRTTI seems to have the fields/methods I need but it is only used as an object's published properties? Or how can I instantiate it for any record type?

Thanks
AntonE

#23 Re: mORMot 1 » mORMot to Nested TClientdataset... and back again. ORMCDS unit » 2014-12-17 10:00:22

Hey Arnaud, thanks for doing this to my little unit. smile

I'm redoing it in a more mORMot way using TSQLPropInfoRtti family.
How do I get a DynArray element type from TSQLPropInfoRTTIDynArray ?
Once I have an instance, I can get it from TDynArray.ElemType but I need to construct from TSQLRecordClass.
...or must I still use Delphi Rtti to get that?

Also, if a DynArray have Record as element type, how do I get TSQLPropInfoRecordRTTI for that type? I can only see how to construct TSQLPropInfoRecordRTTI as a new member, don't know how to reference it for arbitrary type.

Thanks
Regards

#24 Re: mORMot 1 » mORMot to Nested TClientdataset... and back again. ORMCDS unit » 2014-12-16 14:53:50

I uploaded an updated version to that same link above.
Fixed a few bugs a.o. adding/deleting items in a DynArray.
However, I have a problem with memory leaks using DynArrays, but only when resizing them. It seems when a copy is made, I'm not deferencing the old copy properly.
If I run FastMM4 in FullDebugMode I even get error that memory that is freed are referenced and the app crash. Without FullDebugMode I get AnsiString memory leaks (when resizing arrays) but the app works fine. (Win32). In ORMCDS.pas lines 537 onwards is where the trouble lies I think.
I've tried various methods, using mORMot TDynArray and Rtti but it seems it's in the usage of TValue that old reference to array does not get cleaned up, so not production ready yet. smile

Regards

#25 Re: mORMot 1 » ConnectionProperties.GetTableNam return json result? » 2014-12-08 20:22:54

Awesome, working like a charm.
Thank you so much.

#26 Re: mORMot 1 » ConnectionProperties.GetTableNam return json result? » 2014-12-08 12:27:03

Sorry to revive an old thread, but trying with a TRawUTF8DynArrayDynArray doesn't work?

var Arr:TRawUTF8DynArrayDynArray;
begin
 Arr:=DebtorsList_; (*Can see Arr have correct data in debugger*)
 Result:=DynArraySaveJSON(Arr,TypeInfo(TRawUTF8DynArrayDynArray)); (*Output is just gibberish*)
end;

Am I doing it wrong?
Thanks
AntonE

#27 Re: mORMot 1 » mORMot to Nested TClientdataset... and back again. ORMCDS unit » 2014-12-03 18:36:55

Ok, I've improved quite a bit since that version, will upload soon.
I'll check out TSynVirtualDataset. smile
AntonE

#29 mORMot 1 » mORMot to Nested TClientdataset... and back again. ORMCDS unit » 2014-12-01 14:07:33

AntonE
Replies: 12

I wrote a unit to convert TSQLRecord and it's sub-arrays/records to Nested TClientdatasets.

Some key features:

  • Create TClientdataset hierarchy dynamically based on data.

  • Also work with static TClientDatasets+Static fields.

  • Handle sub-TSQLRecord lists. (See sample)

  • Convert Set of ENUM to/from multiple Boolean fields for grid checkboxes

  • Most importantly: Apply delta-changes back to mORMot. i.e. only changed fields.

  • (With RTTI adjustments), should work on any platform that support TClientdataset, e.g. Intraweb

It is very first version so not tested on insert/delete yet nor many types of data, guaranteed to be buggy & lacking at this stage, but working.

ftp://ftp.true.co.za/ORMCDS.7z (Working in Delphi XE4 with JEDI installed for TJvDBUltimGrid, change to TDBGrid if needed.)

In demo:
Choose Static or Dynamic demo, select 'Load' to load data, edit any field or nested data, click 'Apply'.
Best is to see code to get more info.
My first try with RTTI and new at mORMot so I'm sure it could have been done more elegantly with mORMot's RTTI built-support.
Also not optimized for speed but should be pretty fast.

Regards
Antone

#30 mORMot 1 » mORMot & Intraweb » 2014-11-20 16:04:58

AntonE
Replies: 1

Hello,
trying to add mORMot to an IntraWeb XIV app in Delphi XE4.
Just create simple stand-alone IW-app, add:

type
  TIWServerController = class(TIWServerControllerBase)
    procedure IWServerControllerBaseNewSession(ASession: TIWApplication);
    procedure IWServerControllerBaseConfig(Sender: TObject);
    procedure IWServerControllerBaseDestroy(Sender: TObject);

  private

  public
    Model       : TSQLModel;
    SQLDB       : TSQLRest;
  end;

procedure TIWServerController.IWServerControllerBaseConfig(Sender: TObject);
begin
  Model := TSQLModel.Create([TSQLWISPRouter,TSQLWISPClient,TSQLWISPSite,TSQLWISPEMailAcc,TSQLWISPVoIPAcc,TSQLIPTraffic]);
  SQLDB := TSQLRestServerDB.Create(Model,ChangeFileExt(paramstr(0),'.db3'));
  TSQLRestServerDB(SQLDB).CreateMissingTables(0);
end;

procedure TIWServerController.IWServerControllerBaseDestroy(Sender: TObject);
begin
 SQLDB.Free;
 Model.Free;
end;

Just run server and try close, it gives AV error in SynCommons line 43472 in TSynLogFamily.Create(aSynLog: TSynLogClass);
If I just create/close DB it's fine, but once IW app runs, then I can't close without AV.

Best regards
AntonE

#31 Re: mORMot 1 » MVC/MVVM Web Applications with mORMot! » 2014-10-30 09:37:30

Wow I go away for a month and come back to see this... :-)
Great work, showcasing the expandable capabilities of mORMot.

I previous UI generation discussions the focus is always on displaying data, which in my opinion is the easy part.
What I'm interested in is interactive, i.e. INPUT/EDIT of data by users and especially handling concurrency, delta of changes, etc.

E.g. you might have a large TSQLRecord, say "TSQLClient" with many fields and sub-structures (using extensive sharding).
Simple Scenario:
UserA opens Client:ABC001 'view' and go on coffee break, displaying e.g. phone number as '123 456 7890'
UserB opens and edit Client:ABC001 and change phone number to '555 456 7890'
UserB comes back from break, edit 'email address' and save.
Now if I just post everything on UserA 'edit' screen, I will overwrite the phone number change made by UserB.


So in short:
1) how to handle updates and edits from views?
2) how to prevent unexpected data-loss due to concurrent user actions?

Really looking forward to see where this is going.

Best regards
AntonE

#32 Re: mORMot 1 » mormot and LiveBindings » 2014-08-20 07:50:04

LiveBindings is not very cool IMHO.
Which is why I started this, not perfect either: (Which has moved along a bit since)
http://synopse.info/forum/viewtopic.php … 635#p11635

But have a look at samples here:
http://synopse.info/forum/viewtopic.php?id=1144
To get LiveBinding sample

#33 Re: mORMot 1 » TrueORM idea - High level MVC on top of mORMot » 2014-08-04 13:27:32

I had a bit of a rethink. NOT a high-level MVC anymore (or yet), just a code-generation tool, but still very handy! Download & run sample to see possibilities.
A new version available.

ftp://ftp.true.co.za/TrueORM_1.2.zip
(binary included, so just download & run)

ReadMe:
TrueORM 1.2

Tool to help generate classes, units, forms, etc. from basic class/property info.

Quick start from sample:
1)Run TrueORM2
2)Click 'Load project'
3)Go to Project/Tasks tab. (Note Destination folder "FirstApp") Click 'Run tasks'.
4)In Delphi, open SampleApp.dpr from "FirstApp" sub-folder, compile/run! (Need JVCL)

Quick start from new project:
1)Give project name
2)Add classes, in each class, add some fields+controls
3)Add tasks to link project/classes to templates.
4)Save smile
5)Run tasks
(or just add new class to current sample project, link your new class to the task "Data&Lists", run tasks and see what happens smile )

TrueORM just wrote a whole app from basic info and mustache templates.

Detailed description:
Templates:
A template is a collection of related files. E.g. a form that has .pas & .dfm files but you can add many loosely related files(see sample 'Class list & Edit forms' that include mORMot Data unit, etc.)
Templates are separate from the project, so can be re-used in multiple projects.
Templates can be external files or embedded in the DB. Filenames are also mustache templates.
Apart from normal context variables in mustache, use translate to pass some custom variables, like {{"Top}} {{"TopAdd}} {{"TabOrder}} that is used in Delphi code to increment UI controls for DFM files.

Classes:
Classes contain a collection of Fields that is the input required to generate code.

Tasks:
Tasks is bringing the Classes and templates together and is where the actual code is generated.
If any classes are marked as 'Involved' in a task, then those classes will each be sent to the specified template, in turn, with just the Class(+fields) as mustache-context, e.g. for class editing-forms)
If a task does not 'involve' any classes, then the entire project is sent as mustache context to the template, e.g. for main-forms or app-wide templates like .dpr files.

Notes:
There are still few problems/bugs and I haven't tested all DelphiTypes in combination with all control types yet.
Since the app is generated from templates, you can create any type of app (client/server/firemonkey/etc.) or form, the ones included are just simple examples to illustrate possibilities.
The app is still far from perfect, but can be used to generate basic skeleton forms/units that can be copy/pasted/edited in your real app/project. (e.g. Memos, RadioGroups, etc. need to be manually resized in the generated form. packed record and Array/TObjectList support not working yet.)

Hope someone else can find it usefull.
Greetings

#34 Re: Other components » SynMustache and filters » 2014-08-04 09:05:49

I was thinking to use Translate to generate custom values.
e.g. in template have : {{"MyVar}}
then

procedure MyTranslate(var English:String);
begin;
 if SameText(English,'MyVar')
    then begin;
             English:=CalcIt;
           end;

end;

?

Then it can even insert more mustache code and run a second parse/render cycle to render that.

Regards

#35 Re: mORMot 1 » How to implement a TSQLRecord descendant w a property of TObjectList ? » 2014-07-31 23:34:49

I figured my problem out. roll
Subitem that have properties that need init code, like TObjectList only have e.g. TObject.Create called and it's not virtual.
If I descend from TSQLRecord instead of TObject (even not register it to Model), then I can make

Constructor Create;override;

and it therefore works perfectly multiple-levels deep.

Regards

#36 Re: mORMot 1 » TrueORM idea - High level MVC on top of mORMot » 2014-07-31 20:09:08

Thanks tech,
yes I agree, a universal client as you call it can be very cool if done right, with mORMot's superior performance and flexibility, that might be a possibility.
However, I think this project is for now intended to be a.o. a code-generator helper tool, to generate code/units for you to prevent repetitive coding and maybe help generate multi-platform UI code for you as well (think .DFM and .HTML)
Also to help you handle things like enum/set in radio/checkboxes, higher-types like email,phone numbers, instead of just 'RawUTF8', and generating the UI code that goes with it, etc. Stuff I do manually all the time that is mindless, repetitive and annoying. big_smile
Because it use templates, you can do with it what you want, I'll use it to generate Delphi code that I can then manually fine-tune.
Scripting for now will be more to help generate custom code that cannot be easily represented via a templates, if at all.
Eventually it might evolve into a universal client/server, we'll see. smile

Thanks for your input

#38 mORMot 1 » TrueORM idea - High level MVC on top of mORMot » 2014-07-31 12:22:45

AntonE
Replies: 4

Please see CSV2ORM : http://synopse.info/forum/viewtopic.php?id=1911

TrueORM
A high-level Delphi ORM/MVC(?) built on top of mORMot.

It is an idea spawn from CSV2ORM, to expand on that, not all as described below is working yet, but it's the idea that count.

"The idea" is an app that (will have) have 3 parts:

  • Projects (Model| TSQLproject that contains Classes/Records)

  • Templates (View| TSQLTemplate that contains Mustache templates)

  • Scripts (Controller?| TSQLScript that contain Pascal/Javascript code)

You can have multiple projects. Each projects can contain a list of T_Class
"T_Class" each contain a list of T_Variable descendants, just like normal OOP.

A)Projects  (TSQLProject):
As a bare-bone start you create a new Project.
This project contain a list of T_Class that can be marked as either :
packed record
TObject
TSQLRecord

Classes (T_Class):
Classes contain a polymorphic ObjectList of T_Variables (properties/fields) descendants.

  • T_Variable       (abstract)

  • T_SimpleType     (abstract)

  • T_Integer

  • T_Float

  • T_Currency

  • T_Boolean

  • T_DateTime

  • T_String

  • T_Collection  (abstract)

  • T_Array

  • T_ObjectList

  • T_Class

The idea is to use only basic types, e.g. T_Integer but within T_Integer there are options to select if it's Int32/Int64, signed/unsigned, ENum, Set, etc.
Also e.g. there is only 1 DateTime type, but within it you set to use Date only, Time only or DateTime, Duration, high-precision, etc.
T_Array, T_ObjectList, T_Class variables let you select another T_Class from your project to created nested Classes.


USAGE: (Not all working yet, concept smile
As in CSV2ORM, import a text (csv) file like

User.csv:
UserName,String,Edit,50
Password,String,Edit,50

This will add a T_Class 'User' to you project. Mark it as a 'packed record'.

Now import Connection.csv:
FromIP,String,Edit,50
Started,DateTime,DateEdit

This will add a T_Class 'Connection' to you project. Mark it as a 'TObject'.

Now import Device.csv:
Name,String,Edit,50
Number,Integer,Edit
Users,Array:User,ListView
Connections,ObjectList:Connection,ListView

This will add a T_Class 'Connection' to you project. Mark it as a 'TSQLRecord'.

You have setup the model with nested DynArray/ObjectList. Alternatively you can greate quick/easy in the UI.

Each T_Variable can have a Control_Type associated to it. This is for UI generation, e.g. TEdit, TRadioGroup, etc. (Like in CSV2ORM)
This is still an 'not-good idea' as a UI mapping external to the model is needed, so you can have e.g. multiple forms where 'Device.Name' get TEdit or TLabel on one form, TCombobox on another, etc.

B)TEMPLATING (TSQLTemplate):
Similar to CSV2ORM, but more powerfull, using Mustache templates that can be edited in a JvHLEditor with syntax highlighting for many languages.
Here you will be able to setup multi-file templates (like in CSV2ORM) to create e.g.:

  • mORMot Data units/classes

  • Delphi units/forms

  • SMS forms (?)

  • HTML pages

  • SQL-scripts

  • Future idea: form creation, i.o.w. WYSIWIG

C)SCRIPTING (TSQLScript):
Also with HLEditor, able to create Pascal scripts (JvInterpreter) or Javascript (SpiderMonkey).
This code might be run in JvInterpreter or SpiderMonkey, but is intended to be able to create code snips that might be used in Templating.

Summary:
The notion of data, templates and scripting evolved naturally into a kind of model/view/controller concept, and the project's idea is still in 'alpha' phase.
I would like any ideas/comments if anyone find it interesting and have some insights that might be helpfull or thought-provoking.

I can see it possible to create a bare-bone client app that get only TSQLProject, TSQLTemplate, TSQLScript from server and can create it's own UI, scripts, etc. from that.
I.o.w. a client (and/or server) Delphi-app that is just a shell that generate UI-elements and can update without closing as forms/scripts is not compiled but sent from server via TSQLProject, TSQLTemplate, TSQLScript classes.


Regards
AntonE

PS: I should have part A (data modelling) finished in next day or two.

#39 Re: mORMot 1 » How to implement a TSQLRecord descendant w a property of TObjectList ? » 2014-07-31 10:04:57

Thank you very much, it's working one level deep. smile
Test project here:
ftp://ftp.true.co.za/TestORM.zip

If compiled as-is it works, compile with conditional directive TWOLEVELS to make another TObjectList within a TObject class and it fails to persist even first level.
JSONvalues looks right when updating but I'm a bit lost 'deeper inside' mORMot yet.

This can be very powerful.

#40 Re: mORMot 1 » How to implement a TSQLRecord descendant w a property of TObjectList ? » 2014-07-30 11:50:09

I would really like to use TObjectList as it makes LiveBindings easier for nested (sharded?) objects.
I have my objects defined as this and register the ITem class:

uses mORMot,SynCommons,Contnrs;


type TItem       = class(TObject)
                    private
                     fItemName: RawUTF8;
                     fItemCode: Integer;
                    published
                     property ItemName   : RawUTF8 read fItemName write fItemName;
                     property ItemCode   : Integer read fItemCode write fItemCode;
                   end;
type TSQLNested  = class(TSQLRecord)
                    private
                     fName: RawUTF8;
                     fItems: TObjectList;
                    public
                     constructor Create;
                    protected
                     destructor Destroy;override;
                    published
                     property Name  : RawUTF8     read fName  write fName;
                     property Items : TObjectList read fItems write fItems;
                   end;

function CreateDataModel: TSQLModel;

implementation

function CreateDataModel: TSQLModel;
begin
 result := TSQLModel.Create([TSQLNested]);
 TJSONSerializer.RegisterClassForJSON(TItem);
end;

But I still get error:
Unhandled stfUnknown/tkClass type for property Items.
Seems unrelated to TItem and it does not like the TObjectList. Also tried with Generics.Collections version.

#41 Re: mORMot 1 » How to implement a TSQLRecord descendant w a property of TObjectList ? » 2014-07-29 23:47:34

Hello.
Is this still the case? On page 112 of SAD 1.18 it says "The following published properties types are handled by the ORM..." and lists TObjectList.
Or am I misunderstanding it?

#42 Re: mORMot 1 » Class and form generating tool » 2014-07-28 10:09:42

Hi Arnaud,
yes CDS is also painfully slow but I like the briefcase-model/changelog so I still use it for now.

ClientEngineU.pas is just a unit where I centralize client components, basically where TSQLRestClient descendant resides so users should just edit that code to point to their TSQLRestClient unit/component. I'll make next version better commented and generic. + included sample template should be changed to generate any different unit/form/file you want. smile
Can now also generate non-DB components so I should be able to write a similar Livebinding template if needed, instead of CDS/Datasource-based form.

I never really planned this project, so a complete re-think might be needed for it to be a serious/proper tool...
I never worked with Mustache and thought it is just for HTML/JS. I'll check it out some time and revamp this, thank you.

Best regards
AntonE

#43 Re: mORMot 1 » Class and form generating tool » 2014-07-28 08:05:59

Updated version 1.1 can be found on:
ftp://ftp.true.co.za/CSV2ORM1_1.zip

I included the compiled binary so users can use/test if they don't have Jedi library to compile.
Now supports:
Multiple templates with multiple files for each template, e.g. a form generates .pas & .dfm file.
Template-code editing in app. (Need to install syntax highlighter smile )
Comes with sample templates & CSV, just run and test.
Can generate different code for fields/properties/controls that have size limits (Strings) by using [Size] & [!Size] tags in template.

Still scruffy but a lot more versatile.
If anyone want a specific feature or find bug, please let me know.
Regards


Basic explanation:
Create code like:

type TSQLMyObj = class(TSQLRecord)
                          private 
                          [Fields]fMyName : MyType;[/Fields]
                          published
                          [Fields]property MyName : MyType  read fMyName write fMyName;[/Fields]
                          end;

or
[Controls] object LabelMyName: TLabel
    Left = 56
    Top = MyTop
    Width = 23
    Height = 13
    Alignment = taRightJustify
    Caption = 'MyName'
  end
  object MyControlName: MyDBControl
    Left = 84
    Top = MyTop
    Width = 121
    Height = 21
    DataField = 'MyName'
    DataSource = DS
  end[/Controls]

and it will expand to the properties/fields/controls you pass in CSV file.
It still needs a lot of changes but it's a good start and sufficient to create bulk of my repetitive code.

"MyObj" get replaced with your Object-name
"MyName" get replaced with property names, etc. See ReadMe file.

#44 Re: mORMot 1 » Class and form generating tool » 2014-07-26 16:49:26

I'd be honored, sure you can include it. But I think let me make some changes first, because as-is it's kind of scruffy to do just what I wanted quick and dirty.
I'll post back here if there's a bit more versatile version.

Regards

#45 Re: mORMot 1 » Third-party Samples » 2014-07-24 21:57:31

CSV2ORM simple class/unit/form generator tool

I only saw migajek's project now, I made something similar, but with form/TClientDataset creation as well:
http://synopse.info/forum/viewtopic.php … 548#p11548

Edit: Included as third-party sample in https://github.com/synopse/mORMot/tree/ … nE/CSV2ORM

#46 mORMot 1 » Class and form generating tool » 2014-07-24 21:54:49

AntonE
Replies: 10

I just made a simple class/unit/form generator tool.
Simply you create a CSV (E.g. MyObj.csv) file like so:

Code,RawUTF8,Edit,30
Desc,RawUTF8,Edit,512
ItemType,RawUTF8,ComboBox,30
Cost,Currency,Edit
LastCostD,TDateTime,DateEdit
VatCat,Integer,RadioGroup
Active,Boolean,CheckBox

Format:<Property/Field Name>,<Type>,<Control>[,RawUTF8 size for CDS]
And it will create units:

  • DataMyObj.pas (TSQLMyObj class)

  • MyObjFormU.pas (TMyObjForm class)

  • MyObjFormU.dfm

It will also make a TClientDataset on the form and add necessary fields to it, then create TDBxxxx versions of Controls specified (Edit=TDBEdit, etc) + code to get/set it from/to the TSQLMyObj class.
It is very immature and cannot handle Arrays, subobjects, etc. but it will at least create the bulk of your code and form.
Not intended to be full generator, just to create a skeleton of code/controls that you can copy to your project and edit normally from there on. Use RawUTF8 for unsupported types and just edit your code afterwards.

I'm not going to spend lots of more time on it soon, but I can see that in future:

  • More options like combobox/RadioButton listitems, MaskEdit, break a SET up into multiple CheckBoxes, and so on.

  • I might make the code generated 'template-able' so you can have different variations of forms that can be created (TObjectList-based instead of TClientdataset, HTML/JS/etc).

  • change name to CSV2ORM. smile

Can be found here:
ftp://ftp.true.co.za/TrueORMconv.zip

#47 mORMot 1 » DynArr as TSQLrecord property » 2014-07-03 09:13:10

AntonE
Replies: 1

I really like the idea of the Dynamic arrays and packed records and it 'hashed' features, multi-sort etc. Very very nice thinking!
I'm trying to use DynArrs in my ORM classes, but maybe I'm looking at it wrong:

type TContactAttachType = set of (ifFile,itPhoto,itLogo);
type TContactAttachment = packed record
                      fAttachType : TContactAttachType;
                      fAttachID   : Integer;
                      property AttachType  : TContactAttachType read fAttachType write fAttachType;
                      property AttachID    : Integer            read fAttachID   write fAttachID;
                     end;
     TContactAttachArr=Array of TContactAttachment;

type TSQLContact  = class(TSQLRecord)
                     private
                      fName    : RawUTF8;
                      fAttach  : TContactAttachArr;
                     published
                      property Name    : RawUTF8           read fName    write fName;
                      property Attachments  : TContactAttachArr read fAttach  write fAttach;
                    end;

Very cool as I can write simple code to fill e.g. custom Dataset for UI:

 for ATT in Contact.Attachments do
  begin
   CP.Insert;
   CPName     .AsString :=ATT.Number;
   CPFile        .AsBoolean:=ptFile    in ATT.PhoneType;
   CPPhoto     .AsBoolean:=ptPhoto in ATT.PhoneType;
   CPLogo      .AsBoolean:=ptLogo   in ATT.PhoneType;
   CP.Post;
  end;

But to write/change data via the property I'm having a problem:

DA.Init(TypeInfo(TContactAttachment),Item.Attachments,@DAC);
DA.Capacity:=CP.RecordCount;

SetLength(Item.Attachments,CP.RecordCount);

Both cannot compile as I need to access the private variable of TSQLContact.fAttach?
How can I overcome this without polluting the TSQLContact with UI related code?

Or am I looking at it wrong?

Thanks
Regards
AntonE

#48 Re: mORMot 1 » Method SOA in 1.18 » 2014-07-02 18:20:45

Thank you for your kind words.
The manual as under the 'downloads' section is still 1.17
http://synopse.info/files/synproject/sampledoc.zip
But I see it further down

#49 Re: mORMot 1 » Method SOA in 1.18 » 2014-07-02 12:56:51

aha! Hybrid 1.17 & 1.18 code big_smile
Thanks.
Now I see Ctxt.Parameters as:
SearchStr=abc&Fields=ID....
But:
UrlDecodeValue(Ctxt.Parameters,'SearchStr=',zStr);
Does not fill in zStr.


Edit:
After looking at the code, I see I had to pass the parameter as UPPERCASE. Strange, no?
UrlDecodeValue(Ctxt.Parameters,'SEARCHSTR=',zStr);

#50 mORMot 1 » Method SOA in 1.18 » 2014-07-02 10:44:10

AntonE
Replies: 5

Hello, trying to implement first method service:
Server side

type TSQLRestServerDBTW = class(TSQLRestServerDB)
                           published
                            procedure ContactSearch(var Ctxt: TSQLRestServerURIContext);
                          end;

procedure TSQLRestServerDBTW.ContactSearch(var Ctxt: TSQLRestServerURIContext);
var SQL : RawUTF8;
    zStr,
    zFld : RawUTF8;
begin
 zFld:='';
 zStr:='';

 if UrlDecodeNeedParameters(Ctxt.Parameters,'SearchStr,Fields')
     then begin
           while Ctxt.Parameters<>nil do
            begin
             UrlDecodeValue(Ctxt.Parameters,'SearchStr=',zStr);
             UrlDecodeValue(Ctxt.Parameters,'Fields=',zFld,@Ctxt.Parameters);
            end;
           SQL:='select '+zFld+' from Contact WHERE Name='''+zStr+''' ORDER BY Name;';
           Ctxt.Results([ServerForm.DB.DB.ExecuteJSON(SQL)]);
          end
     else Ctxt.Error('Missing Parameter');
end;

Client side

type TSQLHttpClientTW = class(TSQLHttpClient)
                        published
                         function ContactSearch(ASearchStr:String;AFields:RawUTF8):RawUTF8;
                        end;

function TSQLHttpClientTW.ContactSearch(ASearchStr, AFields: RawUTF8): RawUTF8;
var T : TSQLTableJSON;
begin
 Result:=self.CallBackGetResult('ContactSearch',['SearchStr',ASearchStr,'Fields',AFields],TSQLContact);
end;

But when I run code from client, I get to server method, but on first line breakpoint, I see no Ctxt.fInput (most Inaccesible value) and Parameters='' so UrlDecodeNeedParameters gives AV.

The samples in manual is little different for 1.17. so am I even using the correct classes (TSQLRestServerDB & TSQLHttpClient) and the rest is also a bit cloudy still. :)

Regards

Board footer

Powered by FluxBB