//////////////////////////////////////////////////
//  Universal Data Access Components
//  Copyright © 2009-2013 Devart. All right reserved.
//////////////////////////////////////////////////

{$IFNDEF CLR}
{$I NexusDac.inc}
{$IFDEF VER10P}
{$I NexusDBUniProvider.inc}
{$ENDIF}
unit NexusDBUniProvider;
{$ENDIF}

interface

uses
  SysUtils, Classes, Variants, DB, CRAccess, CRConnectionPool, MemData,
  {$IFNDEF FPC}MemDS{$ELSE}MemDataSet{$ENDIF}, DBAccess,
  CRTypes, CRParser, CRDataTypeMap,
  DAScript, DADump, Uni, UniProvider;

type
  TNexusDBUniProvider = class(TUniProvider)
  public
    class function GetProviderName: string; override;

    function IsDatabaseSupported: boolean; override;
    function IsPortSupported: boolean; override;
    function IsInOutParamSupported: boolean; override;
    function IsPoolingSupported: boolean; override;

    function GetParserClass: TSQLParserClass; override;
    function GetConnectionParametersClass: TCRConnectionParametersClass; override;
    function GetConnectionPoolingManagerClass: TCRConnectionPoolManagerClass; override;
    function GetConnectionClass: TCRConnectionClass; override;
    function GetServerEnumeratorClass: TCRServerEnumeratorClass; override;
    function GetTransactionClass: TCRTransactionClass; override;
    function GetCommandClass: TCRCommandClass; override;
    function GetRecordSetClass: TCRRecordSetClass; override;
    function GetDataSetServiceClass: TDADataSetServiceClass; override;
    function GetScriptProcessorClass: TDAScriptProcessorClass; override;
    function GetLoaderClass: TCRLoaderClass; override;
    function GetDumpProcessorClass: TDADumpProcessorClass; override;
    function GetMetaDataClass: TCRMetaDataClass; override;
    function GetConnectDialogServiceClass: TConnectDialogServiceClass; override;
    function GetFieldTypeMapClass: TDAFieldTypeMapClass; override;
    function GetSqlFormatterClass: TUniSqlFormatterClass; override;
    function GetConverterManagerClass: TConverterManagerClass; override;

    procedure SetObjectProps(Obj: TObject; Options: TStrings; SetAllProps: boolean); override;

    function GetConnectionOptions: TOptionsList; override;
    function GetSQLOptions: TOptionsList; override;
    function GetDataSetOptions: TOptionsList; override;
    function GetLoaderOptions: TOptionsList; override;
  end;

  TNexusConnectDialogService = class(TConnectDialogService)
  public
    function UseDatabaseHistory: boolean; override;
  end;

  TNexusFormatter = class(TUniSqlFormatter)
  protected
  public
    constructor Create; override;
  end;

{$IFNDEF FPC}
procedure RegisterComponent;
{$ELSE}
procedure Register;
{$ENDIF}

implementation

uses
  DAConsts, UniConsts,
{$IFNDEF UNIDACPRO}
  NexusClasses, NexusParser, NexusServices, NexusConnectionPool,
  NexusDataTypeMap;
{$ELSE}
  NexusClassesUni, NexusParserUni, NexusServicesUni, NexusConnectionPoolUni,
  NexusDataTypeMapUni;
{$ENDIF}

{$IFDEF DUMMY}
const
  SNeedRecompileNexusDB = 'NexusDB provider should be recompiled.'#13#10 +
    'For more information read the "Using UniDAC with NexusDB" topic of the UniDAC help';
{$ENDIF}

var
  NexusFunctions, NexusMacros: TStrValueStringList;

class function TNexusDBUniProvider.GetProviderName: string;
begin
  Result := 'NexusDB';
end;

function TNexusDBUniProvider.IsDatabaseSupported: boolean;
begin
  Result := True;
end;

function TNexusDBUniProvider.IsPortSupported: boolean;
begin
  Result := True;
end;

function TNexusDBUniProvider.IsInOutParamSupported: boolean;
begin
  Result := True;
end;

function TNexusDBUniProvider.IsPoolingSupported: boolean;
begin
  Result := True;
end;

function TNexusDBUniProvider.GetParserClass: TSQLParserClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusParser;
{$ELSE}
  Result := TSQLParser;
{$ENDIF}
end;

function TNexusDBUniProvider.GetConnectionParametersClass: TCRConnectionParametersClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusConnectionParameters;
{$ELSE}
  Result := TCRConnectionParameters;
{$ENDIF}
end;

function TNexusDBUniProvider.GetConnectionPoolingManagerClass: TCRConnectionPoolManagerClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusConnectionPoolManager;
{$ELSE}
  Result := TCRConnectionPoolManager;
{$ENDIF}
end;

