articles_crud migrated to services container

This commit is contained in:
Daniele Teti 2024-03-30 00:30:14 +01:00
parent 6142c2d929
commit b41e245bbc
13 changed files with 373 additions and 256 deletions

View File

@ -3,46 +3,51 @@ unit BusinessObjects;
interface
uses
MVCFramework.Serializer.Commons, MVCFramework.Nullables;
MVCFramework.Serializer.Commons, MVCFramework.Nullables,
MVCFramework.ActiveRecord;
type
TBaseBO = class
TBaseBO = class(TMVCActiveRecord)
private
[MVCTableField('ID', [foPrimaryKey])]
FID: Integer;
procedure SetID(const Value: Integer);
public
procedure CheckInsert; virtual;
procedure CheckUpdate; virtual;
procedure CheckDelete; virtual;
property ID: Integer read FID write SetID;
end;
[MVCNameCase(ncLowerCase)]
[MVCTable('ARTICOLI')]
[MVCNamedSQLQuery(
'search_by_text',
'SELECT * FROM ARTICOLI WHERE DESCRIZIONE CONTAINING ? ORDER BY ID')
]
TArticle = class(TBaseBO)
private
FPrice: Currency;
[MVCTableField('CODICE')]
FCode: string;
[MVCTableField('DESCRIZIONE')]
FDescription: String;
[MVCTableField('PREZZO')]
FPrice: Currency;
[MVCTableField('UPDATED_AT')]
FUpdatedAt: TDateTime;
[MVCTableField('CREATED_AT')]
FCreatedAt: TDateTime;
procedure SetCode(const Value: string);
procedure SetDescription(const Value: String);
procedure SetPrice(const Value: Currency);
procedure SetCreatedAt(const Value: TDateTime);
procedure SetUpdatedAt(const Value: TDateTime);
protected
procedure OnBeforeInsertOrUpdate; override;
procedure OnBeforeUpdate; override;
procedure OnBeforeDelete; override;
public
procedure CheckInsert; override;
procedure CheckUpdate; override;
procedure CheckDelete; override;
[MVCColumn('CODICE')]
property Code: string read FCode write SetCode;
[MVCColumn('DESCRIZIONE')]
property Description: String read FDescription write SetDescription;
[MVCColumn('PREZZO')]
property Price: Currency read FPrice write SetPrice;
[MVCColumn('CREATED_AT')]
property CreatedAt: TDateTime read FCreatedAt write SetCreatedAt;
[MVCColumn('UPDATED_AT')]
property UpdatedAt: TDateTime read FUpdatedAt write SetUpdatedAt;
end;
@ -53,46 +58,28 @@ uses
{ TBaseBO }
procedure TBaseBO.CheckDelete;
begin
end;
procedure TBaseBO.CheckInsert;
begin
end;
procedure TBaseBO.CheckUpdate;
begin
end;
procedure TBaseBO.SetID(const Value: Integer);
begin
FID := Value;
end;
{ TArticolo }
procedure TArticle.CheckDelete;
procedure TArticle.OnBeforeDelete;
begin
inherited;
if Price <= 5 then
raise Exception.Create('Cannot delete an article with a price below 5 euros (yes, it is a silly check)');
end;
procedure TArticle.CheckInsert;
procedure TArticle.OnBeforeInsertOrUpdate;
begin
inherited;
if not TRegEx.IsMatch(Code, '^C[0-9]{2,4}') then
raise Exception.Create('Article code must be in the format "CXX or CXXX or CXXXX"');
end;
procedure TArticle.CheckUpdate;
procedure TArticle.OnBeforeUpdate;
begin
inherited;
CheckInsert;
if Price <= 2 then
raise Exception.Create('We cannot sell so low cost pizzas!');
end;

View File

@ -10,6 +10,9 @@ type
end;
const
CON_DEF_NAME = 'MyConnX';
implementation
end.

View File

