You are not logged in.
I might have read your post in diagonal and misunderstood some parts of it - will read it again ![]()
you dont have to, you can consume interface based services with any client. For example, apply this patch to the sample and just call /find like
curl 'http://127.0.0.1:11111/find?name=testand /add
curl http://127.0.0.1:11111/add \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"name": "test",
"question": "This is a test?"
}'hi gcarreno,
Alas, the MVC example produces HTML pages. My WEB API will only produce JSON...
Append `/json` at the end of the url to see what happen
(it was primarly made for debugging purpose, but it can be consumed as is too).
What about the question about database migration?
I wrote some parts of rock migration, a module used by ProcessWire community (I am pretty sure you know it) so I can clearly see what you have in mind. As you already mentioned, things turn a bit different with a compiled approach but not that much I think.
I've just published a very minimal example here showing how to compare current model table with external table fields to remove orphaned columns. Then, imagine you set up a proper ci/cd pipelnie for example with jenkins and fpc, you could write migration files to be consumed by your flow, compile, deploy. And as mormot is able to serialize any class/record into a json object, writing a migration module similar to what you’d have on cakephp to keep or rollback your db/api definition should be ok. Anyway, nothing native yet
Hope this points you in more or less the right direction ![]()
Small update. I migrated the certificate and fixed the server config, previous error not gone, but a new one:
14/10/2025 17:06:49.512 Enter 70 mormot.rest.http.client.TRestHttpClientSocket(01b84970) CallBackGet api/timestamp
14/10/2025 17:06:49.512 Enter 70 mormot.rest.http.client.TRestHttpClientSocket(01b84970) InternalUri GET
14/10/2025 17:06:49.512 Exception 70 ENetSock {LastError:"nrClosed",Message:"THttpClientSocket.SockInReadLn [#5 Closed]"} [TTicketPull sagas] at 016a2f45 mormot.net.sock.pas TCrtSocket.Bind (5841) mormot.core.os.windows.inc XorOSEntropy (2311) mormot.core.os.windows.inc XorOSEntropy (2316) {4 0.27 0.76 8 645.8MB/1.7GB 1db10a01}
14/10/2025 17:06:50.160 Client 70 mormot.rest.http.client.TRestHttpClientSocket(01b84970) GET api/timestamp status=200 len=12 state=0
14/10/2025 17:06:50.160 Leave 70 00.654.548Then I patched two machines TLS with KB3140245, and imported missing intermediate certs into Windows 7/10 clients and then no more SEC_E_MESSAGE_ALTERED.
Idk if the following is related and could give some hints. I have the same issue on Windows 7; Recently, we switched new deployed computers on Windows 10 and the same issue is happening.
The current http server is apache reverse proxy for a specific reason using a Sectigo RSA certificate. Actually, I havn't tried to fix it, but I observed the following:
- on my own computer, the error isn't triggered.
- some months ago, I could fix it on Windows 7 by registering missing certs on the local certificate store.
So on my side, I suspect a problem on the certificate chain. I will have more info in the next day as we have renewed the certificate and I will update the server conf.
25/06/2025 07:49:02.464 Enter 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0).CallBackGet api/timestamp
25/06/2025 07:49:02.464 Enter 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0).InternalUri GET
25/06/2025 07:49:03.560 Exception 73 ESChannel {Message:"<the.domain.fr>: HandshakeStep returned 8009030F [SEC_E_MESSAGE_ALTERED], System Error 5 [ERROR_ACCESS_DENIED]"} [] at 01285bdf mormot.net.sock.windows.inc TSChannelNetTls.ESChannelRaiseLastError (1927) {65529.79 4.99 12 0.8GB/2GB 1db10a01}
25/06/2025 07:49:03.560 Exception 73 ESChannel {Message:"recv: Handshake aborted"} [] at 01285d26 mormot.net.sock.windows.inc TSChannelNetTls.FreeAndCheckSocket (1948) {65529.79 4.99 12 0.8GB/2GB 1db10a01}
25/06/2025 07:49:03.560 Exception 73 ESChannel {Message:"recv: Handshake aborted"} [] at 01285d26 mormot.net.sock.windows.inc TSChannelNetTls.FreeAndCheckSocket (1948) {65529.79 4.99 12 0.8GB/2GB 1db10a01}
25/06/2025 07:49:03.560 Client 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0) GET api/timestamp status=666 len=0 state=0
25/06/2025 07:49:03.560 Leave 73 01.102.694
25/06/2025 07:49:03.560 Enter 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0).InternalUri GET
25/06/2025 07:49:04.720 Client 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0) GET api/timestamp status=200 len=12 state=0
25/06/2025 07:49:04.720 Leave 73 01.173.370
25/06/2025 07:49:04.720 Service return 73 mormot.rest.http.client.TRestHttpClientSocket(77b1a0) 135919590467
25/06/2025 07:49:04.720 Leave 73 02.276.213The issues I'm aware of (using ssl tools):
- The chain doesn't contain any intermediate certificates
@FlaviusFX, I think it's related to the following, I remember it was fixed a few days later after the release, read issues #306 on github.
This is beyond the scope of jwt thing, you didn't described how you are adding user and I then assume you are adding manually an user into the external auth user table: if ORM cache is enabled, then this behavior is expected. You could read that you are hitting orm cache on the console by enabling server logs (and by reading the manual).
Thats said, set db.usecache to false or write a small rest client tool for adding your users..
I can help your but put some efforts
just share the file
I see, your file is probably missing something or contain a bad formatting. Swagger doesn't care about the server itself, it's about the file definition.
I dont understand this one sorry - if you mean swagger editor, you will get a button if you define some security schemes. Which api definition are you talking about ?
Yes I've read your comment (I edited it on the PR
) It was not really a bug but a change on the framework implementation. I didn't had the time to push my changes and merging @koraycayiroglu code.
Is it possible to create interface based service for authentication and use it in client side?
Yes you can, just register your service with bypassauthentication true. On the initial sample they were implemented as service methods as I think it fit better to access service context. You can mix both interface/service methods without problem.
The secret is the same as the param you set on TJwtHS256.Create if SecretPbkdf2Round is 0. If you didn't modified the public example then a new secret is generated on each server start and it's the sha256 hash of a random guid, see there.
Just set a breakpoint and copy the value, or echo the key on the console (or generate a new hash from a dummy secret) and then copy paste the key on jwt.io, you should get a valid signature.
Personal taste, I feel more comfortable using IDocDict/List. Maybe take a look at this blog post if it helps (check the advanced features: filtering, searching):
Indeed, I forgot this one ![]()
It's working as expected ![]()
Hi @ab, I did some testing - Delphi 12.3 and FPC - and then:
- without rsoPerConnectionNone, client auth is fine (this was failing).
- enabling rsoPerConnectionNone, client fail at CheckPassoword()
fServer.fOptions:
[rsoNoInternalState,rsoNoTableURI,rsoMethodUnderscoreAsSlashUri,rsoPerConnectionNonce]srvr mormot.rest.server.TRestServerRoutingRest(0334c340) Method GET root/auth?username=Admin=200 out=77 B in 3.09s
ret ServerApiHost.TAppServer(033e9f40) Method len=77 {"result":"bd1a5ead8e255448fd09484e56e33a66ea8cefc3f6d3804735cb6cf7a46881c0"}
[debug] GET /root/auth?username=Admin&password=e23f6a5756da303c6b36de49077cb51d6828768a2763b0b82678122deba05ac8&clientnonce=58671B01_0fb7691644db0de2e1bd776ed8466eb2
[BeforeBody][aInHeaders]:
- X-Real-IP: 127.0.0.1
- X-Forwarded-For: 127.0.0.1
- X-Forwarded-Proto: https
- X-Conn-ID: 17
- Accept: */*Ah! I checked the nginx configuration, the X-Conn-ID header is the only one missing - I didn't paid attention. Thanks you, I will test tomorrow.
I will look at it, the nginx config was kept minimal with a simple proxy_pass for testing. The demo program return both 200 OK (direct and nginx) if the server is compiled on last commit before 65e4597. Once I compile the server starting on commit 65e4597, then it fail on nginx only..
I will try again with a minimal server and report it here.
Is it just me, or am I the only one running into this issue? ![]()
I have provided you with examples there last day: D-H-R/mormot_json/issues/1
And it is really funny how grok is even more hallucinating, the more you give him corrections.
I admit I feel like the more thinking they try to do, the more they tend to hallucinate...
It was a sort of pseudo-code, MvcApp could have been a public property. Glad you get it working, i suggest you to read mormot.core.mvc and mormot.rest.mvc to learn about what @ab said in previous post and to optimize your setup.
Hi @ab, I have an issue with TRestHttpClient.SetUser which is not working starting on this specific commit, and tested yet only on Delphi 12.3
65e4597 - rest: make server nonce unique per connection/client - our authentication scheme is now as secure as SCRAM could be, and even more since we feature strong "Modular Crypt" hashes like BCrypt or SCrypt
- still compatible with old mORMot 1 clients
What happen:
- It work using direct connection to server host (localhost, 192.168.*)
- it doesn't work behind NGINX on 80/http and 443/https
I havn't debugged yet as you might have an answer.
On the test program shown below, the client is a simple TRestHttpClient.SetUser and compiled on commit a919746 from july, 29. I get the same result compiling both server and client on commit 65e4597 or newer. I have saved logs just in case.
Client on left side get HTTP 200, on right side the client get a HTTP 403 return code.

To avoid writing same code over each method, you could set a service on a TRestServer to handle backend logic and attach your MVC instance to it. Then inherit your interfaces with something like that (TAppService will have access to CurrentSession):
TAppService = class(TInjectableObjectRest)
protected
function TryGetSessionCookie(out S: TCookieData): boolean;
function GetLoggedAuthorID(Right: TOrmAuthorRight): TID;
function HasRight(Right: TOrmAuthorRight): boolean;
end;
TAppServer = class(TRestServerDB)
FMvcApp: IMvcApplication;
FAppService: TAppService;
end;then create a instance with a resolver and rest:
FMvcApp := ...
FAppService := TAppService.CreateWithResolverAndRest(Self.ServiceContainer, nil, Self);TryGetSessionCookie implementation could look something like:
function TAppService.TryGetSessionCookie(out S: TCookieData): boolean;
begin
result := false;
S := Default(TCookieData);
result := TAppServer(Server).MvcApp.CurrentSession.CheckAndRetrieve(@S, TypeInfo(TCookieData)) > 0;
end;Write a service to handle backend logic:
TServiceResult = (seSuccess, seNotFound, seMissingField, sePersistenceError);
IBackendService = interface(IInvokable)
['{A513EF1E-62B1-44A3-A2A0-7F3A6E6F19E4}']
function NewArticle: TServiceResult;
function UpdateArticle(aPage: TPage): TServiceResult;
function DeleteArticle(aID: TID): TServiceResult;
// ...
end;
// inherit from TAppService
BackendService = class(TAppService, IBackendService)
// ...
end; then register the backend service as usual on the rest server:
Self.ServiceDefine(TBackendService , [IBackendService]);The JS client can then log in, get cookie and make backend calls... You could also hook on the *Uri rest events to set a custom "gate" logic.
Hope you get the idea...
Why your function returns False
• Assumes signature is always raw 64 bytes (R||S)
• Your check Length(...) <> SizeOf(TEccSignature) exits early for any DER signature. OpenSSL (and many toolchains) output DER. So you never reach Verify for DER input.
• Public key format mismatch
• lCertificate.GetPublicKey returns the X.509 SubjectPublicKey (SPKI) in ASN.1. TCryptAsym.Verify expects EC public key in one of a few raw/PEM/DER encodings it can parse; SPKI isn’t always accepted directly by its low-level PemDerRawToEcc(). You either need to rewrap the SPKI to the EC compressed key DER, or use ICryptCert.Verify (which does that internally).
• Data bytes/encoding
---
credit: gpt
ps: I tested the code
@ab: do you think the ai-model hallucinated?
I did not remember changing anything about RootRedirectGet.
Just throwing this out there, it might have zero impact, but I noticed it while reading last month's commits: rsoAllowSingleServerNoRoot (this option was in fact not implemented at all in mORMot 2 !)
ITWT
désolé
![]()
You are missing the object creation that will trigger an AV and use ObjectToJson, not JsonEncode.
function TUtilisateursService.GetUtilisateur(aID: TID): RawJSON;
var
obj: TOrmUtilisateurs;
begin
obj := TOrmUtilisateurs; // <- missing create
try
if not fClientDB.Orm.Retrieve(aID, obj) then
raise ERestException.Create('404 - Utilisateur non trouvé');
Result := ObjectToJson(obj);
finally
obj.Free;
end;
end;ou
function TUtilisateursService.GetUtilisateur(aID: TID): RawJSON;
var
obj: TOrmUtilisateurs;
begin
obj := TOrmUtilisateurs.Create(fClientDB.Orm, aID);
try
if ID = 0 then
raise ERestException.Create('404 - Utilisateur non trouvé');
Result := ObjectToJson(obj);
finally
obj.Free;
end;
end;read there: SAD1.18 5.2. Working with Objects
to check the command you show you could do it in InBeforeBody, you could validate specific upgrade in flags hsrConnectionUpgrade.
edit: what @ab just said
If it helps you find the way, on my side, I use TWebSocketProtocol.UpgradeBearerToken for that: read more there
FYI you can make code simpler with
with ServiceDefine(TAdmin, [IAdmin], sicPerSession, SERVICE_CONTRACT_NONE_EXPECTED) do
begin
ResultAsJSONObjectWithoutResult := True;
SetOptions([], [optErrorOnMissingParam])
end;I’ve always felt that current large language models aren’t very friendly toward Object Pascal
don't be fooled ..
What data has GitHub Copilot been trained on?
GitHub Copilot is powered by generative AI models developed by GitHub, OpenAI, and Microsoft. It has been trained on natural language text and source code from publicly available sources, including code in public repositories on GitHub.
.. and it's not the only data source; You know.. personal privacy.. checkbox.. big-data, etc...
the mORMot framework is so BIG and complex that inputting a relatively small number of tokens rarely yields effective outputs.
The main issue, IMO, comes from when most datasets were built. The first public release of mormot v2 was around late 2020 (first commit in march 2020), but by then the models had already ingested mormot v1 source code. That’s why on gpt-3, gpt-4 (and even gpt-5!), you often get v1-based code in the answers - I'am quite sure you got the TSqlModel instead of TOrmModel things, etc. which is why the “big prompt” is actually useful.
Also, if you let your tools adapt to your own habits, you’ll naturally get better results. On my side, no matter what I ask, I always end up with a marmot somewhere in the answer ![]()
I mostly use cursor for frontend tasks, like building React dashboards or working with (syn)mustache templates (it actually works really well on Pascal codebases too). But I have to admit - warp terminal is a beast. I will try to make you a small demo if you’re interested.
To be honest, the real secret is to simply RTFM for each tool and configuring it properly, then taking the time to create a solid project structure (folder tree, rules, contextual prompts, etc) and calling the right model for a given task. The models to be used is now gpt-5 (truly impressive), claude-4-thinking and gemini-2.5-pro-thinking.
I'am not following ai trends closely but I'am quite sure claude-5 is in the pipe.
Do you mean that through mcp-delphi, the tokens input to Gemini or ChatGPT can be significantly reduced? I'm sorry, but I'm a bit confused about how this is achieved. Could you give us some hints?
No. At this moment, the mcp-delphi server only allows AI agents to use your IDE to compile your project (Delphi, Lazarus, or FPC directly) and get the output, nothing more. That said, if your coding tool supports "auto-mode", you can let the agents create, compile, and fix the project for you - while you’re cooking, for example
I tried it with gpt-5, project built successfully and potatoes where not burnt lol.
Then I thought it could be useful to have a dedicated MCP server for working with mormot. It would definitely reduce the number of tokens consumed, since the agents would be able to query a well structured knowledge base for the relevant part of the framework instead of injecting a huge prompt. I also believe the agents would "think" better as their memory context wouldn’t be overloaded.
Cool, thanks for the contribution
- I’ll ping you on the PR once I’ve compared it with the pushed changes
made a pull request too
Thanks! I’ll review it this weekend. Is it based on the latest mORMot update?
Thanks for sharing, @koraycayiroglu.
I’ve since refactored parts of the setup and will clean and push the changes to the repo. For example:
We now use ServiceRunningContext via a locally assigned PServiceRunningContext variable.
I addressed an oddity in the token refresh flow — previously it retrieved logonname and password from query strings. Instead, I now generate a token_refresh_uuid embedded in the token payload, and retrieve the logonname from the built-in jcIssuer. This allows validating the user by combining it with the sessionkey.
The goal is to send credentials only once to obtain a valid JWT, and never send them again.
I published a MCP server for delphi and lazarus/fpc; I am working on a special setup focused on mormot2. I must say from my tests with gemini - and now gpt-5 included - it's quite amazing. Token usage will be reduced a lot compared to "the-big-prompt".
You can find it there: https://github.com/flydev-fr/mcp-delphi
The way I learned to use Mormot was by conducting a global search for potential keywords, which was quite challenging.
I thought SAD 8.3[.6] (External database ORM internals) and api/mORMotDB.html might help clarifying.
at least I get some more doc to ingest.
Default "const" would pass it as two registers, not as a single register pointer.
Aw nasty. Thanks you ab
I still didn't found where it happen exactly - in DecodeUriParametersIntoJson, InBody is built correctly with an uuid string in a json array. The issue seem happening elsewhere and deeper in ExecuteJson(). I will continue tomorrow.
I could observe that it happen only when the parameter is defined as const (required with TServiceCustomAnswer as return type) and then found that a method like:
function Example(const uuid: TGUID): RawUtf8;.. produces the same problem. If using var/out TGUID, result is ok.
I just tested with `curl http://localhost:9088/api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21` and I have the very same issue, result:
uuid is: 17868178-0000-0000-0000-000000000000Then I have also compiled the server on ubuntu and same problem. FPC version on Ubuntu is 3.3.1. The lazarus project file is based on MVCServer.lpi with -Xm and compiled without optimization. I will test it with a simple and new project..
---
Edit:
I have created a new simple project on ubuntu and compiled, result is the same, the guid is wrong.
1) Yes, but maybe I was unclear earlier, I cross-compile for both Windows and Linux on my Windows machine (FPC 3.2.2). I must say that I have compiled it directly on Ubuntu two months ago and got the very same issue.
2) no unit windows. I traced it to objpash.inc, line 134.
The server is behind nginx. The GUID param received on Linux is not null, but incorrect.
I compiled for linux and windows with "clean up and build" before posting here. Test results:
Linux: uuid is: 40918D38-0000-0000-0000-000000000000
Windows: uuid is: 3C28EA56-37FE-4ABC-A0B7-508D8C634E21 (as expected)
- Logs Linux:
$ + AuthServer.TRestServerAuth(408199d0) URI GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21 in=0 B
$ call AuthServer.TRestServerAuth(408199d0) UserService.ReadTest len=40 ["3C28EA56-37FE-4ABC-A0B7-508D8C634E21"]
$ srvr RestJwtAuth.TRestRoutingREST_JWT(70f85803e000) Interface GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21=200 out=51 B in 555us
$ ret AuthServer.TRestServerAuth(408199d0) Interface len=51 uuid is: 40918D38-0000-0000-0000-000000000000- Logs Windows:
+ AuthServer.TRestServerAuth(05ddad08) URI GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21 in=0 B
call AuthServer.TRestServerAuth(05ddad08) UserService.ReadTest len=40 ["3C28EA56-37FE-4ABC-A0B7-508D8C634E21"]
srvr RestJwtAuth.TRestRoutingREST_JWT(06389a18) Interface GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21=200 out=51 B in 439us
ret AuthServer.TRestServerAuth(05ddad08) Interface len=51 uuid is green: 3C28EA56-37FE-4ABC-A0B7-508D8C634E21I will test with curl on the linux server without nginx in about 15 minutes.
Again, just a small question about TGUID as I’m hitting a cross-platform snag with FPC 3.2.2 but with TGUID defined as param on SOA:
IUserService = interface(IInvokable)
['...']
function Read(const user_uuid: TGUID): TServiceCustomAnswer;
end;- Win64 build (FPC 3.2.2): user_uuid arrives with the expected value.
- Linux x86-64 build (same sources & FPC version): user_uuid is always null.
Is this due to missing record RTTI for TGUID under FPC on Linux?
I can tackle the problem by passing it as RawUtf8, but I'am asking for my own knowledge.
thanks ![]()
Hi, because it's a string, it's appending a string item to a json array.
Use IDocDict to add an object:
LDocList.AppendDoc(DocDict(['text', 'test']));or you can serialize directly:
LDocList.Json := '[{"text": "test"},{"text": "test2"}]'; // don't make sense: `DocList('[{"text": "test"}]');`when the array (Len) is not empty, you can assign an object directly to it using:
LDocList.O[1] := DocDict(['text', 'test2 is now test3']);@Alek, to force partial changes to be reloaded, apply theses modifications:
on mormot.rest.mvc.pas#L181 add:
FViewPath: RawUtf8;and the public property:
property ViewPath: RawUtf8 read FViewPath write FViewPath;on line mormot.rest.mvc.pas#L1245 add:
{$ifdef DEBUG}
fViewPartials.ViewPath := folder;
{$endif}replace mormot.core.mustache.pas#L1317-L1332 with:
function TSynMustachePartials.GetPartial(
const PartialName: RawUTF8): TSynMustache;
var
i: PtrInt;
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: -dDEBUG on fpc
Result := TSynMustache(fList.Objects[i]);
{$ifdef debug}
begin
Temp := TSynMustache.Parse(AnyTextFileToRawUTF8(UTF8ToString(MakePath([FViewPath, PartialName + '.partial'])), true));
if Temp.Template <> '' then
Result := Temp;
end;
{$endif debug}
end;@ab, any chance you consider adding it or similar - or did we missed something?
---
Edit: I missed last post of @ab - watching for files changes and triggering FlushAnyCache() should be the right way to do it while developping. Anyway, the method presented here still make getting partial markup changes easier.
---
UPDATED: and I also don't quite understand the meaning of the variables.
I made a gist trying to explain it (should be correct), read there: https://gist.github.com/flydev-fr/e0f0a … c2ac78f2bc
Call FlushAnyCache when you change data in your model. If I am correct, on the blog sample, the default data is cleared and filled with new data again if empty on GetViewInfo(). The method is virtual so you can implement your own flush logic there.
... i think no one will make a server on mobile platform.
Sure — but on the other hand, I know a few friends in the IT sec field who would be stunned to carry a mobile phone running a dedicated app instead of walking around with an offline raspberry or any other pocket device.
I started working on it.
When I was doing my daily commit reading, I couldn't help but smile wide… and the image of @ab that popped into my head was ..
![]()

I can't reproduce it - it work as expected at least on fpc 3.2.2.
edit: ... and mormot 2.3.10775
@fatimaEzz, unit is "mormot.crypt.secure".
protip: consider using a specialized tool to perform recursive content searches within a specified folder (/mormot/src), eg. Agent Ransack (free).
hi @ab,
I'd like to propose the addition of a helper function in `mormot.core.rtti.pas` to enhance support for parsing scoped CSV values into enum sets.
About use case, in JWT-based APIs, I often use enum sets encoded as scoped strings such as: `users:create,users:read,system:logs`
These values are not directly mappable using `GetSetCsvValue()` due to their prefixed format (I might missed an existing gem!).
I wrote a helper named `GetSetCsvValueTrimmed()` which uses `TrimOneChar()` to remove the scoped prefix before matching against enumeration names (maybe another internal function would be more appropriate):
/// Parse a delimited list of scoped identifiers into a set, returned as a 64-bit bitmask
// - each entry in the CSV should follow a scoped naming pattern, e.g. 'users:create'
// - the prefix separator (scopeChar) is customizable and defaults to ':' if not specified
// - this function is similar to GetSetCsvValue(), but will remove the scope prefix
// from each identifier before matching it against the enumeration names
// - returns 0 on parsing failure, or if none of the values map to known enum items
// - expects aTypeInfo to point to a set of enumerations with matching names
function GetSetCsvValueTrimmed(aTypeInfo: PRttiInfo; Csv: PUtf8Char; scopeChar: AnsiChar = ':'): QWord; function GetSetCsvValueTrimmed(aTypeInfo: PRttiInfo; Csv: PUtf8Char; scopeChar: AnsiChar): QWord;
var
tmp: RawUtf8;
begin
result := 0;
if (Csv = nil) or (Csv^ = #0) or (aTypeInfo = nil) then
exit;
// remove scopes like 'users:' or 'system:' prefixes from each value
tmp := TrimOneChar(Csv, scopeChar);
result := GetSetCsvValue(aTypeInfo, pointer(tmp));
end; If it makes sense, I also wrote unit tests to validate typical JWT-like scope strings.
type
TEnumPetStorePerm = (
epsPermNone, epsStoreRead, epsStoreWrite);
TEnumPetStorePermSet = set of TEnumPetStorePerm;
checkEqual(GetSetCsvValueTrimmed(TypeInfo(TEnumPetStorePermSet), 'store:read,store:write'), 6, 'TEnumPetStorePerm');
// ...Thanks!
I published a gist with a working example (mormot2), assuming a TAuthUser is on external db, feel free to change the table name with one of your..
TRestClientDB use an hidden TRestServerDB; you could map to an external db for example this should work:
Props := TSQLDBZEOSConnectionProperties.Create(...);
Props.ThreadSafeConnection.Connect;
OrmMapExternal(aORMSQLModel, [TYourOrmMapped], Props);
ORMDB:= TRestClientDB.Create(aORMSQLModel, nil, ':memory:', TRestServerDB, False, StringToUtf8(aPassword));
TRestServerDB(ORMDB.Server).Server.CreateMissingTables(0, [itoNoAutoCreateUsers]);I dont really get what you are asking specifically, but did you took a look at /ex/extdb-bench or mongodb & techempower samples? also read test.orm.extdb.pas from test folder.
Basically to get a TRestServerDB virtually working with MariaDB, there is a generic connection definition:
// 1. Define your external SQL connection
Props := TSQLDBZEOSConnectionProperties.Create(
FormatUtf8('zdbc:mysql://127.0.0.1:%/%?username=%;password=%',
DB_PORT, DB_SOURCE, DB_USERNAME, DB_PASSWORD]),
'aSqlite3.db', DB_USERNAME, DB_PASSWORD);
Props.ThreadSafeConnection.Connect;
// 2. Define your model and ORM mapping
Model := TOrmModel.Create([TOrmSomething]);
OrmMapExternal(Model, [TOrmSomething], Props);
// 3. Create the REST server, mapped to the external DB
Server := TRestServerDB.Create(Model);
Server.Server.CreateMissingTables;