function TNexusDBUniProvider.GetConnectionClass: TCRConnectionClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusConnection;
{$ELSE}
  raise Exception.Create(SNeedRecompileNexusDB);
  Result := TCRConnection;
{$ENDIF}
end;

function TNexusDBUniProvider.GetServerEnumeratorClass: TCRServerEnumeratorClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusServerEnumerator;
{$ELSE}
  Result := TCRServerEnumerator;
{$ENDIF}
end;

function TNexusDBUniProvider.GetTransactionClass: TCRTransactionClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusTransaction;
{$ELSE}
  Result := TCRTransaction;
{$ENDIF}
end;

function TNexusDBUniProvider.GetCommandClass: TCRCommandClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusCommand;
{$ELSE}
  Result := TCRCommand;
{$ENDIF}
end;

function TNexusDBUniProvider.GetRecordSetClass: TCRRecordSetClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusRecordSet;
{$ELSE}
  Result := TCRRecordSet;
{$ENDIF}
end;

function TNexusDBUniProvider.GetDataSetServiceClass: TDADataSetServiceClass;
begin
{$IFNDEF DUMMY}
  Result := TCustomNexusDataSetService;
{$ELSE}
  Result := TDADataSetService;
{$ENDIF}
end;

function TNexusDBUniProvider.GetScriptProcessorClass: TDAScriptProcessorClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusScriptProcessor;
{$ELSE}
  Result := TDAScriptProcessor;
{$ENDIF}
end;

function TNexusDBUniProvider.GetLoaderClass: TCRLoaderClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusLoader;
{$ELSE}
  Result := TCRLoader;
{$ENDIF}
end;

function TNexusDBUniProvider.GetDumpProcessorClass: TDADumpProcessorClass;
begin
{$IFNDEF DUMMY}
  Result := TCustomNexusDumpProcessor;
{$ELSE}
  Result := TDADumpProcessor;
{$ENDIF}
end;

function TNexusDBUniProvider.GetMetaDataClass: TCRMetaDataClass;
begin
{$IFNDEF DUMMY}
  Result := TNexusMetaData;
{$ELSE}
  Result := TCRMetaData;
{$ENDIF}
end;

function TNexusDBUniProvider.GetFieldTypeMapClass: TDAFieldTypeMapClass;
begin
{$IFNDEF DUMMY}
  Result := TCustomNexusFieldTypeMap;
{$ELSE}
  Result := TDAFieldTypeMap;
{$ENDIF}
end;

function TNexusDBUniProvider.GetConnectDialogServiceClass: TConnectDialogServiceClass;
begin
  Result := TNexusConnectDialogService;
end;

function TNexusDBUniProvider.GetSqlFormatterClass: TUniSqlFormatterClass;
begin
  Result := TNexusFormatter;
end;

function TNexusDBUniProvider.GetConverterManagerClass: TConverterManagerClass;
begin
  Result := TNexusConverterManager;
end;

procedure TNexusDBUniProvider.SetObjectProps(Obj: TObject; Options: TStrings; SetAllProps: boolean);
begin
  inherited;
end;

function TNexusDBUniProvider.GetConnectionOptions: TOptionsList;
begin
  if FConnectionOptions = nil then begin
    FConnectionOptions := TOptionsList.Create(GetProviderName);
  {$IFNDEF DUMMY}
    FConnectionOptions.Add(TIntegerOption.Create('ConnectionTimeout', prConnectionTimeout, [TNexusConnection, TNexusConnectionParameters], 15));
    FConnectionOptions.Add(TIntegerOption.Create('HeartbeatInterval', prHeartbeatInterval, [TNexusConnection, TNexusConnectionParameters], 10));
    FConnectionOptions.Add(TIntegerOption.Create('LostConnectionTimeout', prLostConnectionTimeout, [TNexusConnection, TNexusConnectionParameters], 10));
    FConnectionOptions.Add(TIntegerOption.Create('WatchdogInterval', prWatchdogInterval, [TNexusConnection, TNexusConnectionParameters], 10));
    FConnectionOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TNexusConnection, TNexusConnectionParameters], 15));
    FConnectionOptions.Add(TBooleanOption.Create('DatabaseReadOnly', prDatabaseReadOnly, [TNexusConnection, TNexusConnectionParameters], False));
  {$ELSE}
    raise Exception.Create(SNeedRecompileNexusDB);
  {$ENDIF}
  end;
  Result := FConnectionOptions;
end;