@ -7,14 +7,19 @@ uses
mvcframework.Commons,
mvcframework.Serializer.Commons,
System.Generics.Collections,
Controllers.Base, BusinessObjects;
Controllers.Base, BusinessObjects, Services;
type
[MVCDoc('Resource that manages articles CRUD')]
[MVCPath('/articles')]
TArticlesController = class(TBaseController)
private
fArticlesService: IArticlesService;
public
[MVCInject]
constructor Create(ArticlesService: IArticlesService); reintroduce;
[MVCDoc('Returns the list of articles')]
[MVCPath]
[MVCHTTPMethod([httpGET])]
@ -23,17 +28,17 @@ type
[MVCDoc('Returns the list of articles')]
[MVCPath('/searches')]
[MVCHTTPMethod([httpGET])]
procedure GetArticlesByDescription(const [MVCFromQueryString('q', '')] Search: String);
function GetArticlesByDescription(const [MVCFromQueryString('q', '')] Search: String): IMVCObjectDictionary;
[MVCDoc('Returns the article with the specified id')]
[MVCPath('/meta')]
[MVCHTTPMethod([httpGET])]
procedure GetArticleMeta;
function GetArticleMeta: IMVCObjectDictionary;
[MVCDoc('Returns the article with the specified id')]
[MVCPath('/($id)')]
[MVCHTTPMethod([httpGET])]
procedure GetArticleByID(id: Integer);
function GetArticleByID(id: Integer): IMVCObjectDictionary;
[MVCDoc('Deletes the article with the specified id')]
[MVCPath('/($id)')]
@ -61,14 +66,19 @@ implementation
{ TArticlesController }
uses
Services,
Commons,
mvcframework.Serializer.Intf,
System.SysUtils;
constructor TArticlesController.Create(ArticlesService: IArticlesService);
begin
inherited Create;
fArticlesService := ArticlesService;
end;
procedure TArticlesController.CreateArticle(const Article: TArticle);
begin
GetArticlesService.Add(Article);
fArticlesService.Add(Article);
Render201Created('/articles/' + Article.id.ToString, 'Article Created');
end;
@ -76,101 +86,60 @@ procedure TArticlesController.CreateArticles(const ArticleList: TObjectList<TArt
var
lArticle: TArticle;
begin
GetArticlesService.StartTransaction;
try
for lArticle in ArticleList do
begin
GetArticlesService.Add(lArticle);
end;
GetArticlesService.Commit;
except
GetArticlesService.Rollback;
raise;
end;
Render(201, 'Articles Created');
// fArticlesService.StartTransaction;
// try
// for lArticle in ArticleList do
// begin
// fArticlesService.Add(lArticle);
// end;
// fArticlesService.Commit;
// except
// fArticlesService.Rollback;
// raise;
// end;
// Render(201, 'Articles Created');
end;
procedure TArticlesController.DeleteArticleByID(id: Integer);
var
Article: TArticle;
lArticle: TArticle;
begin
GetArticlesService.StartTransaction;
try
Article := GetArticlesService.GetByID(id);
try
GetArticlesService.Delete(Article);
finally
Article.Free;
end;
GetArticlesService.Commit;
except
GetArticlesService.Rollback;
raise;
end;
lArticle := fArticlesService.GetByID(id);
fArticlesService.Delete(lArticle);
end;
procedure TArticlesController.GetArticles;
begin
Render(ObjectDict().Add('data', GetArticlesService.GetAll));
Render(ObjectDict().Add('data', fArticlesService.GetAll));
end;
procedure TArticlesController.GetArticlesByDescription(const Search: String);
var
lDict: IMVCObjectDictionary;
function TArticlesController.GetArticlesByDescription(const Search: String): IMVCObjectDictionary;
begin
try
if Search = '' then
begin
lDict := ObjectDict().Add('data', GetArticlesService.GetAll);
end
else
begin
lDict := ObjectDict().Add('data', GetArticlesService.GetArticles(Search));
end;
Render(lDict);
except
on E: EServiceException do
begin
raise EMVCException.Create(E.Message, '', 0, 404);
end
else
raise;
if Search = '' then
begin
Result := ObjectDict().Add('data', fArticlesService.GetAll);
end
else
begin
Result := ObjectDict().Add('data', fArticlesService.GetArticles(Search));
end;
end;
procedure TArticlesController.UpdateArticleByID(const Article: TArticle; const id: Integer);
begin
Article.id := id;
GetArticlesService.Update(Article);
fArticlesService.Update(Article);
Render(200, 'Article Updated');
end;
procedure TArticlesController.GetArticleByID(id: Integer);
function TArticlesController.GetArticleByID(id: Integer): IMVCObjectDictionary;
begin
try
Render(ObjectDict().Add('data', GetArticlesService.GetByID(id)));
except
on E: EServiceException do
begin
raise EMVCException.Create(E.Message, '', 0, 404);
end
else
raise;
end;
Result := ObjectDict().Add('data', fArticlesService.GetByID(id));
end;
procedure TArticlesController.GetArticleMeta;
function TArticlesController.GetArticleMeta: IMVCObjectDictionary;
begin
try
Render(ObjectDict().Add('data', GetArticlesService.GetMeta));
except
on E: EServiceException do
begin
raise EMVCException.Create(E.Message, '', 0, 404);
end
else
raise;
end;
Result := ObjectDict().Add('data', fArticlesService.GetMeta);
end;
end.

View File

@ -3,19 +3,10 @@ unit Controllers.Base;
interface
uses
MVCFramework, MVCFramework.Commons, Services, MainDM;
MVCFramework, MVCFramework.Commons, Services;
type
TBaseController = class abstract(TMVCController)
strict private
FDM: TdmMain;
FArticlesService: TArticlesService;
function GetDataModule: TdmMain;
strict protected
function GetArticlesService: TArticlesService;
public
destructor Destroy; override;
end;
[MVCPath('/private')]
@ -23,7 +14,7 @@ type
public
[MVCPath('/articles')]
[MVCHTTPMethods([httpDELETE])]
procedure DeleteAllArticles;
procedure DeleteAllArticles(ArticlesService: IArticlesService);
end;
implementation
@ -31,34 +22,11 @@ implementation
uses
System.SysUtils;
{ TBaseController }
destructor TBaseController.Destroy;
begin
FArticlesService.Free;
FDM.Free;
inherited;
end;
function TBaseController.GetArticlesService: TArticlesService;
begin
if not Assigned(FArticlesService) then
FArticlesService := TArticlesService.Create(GetDataModule);
Result := FArticlesService;
end;
function TBaseController.GetDataModule: TdmMain;
begin
if not Assigned(FDM) then
FDM := TdmMain.Create(nil);
Result := FDM;
end;
{ TPrivateController }
procedure TPrivateController.DeleteAllArticles;
procedure TPrivateController.DeleteAllArticles(ArticlesService: IArticlesService);
begin
GetArticlesService.DeleteAllArticles();
ArticlesService.DeleteAllArticles();
end;
end.

View File

@ -0,0 +1,225 @@
unit FDConnectionConfigU;
interface
procedure CreateFirebirdPrivateConnDef(AIsPooled: boolean);
procedure CreateInterbasePrivateConnDef(AIsPooled: boolean);
procedure CreateMySQLPrivateConnDef(AIsPooled: boolean);
procedure CreateMSSQLServerPrivateConnDef(AIsPooled: boolean);
procedure CreatePostgresqlPrivateConnDef(AIsPooled: boolean);
procedure CreateSqlitePrivateConnDef(AIsPooled: boolean);
implementation
uses
MVCFramework.Commons,
System.Classes,
System.IOUtils,
FireDAC.Comp.Client,
FireDAC.Moni.Base,
FireDAC.Moni.FlatFile,
FireDAC.Stan.Intf
, Commons;
var
gFlatFileMonitor: TFDMoniFlatFileClientLink = nil;
procedure CreateMySQLPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
{
docker run --detach --env MARIADB_USER=example-user --env MARIADB_PASSWORD=my_cool_secret --env MARIADB_ROOT_PASSWORD=root -p 3306:3306 mariadb:latest
}
LParams := TStringList.Create;
try
LParams.Add('Database=activerecorddb');
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=root');
LParams.Add('Password=root');
LParams.Add('TinyIntFormat=Boolean'); { it's the default }
LParams.Add('CharacterSet=utf8mb4'); // not utf8!!
LParams.Add('MonitorBy=FlatFile');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'MySQL', LParams);
finally
LParams.Free;
end;
end;
procedure CreateMSSQLServerPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
{
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=!SA_password!" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
}
// [ACTIVERECORDB_SQLSERVER]
// Database=activerecorddb
// OSAuthent=Yes
// Server=DANIELETETI\SQLEXPRESS
// DriverID=MSSQL
//
LParams := TStringList.Create;
try
LParams.Add('Database=activerecorddb');
LParams.Add('OSAuthent=Yes');
LParams.Add('Server=DANIELETETI\SQLEXPRESS');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'MSSQL', LParams);
finally
LParams.Free;
end;
end;
procedure CreateFirebirdPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
LParams := TStringList.Create;
try
LParams.Add('Database=' + dotEnv.Env('database.path'));
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=sysdba');
LParams.Add('Password=masterkey');
LParams.Add('CharacterSet=UTF8');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'FB', LParams);
finally
LParams.Free;
end;
end;
procedure CreateInterbasePrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
LParams := TStringList.Create;
try
LParams.Add('Database=' + TPath.GetFullPath(TPath.Combine('..\..',
'data\ACTIVERECORDDB.IB')));
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=sysdba');
LParams.Add('Password=masterkey');
LParams.Add('CharacterSet=UTF8');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'IB', LParams);
finally
LParams.Free;
end;
end;
procedure CreatePostgresqlPrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
begin
LParams := TStringList.Create;
try
LParams.Add('Database=activerecorddb');
LParams.Add('Protocol=TCPIP');
LParams.Add('Server=localhost');
LParams.Add('User_Name=postgres');
LParams.Add('Password=postgres');
// LParams.Add('MonitorBy=FlatFile');
// https://quality.embarcadero.com/browse/RSP-19755?jql=text%20~%20%22firedac%20guid%22
LParams.Add('GUIDEndian=Big');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'PG', LParams);
finally
LParams.Free;
end;
end;
procedure CreateSqlitePrivateConnDef(AIsPooled: boolean);
var
LParams: TStringList;
lFName: string;
begin
LParams := TStringList.Create;
try
lFName := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)),
'..\..\data\activerecorddb.db');
LParams.Add('Database=' + lFName);
LParams.Add('StringFormat=Unicode');
if AIsPooled then
begin
LParams.Add('Pooled=True');
LParams.Add('POOL_MaximumItems=100');
end
else
begin
LParams.Add('Pooled=False');
end;
FDManager.AddConnectionDef(CON_DEF_NAME, 'SQLite', LParams);
finally
LParams.Free;
end;
end;
initialization
gFlatFileMonitor := TFDMoniFlatFileClientLink.Create(nil);
gFlatFileMonitor.FileColumns := [tiRefNo, tiTime, tiThreadID, tiClassName, tiObjID, tiMsgText];
gFlatFileMonitor.EventKinds := [
ekVendor, ekConnConnect, ekLiveCycle, ekError, ekConnTransact,
ekCmdPrepare, ekCmdExecute, ekCmdDataIn, ekCmdDataOut];
gFlatFileMonitor.ShowTraces := False;
gFlatFileMonitor.FileAppend := False;
gFlatFileMonitor.FileName := TPath.ChangeExtension(ParamStr(0), '.trace.log');
gFlatFileMonitor.Tracing := True;
finalization
gFlatFileMonitor.Free;
end.

