You are not logged in.
I beg your pardon can I find that on the mORMot docs, or in any of the samples?
Hi everyone,
I'm doing some tests with FTS search, I need to have a mORMot server which will only be accesed as localhost from a Node.js application on the same physical/virtual machine, I already have the server working and doing FTS search like this :
http://localhost:8081/root?sql=SELECT RowId, item FROM ListSearch WHERE item MATCH :('peri*'):All is working as expected but there are situations where the end user can do a search with a mispelled word e.g. changing a B with a V, or an accented spanish character e.g. i instead of í so for example if the search term would be dosi I would like the search result include also words with dosí and viceversa so I am looking for the Soundex/SoundexFR funcion mentioned on the docs, but I don't know how to ( and if ) the function can be included on a request as shown above.
Can anyone give any help with this ?
Hello everyone,
I finally found sometime to setup a linux VM and until now everything has been smooth ( fpcupdeluxe gave me big push here), now I want to make a simple daemon for querying static data I already have on a SQLite .db file, I post on this thread because it is sticked out here and I have one simple question related to linux servers.
Seems like I have to put these compiler directives on my lpr :
{$I Synopse.inc}
uses
...
{$I SynDprUses.inc}
...Will that be enough ? Or there is any other directive I have to add
I'm working with current trunk ( Lazarus & FPC ) and the version mORMot which TestSQL3 reports is:
Using mORMot 1.18.3765 FTS3
Running on Linux-4.4.0-88-generic #111-Ubuntu SMP Thu Jul 20 09:32:39 UTC 2017
TSQLite3LibraryStatic 3.19.2 with internal MM
Generated with: Free Pascal 3.1.1 MOP 64 bit compilerThank you
Well this was kind of urgent and I know everybody here are pretty busy people, I passed the task to the existing TCP (non mormot) server and stored the user info on a legacy database, but STILL it would be nice if someone can enligthen me on how can one work with the SQLite database from SERVER code and in particular in this use case, I did some tests from client code and is pretty easy but not in this case, I couldn't use a TSQLRestclient in sessionCreated event because, well the TSQLRestclient needs to authenticate and that would fire sessionCreated again and that give us an ugly loop of events.
Regards
Hi,
I'm having a hard time trying to store/retrieve additinal user info, I have an TSQLHttpserver which is serving interface based services, and because I'm consuming data from another TCP server didn't have the need for storing retrieving info from SQLite, the groups and users are stored in a SQLite file to take advantage of the mORMot authentication, this database is populated at server startup using the ORM, everything is working well so far, but I have the need to store the date time (just an example) of user login, so I created an inherited TSQLAuthUser class :
TSQLMyAuthUser = class(TSQLAuthUser)
protected
FLastAccess : TDateTime;
published
property LastAccess : TDateTime read FLastAccess write FLastAccess;
end;Then added:
class function TSessionmORMot.sessionCreated(Sender: TSQLRestServer;
Session: TAuthSession; Ctxt: TSQLRestServerURIContext): boolean;
var
myUser: TSQLMyAuthUser;
begin
myUser := TSQLMyAuthUser(Session.User);
myUser.LastAccess := Now;
TSqlRestserver(sender).Update(myUser);
Result := False;
end;
restServer.OnSessionCreate := TSessionmORMot.sessionCreated; // restServer is TSQLRestServerDBSeemed to work fine, I can see populated the field LastAccess on the db file, but after two different users log in I have an error like this :
20170201 04062437 EXC ESecurityException {"Message":"Invalid TAuthSession.Create(TSQLRestRoutingREST,TSQLMyAuthUser)"} at 0054EB90 stack trace ...
Obviously that doesn't seem to be the right way, I was hoping that I would have access to the new field on my Interface based services with the following code ( recommendations are welcome ) :
var
context : TServiceRunningContext;
user : TSQLMyAuthUser;
theDate : TDateTime;
Begin
context := CurrentServiceContext;
user := TSQLMyAuthUser.Create(context.Request.Server, context.Request.SessionUser);
theDate := user.LastAccess;
EndSo can a mORMot guru give me some advice on how to store safely the additional data and how to retrieve it from a service ?
Thank you all
@AOG
Many people are interested in the mORMot / FPC combi. If we help them, they will become mORMot users.
Many have difficulty with cross-compiling. If we help them, they will become mORMot/crossFPC users.
mORMot is now fully cross-platform. mORMot running on Linux64 is a MAJOR plus.
I am, please go on
@AB
We need some clear instructions, though, for beginners/reviewers of the FPC+Lazarus+mORMot solution.
A one-pass setup, with no manual modification whatsoever could be a big live changer!
Agreed, I'm ready to give it a shot if you need some feedback
@hnb
it is still FPC, NewPascal is just fork name with full credits for FPC and with full backward compatibility for the official FPC. We need to somehow distinguish between FPC and the FPC dedicated for our purposes.
Great! I like that too, compatibilty is dead serious, this is all very exciting I'll be watching the progress ![]()
Seems like there is a better future for SMS, time will tell:
https://jonlennartaasenden.wordpress.co … le-studio/
Merry christmas to you all !
Thank you Arnaud
, I think we can go Windows first and following your advice I'll begin to research on the linux side of things later
Hi to all,
I know that support for Lazarus + FPC is not finished yet, but I'm looking more seriously to use FPC for my server code, and although I'm still coding 100% on Delphi + Windows I was wondering if I can have a server compiled with FPC to replace an existing interface based server which is serving https requests on a windows machine, so my questions are :
1. Can I serve https requests on Windows with a FPC + mORMot compiled binary ? I guess it has the same http.sys kernel-mode server support but I'm interested to hear experiences from others
2. Can I have a similar setup on Linux (I mean serving https requests) ?
3. If answer to number 2 is no, how far do you think is mORMot from doing same task on Linux ? ( I'll be just fine with windows, but I'm looking forward to linux server support )
Thank you
Feliz navidad para todos !! Y que el año próximo traiga lo mejor.
About sortable unique ID's there is this blog post from Rob Conery which shows a way to solve it, although is implemented as a PostgreSQL function and DB Schemas maybe you could borrow some concepts ?
http://rob.conery.io/2014/05/29/a-bette … ostgresql/
Regards
not, it not working 'C:\Program Files\PostgreSQL\9.3\bin\libpq.dll'
I copied libpq.dll and libintl.dll into my app folder and all is working fine, are you sure these files are in a path discoverable by your application?
30 - MVC Server from today(ZEOSLIB 7.2 Revision 3465), also works with Firebird 3.0 smile
Michal
Hi Michal, did you noticed any performance differences with FB 3.0 vs FB 2.5 ?
Great! seems like you are always one step forward
Note that this sample is tuned for a sqlite db or a MongoDB nosql instance.
External db would be less efficient for instance about the tags dynamic array, which flies on internal sqlite but would be slower with external db, since it uses a blob field.
I don't want to bother you with this because I know mORMot is muilti-db and you must limit yourself to the lowest common denominator and I am ATM more interested on PostgreSQL support and maybe other people don't care about it, but I have to say it, have you seen the soon to be released 9.4 version and his JSON/JSONB support?
http://opensourceconnections.com/blog/2 … xtensions/
http://blogs.enterprisedb.com/2014/09/2 … r-reality/
I don't know what level of support for this feature will be on Zeos ( hello EgonHugeist
), FireDAC or UNIDAC (I still don't explore this on my own) but it could be worth to take a look at it and perhaps in the future we can have some of these niceties on our little mORMot ?
For BeDelphi in November, I would like to show some real sample in real time. I may write a new "main sample", for a real use case, to show how ORM/SOA (and MVC) is implemented with mORMot.
Great! I'd like to see that sample, please keep us informed when it happen
Googling around you can find some posts like this:
https://lonewolfer.wordpress.com/2011/10/11/side-track/
On the comments there is also a reference to another and so on:
http://weblambdazero.blogspot.mx/2011/0 … actor.html
It's been a long time since then but maybe is worth that you take a look at those.
What do you think of using http://gwan.com/ as our HTTP server under Linux?
Sounds like a great and proven system, to be used instead of http.sys (which sounds the best under Windows) and any FastCGI processes (e.g. Apache/NGinx/Lighttpd) under Linux.
Take a look at http://www.wikivs.com/wiki/G-WAN_vs_Nginx
mORMot already runs on Linux (OSS) under Lazarus/FPC (OSS) G-WAN is closed source, so if I may I would prefer a server technology based also on OSS ![]()
Hi Thomas,
Make sure you download mORMotNightlyBuild.zip after uncompressing you will find the folder "SQLite3\Samples" which is what you are asking for, also make sure to download the latest SAD Synopse mORMot Framework SAD 1.18.pdf .
Enjoy it!
Edit: Also don't forget to download the latest SQLite3 .obj files from sqlite3obj.7z
Hi,
I'm bumping this thread because I have an issue with DataSetToJSON and I thought this was the best place.
First, some background: I have a project made with mORMot and Delphi 2007 which is running fine on production, basically it gets data from another application server (via some RPC calls), the former server return the data as memory datasets (TDataset descendant) these dataset are getting the records from a Firebird 2.5 database and the mORMot application server is mainly exposing the datasets as JSON using DataSetToJSON and everything is running as expected.
Now to the problem, I have been asked to port the project to Delphi XE3 and it compiles fine with no error whatsoever but a minor glitch on some strings, e.g.:
GARANTÍAThe former text is on a field of type string (ftString), debugging and setting a breakpoint on line 497 (SynVirtualDataset.pas) :
W.AddAnsiString({$ifdef UNICODE}AsAnsiString{$else}AsString{$endif},
twJSONEscape);I can see the "AsString" or "AsAnsiString" give me the correct string, but after "W.AddAnsiString(..." the string changes to :
GARANTÃAATM the only way I can see the right char on the JSON output is if I change the former code to :
W.AddShort(AsAnsiString); // or W.AddShort(AsString)But then I could lose data on some long strings, so I am looking for a definitive solution.
Any hints?
The environment:
Synopse framework: 1.18.381
wSeven_64 with code page 1252
SQlite3 engine: 3.8.6
Delphi XE3 compiler
Edit: The codepage on the firebird database is: ISO_8859_1, but I'm not making direct queries from mORMot, the data is queried from other software and I'm only consuming the returned datasets.
Hi Arnaud,
I found sometime to dig deeper on the failed tests, the TestSQL3 program is failing at first at p line 8576 (SynSefTests.pas) :
n := 0;
while RInt.FillOne do begin
if RInt.fID<100 then // some real entries for backup testing
aExternalClient.Add(RInt,true,true);
RExt.Data := RInt.Data;
RExt.FirstName := RInt.FirstName;
RExt.LastName := RInt.LastName;
RExt.YearOfBirth := RInt.YearOfBirth;
RExt.YearOfDeath := RInt.YearOfDeath;
{$ifndef NOVARIANTS}
RExt.Value := ValuesToVariantDynArray(['text',RInt.YearOfDeath]);
{$endif}
RExt.fLastChange := 0;
RExt.CreatedAt := 0;
if RInt.fID>100 then begin
if aExternalClient.BatchCount=0 then
aExternalClient.BatchStart(TSQLRecordPeopleExt);
aExternalClient.BatchAdd(RExt,true);
end else begin
aID := aExternalClient.Add(RExt,true);
Check(aID<>0);
Check(RExt.LastChange>=Start); // <--------- HERE!Values
aID = 1
RExt.LastChange = 135197975833
Start = 135197975833
aID = 2
RExt.LastChange = 135197955540
Start = 135197975833
The test fails when aID > 1 don't know if this behaviour rings a bell for you.
What do you think?
My current tests status:
2.8. External database:
- TQuery: 2,003 assertions passed 7.83ms
- External records: 2 assertions passed 877us
- Auto adapt SQL: 624 assertions passed 31.56ms
- Crypted database: 253,275 assertions passed 167.23ms
! - External via REST: 21,893 / 168,339 FAILED 1.21s
! - External via virtual table: 21,893 / 168,339 FAILED 1.82s
! - External via REST with change tracking: 22,904 / 178,439 FAILED 2.55s
- JET database: 7,007 assertions passed 987.85ms
Total failed: 66,690 / 778,028 - External database FAILED 6.79sSynopse framework used: 1.18.346
Running on wSeven_64 with code page 1252
SQlite3 engine used: 3.8.6
Generated with: Delphi XE3 compilerTime elapsed for all tests: 73.65s
Tests performed at 17/10/2014 05:18:22 p.m.
Total assertions failed for all test suits: 66,690 / 17,544,492
! Some tests FAILED: please correct the code.
Regards
I understand because I been there ;-), unfortunately I only have 2007, XE and XE3 and the tests previously ran fine, right now I don't have the time but maybe in a few weeks I can download a Delphi XE7 trial version and see what will happen there
Thanks for taking a look at this
Yes I am
UPDATE: Nightly build from today, same tests failed:
Synopse framework used: 1.18.290
SQlite3 engine used: 3.8.6
Generated with: Delphi XE3 compilerI don't have a single problem with my mORMot production code, I'm just reporting TestSQL3 Behavior :-)
From the log with detailed map info
20140925 13064013 EXC EInterfaceFactoryException ("Invalid TInterfacedObjectFake.FakeCall() for ICalculator.Add: TInterfaceStub returned error: expected exception") at 001B1787 mORMot.RaiseError (36492) stack trace 002ACCF7 mORMotSelfTests.SQLite3ConsoleTests (198) 0000662C System.@StartExe
20140925 13064013 EXC ESynException ("expected exception") at 001B6850 mORMot.TInterfaceStub.Invoke (37902) stack trace 002ACCF7 mORMotSelfTests.SQLite3ConsoleTests (198) 0000662C System.@StartExe
20140925 13064111 fail TTestExternalDatabase(0084A950) External database: External via REST "" stack trace API 002905BD SynSelfTests.TTestExternalDatabase.Test (8503) 0028DD2B SynSelfTests.TTestExternalDatabase.ExternalViaREST (8085) 002ACCF7 mORMotSelfTests.SQLite3ConsoleTests (198)
20140925 13064111 fail TTestExternalDatabase(0084A950) External database: External via REST "" stack trace API 0029091B SynSelfTests.TTestExternalDatabase.Test (8525) 0028DD2B SynSelfTests.TTestExternalDatabase.ExternalViaREST (8085) 002ACCF7 mORMotSelfTests.SQLite3ConsoleTests (198)
20140925 13064111 fail TTestExternalDatabase(0084A950) External database: External via REST "" stack trace API 002905BD SynSelfTests.TTestExternalDatabase.Test (8503) 0028DD2B SynSelfTests.TTestExternalDatabase.ExternalViaREST (8085) 002ACCF7 mORMotSelfTests.SQLite3ConsoleTests (198) Call stack on first fail when running from IDE with debugging:
SynCommons.TSynLog.DebuggerNotify((...),'Test failed %')
SynCommons.TSynTestCase.TestFailed('')
SynSelfTests.TTestExternalDatabase.Test(True,False)
SynSelfTests.TTestExternalDatabase.ExternalViaREST
SynCommons.TSynTests.Run
mORMotSelfTests.SQLite3ConsoleTests
TestSQL3.TestSQL3
:760b1174 kernel32.BaseThreadInitThunk + 0x12
:7753b3f5 ntdll.RtlInitializeExceptionChain + 0x63
:7753b3c8 ntdll.RtlInitializeExceptionChain + 0x36Does it help ?
UPDATE: Downloaded latest version:
2.8. External database:
- TQuery: 2,003 assertions passed 6.38ms
- External records: 2 assertions passed 512us
- Auto adapt SQL: 448 assertions passed 19.22ms
- Crypted database: 253,275 assertions passed 155.50ms
! - External via REST: 21,893 / 168,346 FAILED 1.31s
! - External via virtual table: 21,893 / 168,346 FAILED 2.38s
! - External via REST with change tracking: 22,808 / 178,446 FAILED 2.47s
- JET database: 7,007 assertions passed 920.15ms
Total failed: 66,594 / 777,873 - External database FAILED 7.27s
Synopse framework used: 1.18.281
SQlite3 engine used: 3.8.6
Generated with: Delphi XE3 compiler
Time elapsed for all tests: 72.12s
Tests performed at 25/09/2014 09:28:31 a.m.
Total assertions failed for all test suits: 66,594 / 17,532,744
! Some tests FAILED: please correct the code.So I got the same behavior with latest sources on the TestSQL3 just FYI.
Is it just me? Now I tested with 3 different PC's (two with XE3 and 1 with XE)
Well I must be blind, here you are :
Synopse framework used: 1.18.275
SQlite3 engine used: 3.8.6
Generated with: Delphi XE compilerSame with XE3
I downloaded both (mormot and sqlite) files at the same time I suppose they are the latest, can't see version number on file properties how can I check that?
Hi folks,
I'm setting up a new machine Windows 7, Delphi XE3 and mORMot nightly build 2014-09-23_221033_ada8020315 just for the sake of check I ran TestSQL3 ( TestSQL3Register first )
2.8. External database:
- TQuery: 2,003 assertions passed 8.82ms
- External records: 2 assertions passed 612us
- Auto adapt SQL: 448 assertions passed 25.88ms
- Crypted database: 253,275 assertions passed 137.00ms
! - External via REST: 21,893 / 168,346 FAILED 1.26s
! - External via virtual table: 21,893 / 168,346 FAILED 2.33s
! - External via REST with change tracking: 22,814 / 178,446 FAILED 2.38s
- JET database: 7,007 assertions passed 697.57ms
Total failed: 66,600 / 777,873 - External database FAILED 6.88sThere are three failed tests, the log has the following:
20140924 15592341 EXC EInterfaceFactoryException ("Invalid TInterfacedObjectFake.FakeCall() for ICalculator.Add: TInterfaceStub returned error: expected exception") at 0064AE5F stack trace 00526B38 0074BC03 0040AF64 007537C1 75C833CA 77509ED2 77509EA5
20140924 15592341 EXC ESynException ("expected exception") at 006501F4 stack trace 00526B38 0074BC03 0040AF64 007537C1 75C833CA 77509ED2 77509EA5
20140924 15592423 fail TTestExternalDatabase(003CAA40) External database: External via REST "" stack trace API 00536DAE 0053C04B 00525AAD 0072DE64 0072B81B 00526B38 0074BC03 007537C1 75C833CA 77509ED2 77509EA5
20140924 15592423 fail TTestExternalDatabase(003CAA40) External database: External via REST "" stack trace API 00536DAE 0053C04B 00525AAD 0072E1C2 0072B81B 00526B38 0074BC03 007537C1 75C833CA 77509ED2 77509EA5
...I can see the same behavior on Delphi XE.
Has anyone else seen this ?
I have to agree with Michael about generating ID's at the database level and if the database does not have an internal mechanism we can always fallback to the "select Max(ID)", but of course Arnaud has the last word on this; I think it will always be "safer" to let the database handle that job also I want to be very careful here, that doesn't mean I'm against AB approach it is just to let you know how I think about this if I may :-)
Hi moctes,
I've modified esmondb's code by adding a field to SynAuth:
.
.
.
Hi Jerry,
I used RangerX code without problems on that occasion and I have been using it on production since then but I will make some time to check esmondb's with your suggested tweaks.
Regards.
AFAIK you can do this
var
context: TServiceRunningContext;
user: Integer;
Begin
context := CurrentServiceContext;
user := context.Request.SessionUser;
End;Regards
Yes, in console mode, the key has to be fetched directly from our loop.
It is mandatory to let Synchronize() work as expected, i.e. let some process be executed in the main thread.You could change the ConsoleWaitForEnterKey; call by a Readln; if you do not use any option to force execution in the main thread.
Tested, with readln the application ends immediately
About the "file still in use" I've never seen this.
Could you try with the ProcessExplorer tool (from SysInternals) to find out what is happening at this time.
Also enable the logs and check what is on, according to the timestamp.
Will check with ProcessExplorer, sometimes I can run the project twice on a row but a third try gives me
[dcc32 Fatal Error] F2039 Could not create output file '.\Win32\Debug\httpservice_lx.exe'Some lines that came to my attention on the log file:
20140820 16543205 + TSQLDBZEOSStatement(0092D410).007DE22C
20140820 16543205 SQL TSQLDBZEOSStatement(0092D410) CREATE UNIQUE INDEX NDXPaisID ON public.Pais(ID)
20140820 16543205 EXC EZSQLException ("SQL Error: ERROR: Relation «ndxpaisid» already exists") at 0073C170 stack trace API 00520B5C
20140820 16543205 - 00.002.897This is appearing on the second and subsequents runs (the first run created the tables) I suspect
RestServerDB.CreateMissingTables(0);is the culprit, I getting this for every table index of the model per database/schema (it isn't causing troubles but is in the log) and that includes the Authorization tables.
The following code :
Server := TSQLHttpServer.Create('8080',aServidores,'+',useHttpApiRegisteringURI);
TSQLLog.Add.Log(sllInfo,'Server % started by %',[Server.HttpServer, Server]);register this on the log:
20140820 16552547 info Server null started by nullI don't know if "null" is what should be on the log, btw "Server" is not null
The server does run and also get the job done, just wanted to point your attention to the previous messages, maybe I'm still missing something.
Hi,
I took the sample "10 - Background Http service" as a basis for a Windows service, for manual testing and debugging I am running the project with the "-c" parameter, and I have no problem at all, but I can see a weird behavior when I press the Enter key on the console window sometimes the window won't close right away and I need to keep pressing the enter key a few more times until the window is closed and the process terminated, although it is a little annoying I don't have a problem with that, but what really bothers me is that when I try to run the project again the Delphi IDE will complain it can't create the .exe file which seems to be still in use, I can go to the .exe folder and manually delete the file but if I refresh the folder, then the exe "magically" appears and I can keep deleting the file and it will keep appearing for a while, eventually it would be effectively deleted and I would be able to run it again, I have checked with the Unlocker utility and it doesn't report that te file is blocked by any application :-|
Anyone else is seeing this behavior ? May be is something normal but it hinders the work :-( I would like to know if it is a problem that can be solved or is simply the way that things work.
P.S. Environment: Delphi XE3, Windows 7 64, Testing is done compiling for 32 bits.
Ohh ! I can see clearly now, so there is a pool of 32 threads by default (correct me if I'm wrong) and once I have reached this number of instances they are being reused! Tested and checked, you are as always right.
Thank you for the clarification.
I'll need to investigate more, I'm creating 3 TSQLRestServerDB instances in a demo application and one postgres instance for each TSQLRestServerDB is being created also by mORMot which seems correct to me, I was thinking that each instance of TSQLRestServerDB will route the incoming requests through one of these 3 already created postgres processes, something like:
TSQLRestServerDB Instance 1 <---> TSQLDBZEOSConnection <---> postgres process 1
TSQLRestServerDB Instance 2 <---> TSQLDBZEOSConnection <---> postgres process 2
TSQLRestServerDB Instance 3 <---> TSQLDBZEOSConnection <---> postgres process 3So when I make a request on the browser and the url is routed to one of the TSQLRestServerDB instances it would be reusing the DB connection already created (kind of a DB connection pool) but what I'm seeing is a new db connection (TSQLDBZEOSConnection) is created for each page refresh on the browser (yes, using the very same url every time).
I can see on SynDBZeos.pas that the following code gets executed:
function TSQLDBConnectionPropertiesThreadSafe.ThreadSafeConnection: TSQLDBConnection;
...
result := NewConnection;and Newconnection is as follows:
function TSQLDBZEOSConnectionProperties.NewConnection: TSQLDBConnection;
Begin
result := TSQLDBZEOSConnection.Create(self);
End;Thus what is happening is a new connection is being created each time :
TSQLDBZEOSConnection <---> postgres process 4
TSQLDBZEOSConnection <---> postgres process 5
TSQLDBZEOSConnection <---> postgres process 6
...Maybe I'm wrong on my understanding of who the "client" is, this is what I thought was happening :
Client <------> TSQLHttpServer instance <----> | TSQLRestServerDB Instance 1 <------> postgres process 1
(browser) | TSQLRestServerDB Instance 2 <------> postgres process 2
| TSQLRestServerDB Instance 3 <------> postgres process 3I'm considering the browser the "client" of the TSQLHttpServer instance, and the former as the "client" of the TSQLRestServerDB instances which in turn are "client" of the already created postgres processes but it looks like if no connection created at first is being "reused".
I don't know if my english is good enough to make my case, I hope you can understand what I mean :-)
One question about database connection, I made a test with 3 TSQLRestServerDB instances, after creating them I can see on windows task manager processes 3 new postgres.exe processes, which I think is fine, but each request (eg. http://localhost:8080/lxapp.mormot.public/pais/1) is creating a new postgres.exe process, don't know if it is correct or if there is some setting I am missing.
Any thoughts ?
I have to say this, your framework is AWESOME!
I had to tweak my classes because I realized I shouldn't be freeing Props and Model instances, also used TRawUTF8List as suggested and as you said I don't need tho free the owned objects by hand, no memory leaks so far and now I can retrieve data using URIs which includes the database + schema
I'm enjoying working with mORMot, at first it looks complicated but once you get used to it, is really easy.
You are searching FDBServers.IndexOf( FullSchemaName ) but you do later on FDBServers.AddObject(aSpec.DBSchema, DBServer).
It should be FDBServers.AddObject(FullSchemaName, DBServer) IMHO, to be consistent.
Good catch!
There is one big issue with your code: you are using a single TSQLModel instance for all your servers.
This is not correct: each DB server should have its own TSQLModel.
That's the kind of thing I need to be aware of, thanks for the advise.
Just a detail: you may use TRawUTF8List instead of TStringList, to avoid any string conversion issue.
Good to know you have a dedicated class :-D I'll change it.
Note that since you defined the same "root" value for all DB servers, you would NOT be able to add the DB servers to the main HTTP server instance.
There would be a conflict of duplicated "root".
But if you want to use the DB servers from services, sounds fine to me.
I was originally thinking of retrieving data only from services, but you just gave me another idea which I'm going to work on.
THANK YOU !
This is what I have so far:
type
TlxServerSpec = record
ServerType: TSQLDBDefinition;
Host,
Port,
DBName,
DBSchema,
User,
Pass : RawUTF8;
end;
TlxServerList = class
private
FDBServers : TStringList;
public
constructor Create;
destructor Destroy;override;
procedure Add(aSpec: TlxServerSpec; aModel: TSQLModel);
function GetServer(schemaName: RawUTF8): TSQLRestserverDB;
end;
implementation
const
SCHEMA_SEPARATOR = ':';
{ TlxServers }
procedure TlxServerList.Add(aSpec: TlxServerSpec; aModel: TSQLModel);
var
props : TSQLDBZEOSConnectionProperties;
DBServer: TSQLRestServerDB;
FullSchemaName,
portStr : RawUTF8;
begin
//Own convention, separating DB from schema with :
FullSchemaName := aSpec.DBName + SCHEMA_SEPARATOR + aSpec.DBSchema;
if FDBServers.IndexOf( FullSchemaName ) >= 0 then
Exit; // a server for the schema already exists
if aSpec.Port<>'' then
portStr := ':'+aSpec.Port;
Props := TSQLDBZEOSConnectionProperties.Create(
TSQLDBZEOSConnectionProperties.URI(aSpec.ServerType, aSpec.Host+portStr),
aSpec.DBName, aSpec.User, aSpec.Pass);
Props.ForcedSchemaName := aSpec.DBSchema; // <--- Not recommended by MPV
VirtualTableExternalRegisterAll(aModel,Props);
try
DBServer := TSQLRestServerDB.Create(aModel,':memory:',false);
DBServer.CreateMissingTables(0);
FDBServers.AddObject(aSpec.DBSchema, DBServer);
finally
Props.Free;
end;
end;
constructor TlxServerList.Create;
begin
FDBServers := TStringList.Create;
end;
destructor TlxServerList.Destroy;
var
i: Integer;
begin
for I := 0 to FDBServers.Count-1 do
TSQLRestServerDB(FDBServers.Objects[i]).Free;
FDBServers.Free;
inherited;
end;
function TlxServerList.GetServer(schemaName: RawUTF8): TSQLRestserverDB;
begin
Result := TSQLRestServerDB( FDBServers.Objects[FDBServers.IndexOf(schemaName)] );
end;I can create a global instance of the previous class when starting the server like this :
var
Model: TSQLModel;
sSpec : TlxServerSpec;
begin
Model := TSQLModel.Create([TSQLPais, TSQLCliente]);
try
FDBServerList := TlxServerList.Create;
//Populate the list of physicaldb/schemas from a SQLite db maybe, still not decided
sSpec.ServerType := dPostgreSQL;
sSpec.Host := 'localhost';
sSpec.Port := '5432';
sSpec.DBName := 'mormot';
sSpec.DBSchema := 'public';
sSpec.User := 'postgres';
sSpec.Pass := 'mypass';
FDBServerList.Add( sSpec, Model);
sSpec.ServerType := dPostgreSQL;
sSpec.DBName := 'test';
FDBServerList.Add( sSpec, Model);
finally
Model.Free;
end;
end;Before I go further I would like to hear why MPV doesn't recommend using ForcedSchemaName, I'm planning to follow his advice and create roles for the schemas for security reasons, but I would also like to have explicitly stated on each connection what Schema to use.
What do you think?
Thank you Arnaud,
I can see both requests could be useful for my purposes I'll keep following the progress of the threads, and int the meantime I'm going to try to make a proof of concept and post the code here, may be others find it useful or of course point out the flaws.
Thanks Arnaud and MPV, I can see both approaches are at connection level, so if I have a shared TSQLRestServerDB instance on the server I wont be able to change the schema based on the client who did the request (which is my intention).
I have used mORMot on a server which act as a proxy between a delphi middleware and a Titanium Appcelerator mobile application with success, and now I'm beginning with the ORM part and enjoying the tremendous work of AB so far, I think I can solve the issue with an array of TSQLRestServerDB and access them using Interface based services, What do you think?
Hi,
As the title says, I'm failing to find how can I use postgresql database schemas in addition to the 'PUBLIC' one, is a very neat feature of Postgres and one of the reasons why we have chosen this database, the plan is to have a multitenant database for an application provided under the SAAS model.
Has anyone used SCHEMAS with mORMot and PG ?
@edwinsn
The more I think about it, the less I would make the server part compatible with Linux, unless Delphi supports this platform officially.
We can afford cheap Windows hosting for our mORMot server projects - no need to have a huge configuration: it uses much less resources than the IIS/MSSQL/.Net/WCF stack.
The time spent on refactoring the code would be higher for us than our hosting costs.
It is sad to hear that but I understand, I'm researching right now hosting options, I'm undecided between Dedicated Server/VPS or some cloud computing offerings like Amazon (btw the cheaper options on Amazon AWS are for Linux)
Amazon has many attractive options out of the box, their windows pricing is just too expensive for us; I'm not convinced in general with the pricing but on the DB side (RDS) I will feel better with the high availability service, automated backups, pre-configured parameters, automatic software patching etc. we are not many people and that kind of service means less effort on our side to have our solution working.
What are others doing?
What do you think of a combo VPS/Amazon RDS (PostgreSQL), Won't that defeat the performance gains of mormot because of the added latency to Amazon RDS? I'm going to start with the Amazon AWS free tier and then compare with a Cheap VPS/Dedicated but if anyone wants to share their experiences I would love to hear how they are doing.
Regards,
Mocte
Thank you Arnaud,
If anybody ever needs to do this the working code is as follows :
function TServiceCustomers.GetReport(idReport: Integer): TServiceCustomAnswer;
var
reportFileName: RawUTF8;
begin
// some custom logic to locate the right file
result.Header := HEADER_CONTENT_TYPE + HTTP_RESP_STATICFILE;
result.Content:= reportFileName;
end;Regards
Hi,
I hope this one will be easier, I'm using interface based web services and I need to send a PDF file to the client ( testing with google chrome ) I have this code on place :
procedure GetReport( idReport:Integer );
var
context: TServiceRunningContext;
begin
context := CurrentServiceContext;
context.Request.Call.OutHead := HEADER_CONTENT_TYPE + HTTP_RESP_STATICFILE;
context.Request.Call.OutBody := './reports/January.pdf';
context.Request.Call.OutStatus := 200;
end;The former code is giving the following answer on the browser :
Server Error 404: Not FoundI don't know if this is the right way to serve files, because the procedure gets executed (already tried with function instead) but the file is not arriving to the browser, I looked at the sample 09 Http Api Web Server but the sample code isn't for interface based web services, may be it is not posible?
@itSDS,
Here:
"...the preferred systems of the most clients in the world are Windows, Android, iOS, i don't know anyone who is using LINUX in practice."
I thought like you, I did a proxy server between an existing application server and some mobile apps ( android & ios made with Titanium appcelerator ) using mORMot, that work drew attention of another customer who wants a similar project and he has already infrastructure on internet, to be precise three dedicated servers that can be used to put those little mORMot servers running, but guess what? All of them are running Linux, no Windows at all, Why? because they are cheap so offering him a solution based on mORMot is harder, not impossible, we all know virtual machines I could create one an run my server there or I can suggest him to pay for another dedicated server running Windows, or perhaps another alternative? for Desktop I almost agree with you, but on the server side it would be nice (and easier) if one could compile mORMot binaries using FPC for cases like this, I presume will become more frequent for me.
I can't speak for others but I thought it was worth to say.
Nevermind, I thought this problem was related to one of mine but the URL on the GET call I was doing was wrong hence I was receiving an error.
I am also interested on the answer to this question.
Anyone?
Thanks for answering esmondb, but adding "/" causes errors like:
net::ERR_FILE_NOT_FOUNDTrying RangerX code seems like I can go farther, at least the passwordcheck is successful; I'll keep posting my findings.