function TNexusDBUniProvider.GetSQLOptions: TOptionsList;
begin
  if FSQLOptions = nil then begin
    FSQLOptions := TOptionsList.Create(GetProviderName);
  {$IFNDEF DUMMY}
    FSQLOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TNexusCommand], 15));
    FSQLOptions.Add(TBooleanOption.Create('ReadOnly', prCommandReadOnly, [TNexusCommand], False));
  {$ENDIF}
  end;
  Result := FSQLOptions;
end;

function TNexusDBUniProvider.GetDataSetOptions: TOptionsList;
begin
  if FDataSetOptions = nil then begin
    FDataSetOptions := TOptionsList.Create(GetProviderName);
  {$IFNDEF DUMMY}
    FDataSetOptions.Add(TBooleanOption.Create('FetchAll', prFetchAll, [TNexusRecordSet], False));
    FDataSetOptions.Add(TBooleanOption.Create('CursorUpdate', prCursorUpdate, [TNexusRecordSet], True));
    FDataSetOptions.Add(TBooleanOption.Create('ServerCursor', prServerCursor, [TNexusRecordSet], False));

    FDataSetOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TNexusCommand], 15));
    FDataSetOptions.Add(TBooleanOption.Create('ReadOnly', prCommandReadOnly, [TNexusCommand], False));
  {$ENDIF}
  end;
  Result := FDataSetOptions;
end;

function TNexusDBUniProvider.GetLoaderOptions: TOptionsList;
begin
  if FLoaderOptions = nil then begin
    FLoaderOptions := TOptionsList.Create(GetProviderName);
  {$IFNDEF DUMMY}
    FLoaderOptions.Add(TBooleanOption.Create('DirectLoad', prDirectLoad, [TNexusLoader], True));
  {$ENDIF}
  end;
  Result := FLoaderOptions;
end;

{ TNexusConnectDialogService }

function TNexusConnectDialogService.UseDatabaseHistory: boolean;
begin
  Result := True;
end;

{ TNexusFormatter }

constructor TNexusFormatter.Create;
begin
  inherited;

  FFunctions := NexusFunctions;
  FPredefinedMacros := NexusMacros;
end;

{$IFNDEF FPC}
procedure RegisterComponent;
{$ELSE}
procedure Register;
{$ENDIF}
begin
  RegisterComponents('UniDAC Providers', [TNexusDBUniProvider]);
end;

initialization
  UniProviders.RegisterProvider(TNexusDBUniProvider);

  NexusFunctions := TStrValueStringList.Create;
  //NexusFunctions.Add('USER', '');
  NexusFunctions.Add('CHAR_LENGTH', 'LENGTH(%s)');
  //NexusFunctions.Add('LOCATE', 'STRPOS(%1:s, %0:s)');
  NexusFunctions.Add('SUBSTRING', 'SUBSTR(%s, %s, %s)');
  NexusFunctions.Add('CONCAT', '%s || %s');
  //NexusFunctions.Add('CHAR', 'CHR(%s)');
  NexusFunctions.Add('TRIM', 'TRIM(%s)');
  //NexusFunctions.Add('TRUNCATE', 'TRUNC(%s, %s)');
  //NexusFunctions.Add('CEILING', 'CEILING(%s)');
  // Date-time
  NexusFunctions.Add('CURRENT_DATE', 'CURRENT_DATE');
  //NexusFunctions.Add('YEAR', 'EXTRACT(YEAR FROM %s)');
  //NexusFunctions.Add('MONTH', 'EXTRACT(MONTH FROM %s)');
  //NexusFunctions.Add('DAY', 'EXTRACT(DAY FROM %s)');
  NexusFunctions.Add('DATEADD', 'DATE(%2:s, ''%1:s %0:s'')');
  //NexusFunctions.Add('DATEDIFF', 'EXTRACT(%s FROM (%2:s - %1:s))');
  // Date-time literals
  NexusFunctions.Add('__DATE_TIME_LITERAL', '%s');
  NexusFunctions.Add('__DATE_LITERAL', '%s');
  NexusFunctions.Add('__TIME_LITERAL', '%s');
  // CONVERT functions
  NexusFunctions.Add('TODATE', 'CAST(%s AS VARCHAR)');
  NexusFunctions.Add('TONUMBER', 'CAST(%s AS DOUBLE)');
  NexusFunctions.Add('TOCHAR', 'CAST(%s AS VARCHAR)');

  NexusMacros := TStrValueStringList.Create;
  NexusMacros.Add('PROVIDER', 'NexusDB');
  NexusMacros.Add('NexusDB', '');
  // DataType macros
  NexusMacros.Add('DATETIME', 'TEXT');
  NexusMacros.Add('DOUBLE', 'DOUBLE');
  NexusMacros.Add('VARCHAR', 'VARCHAR');

finalization
  UniProviders.UnRegisterProvider(TNexusDBUniProvider);

  NexusFunctions.Free;
  NexusMacros.Free;

end.