View File

@ -23,10 +23,10 @@ uses
FireDAC.DApt,
FireDAC.Comp.DataSet,
FireDAC.Phys.FBDef,
FireDAC.VCLUI.Wait;
FireDAC.VCLUI.Wait, Services;
type
TdmMain = class(TDataModule)
TdmMain = class(TDataModule, IArticlesDataModule)
Connection: TFDConnection;
dsArticles: TFDQuery;
updArticles: TFDUpdateSQL;
@ -34,7 +34,9 @@ type
private
{ Private declarations }
public
constructor Create;
function SearchProducts(const SearchText: string): TDataSet;
end;
implementation
@ -52,6 +54,11 @@ begin
Connection.Params.Values['Database'] := dotEnv.Env('database.path');
end;
constructor TdmMain.Create;
begin
inherited Create(nil);
end;
function TdmMain.SearchProducts(const SearchText: string): TDataSet;
begin
Result := TFDMemTable.Create(nil);

View File

@ -5,23 +5,23 @@ interface
uses
System.Generics.Collections,
BusinessObjects,
MainDM,
System.SysUtils,
Commons, JsonDataObjects;
type
TServiceBase = class abstract
strict protected
FDM: TdmMain;
public
constructor Create(AdmMain: TdmMain); virtual;
procedure Commit;
procedure Rollback;
procedure StartTransaction;
IArticlesService = interface
['{D6843E17-1B98-435C-9EBC-8E76DCEF9A3B}']
function GetAll: TObjectList<TArticle>;
function GetArticles(const aTextSearch: string): TObjectList<TArticle>;
function GetByID(const AID: Integer): TArticle;
procedure Delete(AArticolo: TArticle);
procedure DeleteAllArticles;
procedure Add(AArticolo: TArticle);
procedure Update(AArticolo: TArticle);
function GetMeta: TJSONObject;
end;
TArticlesService = class(TServiceBase)
TArticlesService = class(TInterfacedObject, IArticlesService)
public
function GetAll: TObjectList<TArticle>;
function GetArticles(const aTextSearch: string): TObjectList<TArticle>;
@ -36,112 +36,59 @@ type
implementation
uses
FireDAC.Stan.Option,
FireDAC.Comp.Client,
FireDAC.Stan.Param,
MVCFramework.ActiveRecord,
MVCFramework.FireDAC.Utils,
MVCFramework.DataSet.Utils,
MVCFramework.Serializer.Commons;
MVCFramework.Serializer.Commons, Data.DB;
{ TArticoliService }
procedure TArticlesService.Add(AArticolo: TArticle);
var
Cmd: TFDCustomCommand;
begin
AArticolo.CheckInsert;
Cmd := FDM.updArticles.Commands[arInsert];
TFireDACUtils.ObjectToParameters(Cmd.Params, AArticolo, 'NEW_');
Cmd.Execute;
AArticolo.ID := Cmd.ParamByName('ID').AsInteger;
AArticolo.Insert;
end;
procedure TArticlesService.Delete(AArticolo: TArticle);
var
Cmd: TFDCustomCommand;
begin
AArticolo.CheckDelete;
Cmd := FDM.updArticles.Commands[arDelete];
TFireDACUtils.ObjectToParameters(Cmd.Params, AArticolo, 'OLD_');
Cmd.Execute;
AArticolo.Delete();
end;
procedure TArticlesService.DeleteAllArticles;
begin
FDM.Connection.ExecSQL('delete from articoli');
TMVCActiveRecord.DeleteAll(TArticle);
end;
function TArticlesService.GetAll: TObjectList<TArticle>;
begin
FDM.dsArticles.Open('SELECT * FROM ARTICOLI ORDER BY ID', []);
Result := FDM.dsArticles.AsObjectList<TArticle>;
FDM.dsArticles.Close;
Result := TMVCActiveRecord.SelectRQL<TArticle>('sort(+id)', 1000);
end;
function TArticlesService.GetArticles(
const aTextSearch: string): TObjectList<TArticle>;
begin
FDM.dsArticles.Open('SELECT * FROM ARTICOLI WHERE DESCRIZIONE CONTAINING ? ORDER BY ID', [aTextSearch]);
try
Result := FDM.dsArticles.AsObjectList<TArticle>()
finally
FDM.dsArticles.Close;
end;
Result := TMVCActiveRecord.SelectByNamedQuery<TArticle>('search_by_text',[aTextSearch],[ftString]);
end;
function TArticlesService.GetByID(const AID: Integer): TArticle;
begin
FDM.dsArticles.Open('SELECT * FROM ARTICOLI WHERE ID = :ID', [AID]);
try
if not FDM.dsArticles.Eof then
Result := FDM.dsArticles.AsObject<TArticle>
else
raise EServiceException.Create('Article not found');
finally
FDM.dsArticles.Close;
end;
Result := TMVCActiveRecord.GetByPK<TArticle>(AID);
end;
function TArticlesService.GetMeta: TJSONObject;
begin
FDM.dsArticles.Open('SELECT ID, CODICE as CODE, DESCRIZIONE as DESCRIPTION, PREZZO as PRICE, CREATED_AT as CREATEDAT, UPDATED_AT as UPDATEDAT FROM ARTICOLI WHERE TRUE = FALSE');
Result := FDM.dsArticles.MetadataAsJSONObject();
var lDS := TMVCActiveRecord.SelectDataSet('SELECT ID, CODICE as CODE, DESCRIZIONE as DESCRIPTION, PREZZO as PRICE, CREATED_AT as CREATEDAT, UPDATED_AT as UPDATEDAT FROM ARTICOLI WHERE TRUE = FALSE',[]);
try
Result := lDS.MetadataAsJSONObject()
finally
lDS.Free;
end;
end;
procedure TArticlesService.Update(AArticolo: TArticle);
var
Cmd: TFDCustomCommand;
begin
AArticolo.CheckUpdate;
Cmd := FDM.updArticles.Commands[arUpdate];
TFireDACUtils.ObjectToParameters(Cmd.Params, AArticolo, 'NEW_');
Cmd.ParamByName('OLD_ID').AsInteger := AArticolo.ID;
Cmd.Execute;
if Cmd.RowsAffected <> 1 then
raise Exception.Create('Article not found');
end;
{ TServiceBase }
procedure TServiceBase.Commit;
begin
FDM.Connection.Commit;
end;
constructor TServiceBase.Create(AdmMain: TdmMain);
begin
inherited Create;
FDM := AdmMain;
end;
procedure TServiceBase.Rollback;
begin
FDM.Connection.Rollback;
end;
procedure TServiceBase.StartTransaction;
begin
FDM.Connection.StartTransaction;
AArticolo.Update();
end;
end.

