You are not logged in.
You use ORM system and classes when you start with an empty system, empty database and you define tables and relations from Delphi code (ORM part),
it's also good to use it for authentication (TSQLRestServerAuthenticationDefault is quite good for Delphi server/client).
And you can mix and match, have something accessed through ORM (it goes directly to database and you never touch raw sql), or through some API, either via methods or interfaces (or both). In methods/interfaces you can use orm or you can use direct database access (for existing db outside of ORM).
mORMOt is complex because it has so many parts and systems, so just start small and see what you need at the moment, use minimal approach and later add to it.
Do you have an external (existing) database?
In that case, that connection is independent of orm or TRestServerFullMemory.
You define and use TRestServerFullMemory as a server to which clients access and request data and then retrieve data from DB and send it to clients.
var
conn: TSQLDBConnectionProperties;
conn := TSQLDBZEOSConnectionProperties.Create(
TSQLDBZEOSConnectionProperties.URI(dFIREBIRD, PrgSettings.DBServer.AsUTF, 'fbclient.dll', False),
PrgSettings.DBPath.AsUTF, PrgSettings.DBUserName.AsUTF, PrgSettings.DBPass.AsUTF);
and when you need to retrieve something:
var
json: RawUTF8;
json := conn.Execute(ASQL, AParams).FetchAllAsJSON(True);
MultiPartFormDataDecode returns false.
mORMot1 encoded multipart content has boundary twice, at the begining of section, at the and, and there's also end boundary.
So mORMot2 fails to set Result
due to this part because j is not 0:
j := PosEx(boundary, Body, i);
if j = 0 then
begin
...
result := true;
end
while mORMot1 has same check but doesn't set Result at that place.
I'm not sure if mORMot1 including boundary twice is per standard, couldn't find anything saying it cannot be written twice so likely best thing is to change MultiPartFormDataDecode in mORMot2.
mORMot2 cannot decode content encoded in mORMot1 with MultiPartFormDataAddField/MultiPartFormDataAddFile, it works other way around.
Here is code to reproduce it.
MultiPartFormDataEncode in mormot1 and mormot2 adds "Content-Type: " prefix to ContentType.
If encoded data and ContentType is sent using THttpRequest.Request descendant, prefix is doubled with:
if InDataType<>'' then
InternalAddHeader(SockString('Content-Type: ')+InDataType);
So when sent to recipient ContentType will look like:
Content-Type: Content-Type: multipart/form-data; boundary=
Perhaps THttpRequest.Request should be updated to include "Content-Type:" only if InDataType doesn't have it.
I see InitCSV was removed from mORMot2 in past year, any builtin alternative for it?
https://x.com/sashayanshin/status/1799118418085380431
https://twitter.com/sashayanshin/status … 8085380431
This is not related to mORMot but since we all use PDF for various stuff it's worth mentioning I think.
Adobe seems to have changed their license terms and if I understand correctly just opening pdf with AcrobatReader gives them permanent right to use that pdf for improving their products/services, which likely means for anything. It's also not just for pdf but images, text or anything other that's used on some Adobe software.
Since pdf is de facto standard for everythhing, I'm wondering what are simple alternatives to their viewer software? I know of Foxit Readear but that's not much better to AcrobatReader.
Grid control is slow in adding records one by one, when you call BeginUpdate (and EndUpdate at the end) you're telling grid not to add/repaint record one by one but rather create all and then do a repaint. Perhaps a bit better (if you have multiple controls associated with table) Dataset.Disable(Enable)Controls
https://docwiki.embarcadero.com/Librari … leControls
Sorry, I've missed part of you using CrossPlatform unit, there's likely nothing ready for it. Try to copy GetValueByPath from SynCommons or mormot.core.variants
Try with _Safe(JsonOb).GetValueByPath(...
For web browser app built with mORMot you can look at mvc-blog or WebMustache in examples.
For accessing database I don't know if there are samples in mORMot2 but there are in mORMot1 (SynDB Explorer).
Have in mind that browser isn't great for displaying large number of rows, if your query will return more than 5k records you should consider adding same pagination or similar technique to limit records to a usable size.
This seems like server/client mistakes json as text and so escapes " with \.
Try to use RawJSON for your interface function result.
I had the same issue (same error) happening randomly while communicating to some API rest server. Never managed to find the cause: server, cliient, routers or CloudFlare. Solution I used was to reastablish connection and repeat the request.
Thanks, this will be perfect.
I'm actully not serving any json to client, it's just standard get to display object record (user for example), post to add/update it and for delete I had to add a custom DeleteUser method. Now with this change it's possible to handle all general actions (get, add, update, delete) in one method which is quite neat.
I'm using htmx library with mORMot MVC and with it client application is not bound to html FORM restrictions (GET/POST only).
Html form is not even needed (it can collect input values from a standard div) and it can issue delete request as well.
It offers some really nice features so it's possible to create complex applications without much javascript on client side.
For example when new user is added/deleted by client it can automatically append/delete it to the list, so it's not necessary to refresh whole page.
MVC right now is able to handle get and post (add/update) but it cannot handle delete request so I would like to propose to change TMvcRunOnRestServer.InternalRunOnRestServer
if Ctxt.Method in [mGET, mPOST] then
to
if Ctxt.Method in [mGET, mPOST, mDELETE] then
Or better yet allow for each of MVC methods to specify list of supported http methods
> Is that not equal to implement the OnAuthentificationFailed event available on TSQLHttpClient?
It is, with descendant class I have it solved for any application.
> When I tried that, OnAuthentificationFailed only fired when wrong credentials are inserted...
For me it definitely fails after connection is lost (restart of server for example), there are other onError events if this doesn't gets called.
Note that it it won't detect lost connection at the exact moment, it fails when connection is used for the first time after being lost.
Solution I'm using is descendant client class
TSQLHttpClientExt = class(TSQLHttpClientWinHTTP)
In the TSQLHttpClientExt.Create I have:
OnAuthentificationFailed := HandleAuthentificationFailed;
function TSQLHttpClientExt.HandleAuthentificationFailed(ARetry: integer; var AUserName, APassword: string; out APasswordHashed: Boolean): Boolean;
begin
// Will be called if wrong username/pass is sent or if client has been disconnected from server, session timeout or something similar
if Assigned(SessionUser) then
begin
AUserName := UTF8ToString(SessionUser.LogonName);
APassword := UTF8ToString(SessionUser.PasswordHashHexa);
APasswordHashed := True;
Result := True;
end
else
Result := False;
end;
MVCApp can handle many users, sessions are created as cookies and sent and stored on the client and sent back to server with new request and read from current ServiceContext.
Just wondering what's the usage for SaveContext/LoadContext in TMVCSessionWithCookies, it can only save/store single user/client cookie, what would a potential use case be?
I'm not sure then where serialization fails, is it when you have a property that writes to a record member or when you have a property that is a record?
Seems you want to have a published properties that are members of record in order to easier exchange those records, that's deinitely non standard behaviour, so it may work or not.
I would suggest to simplify design, define your orm object with fields it needs and have, use simple types for fields, (string, integer) and Variant (json object) where more complex data is required or when you need to exchange data among few classes.
AFAIK only published variables will be serialezed, your record is public variable.
Do note that you can use TDocVariantData instead of record, it's much more powerful and sometimes equally fast since it's stored as Variant and that can also be copied by reference.
Note that this works in mORMot.
Do you have control over server side application? If so you have to change there first to https.
Was your code generated through wrappers, if so after changing server side you should regenerate client wrapper again.
Good starting point would be documentation https://synopse.info/files/html/Synopse … #TITLE_491
Now it's possible to call multiple helper functions in sequence for example:
{{Upper Lower MyValue}}
However, that's not possible with if, for example:
{{if Upper MyValue,"=","VALUE"}} SomeResult {{/if}} or with
{{if {{Upper MyValue}},"=","VALUE"}} SomeResult {{/if}}
Would it be possible to enhance SynMustache to allow recursive calls to helpers?
Based on previous example, it would first perform Upper on MyVallue and then use that value to evaluate if.
ServiceRunningContext from mormot.rest.server
> Here are interesting benchmarks from Tommi on the subject too.
I've read somewhere that comparing speeds with different settings is wrong (apples/oranges) so all test should be done using same window sizes.
Following link has that test (brotli is faster for compression, zstd for decompression):
https://peazip.github.io/fast-compressi … ndard.html
Search for table marked: Fixed 128 MB window size for both algorithms
ArchiveFile is also defined as working with IInStream (see IArchiveOpenCallback) so 7z archive can fully be in memory.
But I understand what you mean, overhead of having simple buffer treatead as archive instead of compressed buffer, I think that overhead isn't large and is worth having any compression supported.
> And the 7z library we support is a dll for Windows only.
7z does have debian/linux implementation, though I do not know how compatible it is or if 7z ZS has linux support.
BTW there's also LZMA2 compression (default 7z algo), InnoSetup has Pascal implementation of it and there are some other implementation but I don't know if they're cross platform.
7z by default works on buffers/streams (IInStream, IOutStream) which caller decides how to implement, as file stream or memory stream.
Since 7z is already supported I think it would be better to check if 7z ZS is supported as well.
7z ZS supports ZTSD, brotli and other codecs and so it would give more options to users.
Brotli is also becoming more and more supported by webservers or API providers.
I've tried new mab.exe file and it does embed map info in the exe and give details for the exception.
In case of exception when map file is present, log includes details about unit name and line number but that's missing in case of embeded mab file, it only gives name of procedures.
Same happens if only mab file is present (not embedded), so I guess mab info doesn't include that level of details, is there an option to include it or that's as far as it can go?
> I have my own printer for my application. It creates a Postscript printer from which a catch the output to a .ps file and I
> throw that through ghostscript.
This is very interesting, so you kind of have your own printToPDF printer installed as part of your app.
Can you explain a bit more how you achieved it?
Is there an equivalent of map2mab in mORMot2?
Using one from mORMot1 seems to generate mab file and embed it but doesn't give detailed results (stack traces for exceptions) in logs as it does if .map file is present in application dir.
> I closely examined most of the Pascal related web development applications over a number of years, and for me the standout
> solution was Elevate Web Builder both because of it's excellent architecture, delphi like IDE and form designer, and excellent visual controls.
> So it's well worth a look (and it's very reasonably priced).
> Let me know if you need further info (I've been using it as a mORMot client for some years now).
Thanks, I've tried EWB but decided on SMS and that's abandon now.
Do you know what kind of compiler EWB uses, is it a proprietary or DWScript?
For me UI and html controls are not important, I've did it for years and it's hard to maintain or change. What I'm doing now is create UI in html with mustache template and bootstrap and so UI can be changed by others (designer) and I just focus on code side.
> pas2js seems like the right choice in current context.
Do you know is it comparable to DWScript capabilities?
> IIRC the DWSscript to javascript transpyler is not included any more in github, and it is Delphi and Windows only.
I am working on Windows so that's fine with me.
Their main page is at https://bitbucket.org/egrange/dwscript/src/master/ with mirror on github, it's still active with updates every so often.
> Depend of type of your web app. Do you really need JS?
I think so, it has to include offline mode (I'll try that via service workers) and some processing on client side.
> I build some internal projects with mormot mvc + mustache + htmx + Bootstrap5 and I will recommend to try htmx
Thanks, I've heard about htmx before but haven't tried it yet.
Do you create a method based functions on mORMot side that you call from htmx?
I'll be starting a new webbased application and idea is to use mormot mvc app for serverside with Mustache templates for UI and javascript for client side.
Main question is what others use for client side java script development? Ideally I would like to write pascal code that's compiled to JS.
In the past I've used SmartMobileStudio but since that's dead I'm looking for alternatives, I do not care about UI components since I'll handle that directly in html files.
So far I'm considering:
- pas2js, with Lazarus/Delphi as editor.
- DWScript, question is what to use as editor?
- TMS WebCore, I think it uses Delphi as editor
I would be grateful to hear about other people experience/impressions with above tools alone or in combination with mORMot, also if I should consider some other toools (preferably opensource)?
Can you get page in QR as Metafile (or EMF), if you can try to insert those with Canvas.RenderMetaFile.
I've created 7z wrapper years ago, it supports more of 7z options (GetNumberOfFormats, GetHandlerProperty2, self extracting). To create dir in 7z you have to pass empty file name, perhaps if you expose T7zWriter.AddOrReplace it could be done.
Here's my code in case someone want's to add more functionality to this implementation:
https://www.dropbox.com/s/iszoge0frqocf … er.7z?dl=0
Perhaps try with some of the available properties (check code comments for their meaning):
StandardFontsReplace := False;
EmbeddedTTF := True;
UseUniscribe := True;
UseFontFallBack := True;
Also go through code with debugger, perhaps something could give a hint on how to solve issue.
Yes, mustache is powerfull but sometimes it's simplicity is weak link. In some cases it requires creating new variables or additional processing on code side to achive something. I do think an additional MustacheEx or MustachemORM descendant could help in many areas and make it much more powerful.
Use:
<option value="111.222.333.111" {{#if host.mask="111.222.333.111"}} selected {{/if}}> 111.222.333.111 </option>
<option value="222.222.222.0" {{#if host.mask="222.222.222.0"}} selected {{/if}}>222.222.222.0</option>
On a similar note, TMVCRendererJson isn't cacheable by default while TMVCRendererFromViews.
Situation I have in practice is that I have server MVCApp that creates pages, fills it via mustache templates and it's then consumed by JS client.
JS client needs same data as server (taken from database or from some external API), it just does some additional handling with it.
Retrieving data depending on page (query) could take few seconds or more if it uses some external API. From client I'm getting data by calling same URL just with added /json param which makes MVC let it go through TMVCRendererJSON that does call same interface method as default page handler (without /json sufix). So in span of few second same method will be called twice (so twice DB call, and API call) and that's a perfect candidate for caching.
Rendering html based on json data is fast but creating that json data is slow so having caching in the first step would be quite usefull.
For example if inheritance order is changed here, make TMVCRendererJson a base and then inherit TMVCRendererFromViews from it.
That way database/API call that generates json could be cached and used several times either with different user/session or from both server that produces html page and js client that consumes raw json.
Alternative (or best both) would be to decouple TMVCRunOnRestServer.InternalRunOnRestServer from TMVCRendererJSON/TMVCRendererFromViews and allow app to specify inherited renderers for use here.
I think it would be useful to add cacheParamsWithSession that would combine caching with session data and parameters.
For example page could render different based on logged user (covered now with cacheRootWithSession) and based on logged user and parametars which is not covered right now.
> Problem with this is that we have to treat all input/output parameters of service method, getting of Ctx. very hard work!
Note for parsing input params you can use Ctx.GetInputAsTDocVariant to receive params as JSON document which is easy to parse.
Also when sending result you can do that as JSON which is easy to write/read on both server and client side.
There's no TSynCrypto declared there, here's the basic pass encrypt some string example (change TAESOFB with enryption class you need):
function AESEncrypt(const AContent, APass: RawByteString): RawByteString;
begin
Result := TAESOFB.SimpleEncrypt(AContent, APass, True, True);
Result := BinToBase64(Result);
end;
function AESDecrypt(const AContent, APass: RawByteString): RawByteString;
begin
Result := TAESOFB.SimpleEncrypt(Base64ToBin(AContent), APass, False, True);
end;
BTW you're using mORMot1 version which is in maintenance mode, there's also v2 which is actively in development.
Partials changes are not tracked, so you can try to force changes yourself (perhaps with FlushAnyCache) or change code for example I did this:
function TSynMustachePartials.GetPartial(const PartialName: RawUTF8): TSynMustache;
var
i: integer;
Temp: TSynMustache;
begin
if self=nil then begin
result := nil;
exit;
end;
i := fList.IndexOf(PartialName);
if i<0 then
result := nil
else begin
// Partial files by default in mORMot are loaded just once and then cached which is very bad
// during debugging when files are changed and it requires constant restart of the application.
// With this change we're disabling cache in debugMode.
// Note that internal partials (defined in template, not in external file) have to be loaded in a standard manner
Result := TSynMustache(fList.Objects[i]);
if DebugHook <> 0 then
begin
Temp := TSynMustache.Parse(AnyTextFileToRawUTF8(UTF8ToString(ViewsPath + PartialName + '.partial'), true));
if Temp.Template <> '' then
Result := Temp;
end;
end;
end;
Missing indices? So search during update check whole table?
It would probably be a good idea to update https://synopse.info/fossil/wiki?name=Downloads page and to include m2 info/links and m2 NightlyBuild.
Try TDocVariantData.InitJSONInPlace(pointer(AnyTextFileToRawUtf8(FilePath)));
Just try to parse that file and check if you get expected results, you can use TDocVariantData.InitJsonFromFile for example.
There's problably nothing ready like that, SearchItemByProp only looks in first level.