View File

@ -2,7 +2,8 @@ unit WebModuleUnit1;
interface
uses System.SysUtils, System.Classes, Web.HTTPApp, mvcframework;
uses System.SysUtils, System.Classes, Web.HTTPApp, mvcframework, FireDAC.Phys.FBDef, FireDAC.Stan.Intf, FireDAC.Phys,
FireDAC.Phys.IBBase, FireDAC.Phys.FB;
type
TWebModule1 = class(TWebModule)
@ -23,10 +24,13 @@ implementation
uses
Controllers.Articles,
MVCFramework.Middleware.CORS,
MVCFramework.Middleware.ActiveRecord,
MVCFramework.Middleware.Compression,
MVCFramework.Middleware.Trace,
MVCFramework.SQLGenerators.Firebird,
MVCFramework.Commons,
Controllers.Base;
Controllers.Base,
Commons;
{$R *.dfm}
@ -45,6 +49,8 @@ begin
{$ENDIF}
FEngine.AddMiddleware(TCORSMiddleware.Create);
FEngine.AddMiddleware(TMVCCompressionMiddleware.Create(256));
FEngine.AddMiddleware(TMVCActiveRecordMiddleware.Create(CON_DEF_NAME));
// FEngine.AddMiddleware(TMVCTraceMiddleware.Create);
end;

View File

@ -10,6 +10,7 @@ uses
MVCFramework.Commons,
MVCFramework.Signal,
MVCFramework.Logger,
MVCFramework.Container,
MVCFramework.dotEnv,
Web.WebReq,
Web.WebBroker,
@ -18,10 +19,10 @@ uses
Controllers.Articles in 'Controllers.Articles.pas',
Services in 'Services.pas',
BusinessObjects in 'BusinessObjects.pas',
MainDM in 'MainDM.pas' {dmMain: TDataModule},
Commons in 'Commons.pas',
MVCFramework.ActiveRecord in '..\..\sources\MVCFramework.ActiveRecord.pas',
MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas';
MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas',
FDConnectionConfigU in 'FDConnectionConfigU.pas';
{$R *.res}
@ -68,6 +69,12 @@ begin
.Build(); //uses the executable folder to look for .env* files
end);
CreateFirebirdPrivateConnDef(True);
DefaultMVCServiceContainer
.RegisterType(TArticlesService, IArticlesService, '', TRegistrationType.SingletonPerRequest)
.Build;
WebRequestHandlerProc.MaxConnections := dotEnv.Env('dmvc.handler.max_connections', 1024);
RunServer(dotEnv.Env('dmvc.server.port', 8080));
except

View File

@ -97,13 +97,10 @@
<DCCReference Include="Controllers.Articles.pas"/>
<DCCReference Include="Services.pas"/>
<DCCReference Include="BusinessObjects.pas"/>
<DCCReference Include="MainDM.pas">
<Form>dmMain</Form>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ActiveRecord.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas"/>
<DCCReference Include="FDConnectionConfigU.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>

View File

@ -23,14 +23,6 @@ type
procedure Build();
end;
MVCInjectAttribute = class(TCustomAttribute)
private
fServiceName: String;
public
constructor Create(ServiceName: String = '');
property ServiceName: String read fServiceName;
end;
EMVCContainerError = class(Exception) end;
EMVCContainerErrorUnknownService = class(EMVCContainerError) end;
EMVCContainerErrorInterfaceNotSupported = class(EMVCContainerError) end;
@ -45,7 +37,7 @@ type
implementation
uses
MVCFramework.Rtti.Utils;
MVCFramework.Rtti.Utils, MVCFramework;
type
IMVCServiceInternalResolver = interface
@ -314,15 +306,6 @@ begin
Result := TMVCServiceContainer.Create;
end;
{ MVCInjectAttribute }
constructor MVCInjectAttribute.Create(ServiceName: String);
begin
inherited Create;
fServiceName := ServiceName;
end;
{ TMVCServiceContainerAdapter }
constructor TMVCServiceContainerAdapter.Create(Container: IMVCServiceContainer);

View File

@ -315,7 +315,7 @@ begin
end;
if lMsg.Trim.IsEmpty then
lMsg := '<EOF>';
raise ERQLException.CreateFmt('[Error] %s (column %d - found %s)', [message, fCurIdx, lMsg]);
raise ERQLException.CreateFmt('[Error] %s (column %d - found %s)', [message, fCurIdx, lMsg]) at AddressOfReturnAddress;
end;
procedure TRQL2SQL.Execute(

View File

@ -338,6 +338,14 @@ type
end;
MVCInjectAttribute = class(TCustomAttribute)
private
fServiceName: String;
public
constructor Create(ServiceName: String = '');
property ServiceName: String read fServiceName;
end;
// test
// TMVCHackHTTPAppRequest = class(TIdHTTPAppRequest)
// private
@ -5051,6 +5059,16 @@ begin
inherited;
end;
{ MVCInjectAttribute }
{ MVCInjectAttribute }
constructor MVCInjectAttribute.Create(ServiceName: String);
begin
inherited Create;
fServiceName := ServiceName;
end;
initialization
// https://quality.embarcadero.com/browse/RSP-38281