unit Aurelius.Sql.Interfaces;

{$I Aurelius.inc}

interface

uses
  TypInfo, Generics.Collections, DB,
  Aurelius.Global.Utils,
  Aurelius.Sql.BaseTypes,
  Aurelius.Sql.Commands,
  Aurelius.Sql.Metadata,
  Aurelius.Drivers.Interfaces;

type
  TSequentialGuidMode = Aurelius.Global.Utils.TSequentialGuidMode;

  TFieldTypeSet = set of TFieldType;

  TDBFeature = (Sequences, AutoGenerated, ForeignKeys, AlterTableForeignKey, DropUniqueKey,
    RetrieveIdOnInsert, Schemas);
  TDBFeatures = set of TDBFeature;

  TFieldTypeEquivalence = record
  public
    NotSupportedType: TFieldType;
    EquivalentType: TFieldType;
    EquivalentLenth: Integer;
    EquivalentPrecision: Integer;
    EquivalentScale: Integer;
  end;

  TFieldTypeEquivArray = array of TFieldTypeEquivalence;

  ISQLFunction = interface
  ['{3D7707C4-D463-45A0-97DB-2598E814B8DF}']
    function BuildSql(AArgs: TArray<string>): string;
    function ResultType(ArgTypes: TArray<PTypeInfo>): PTypeInfo;
  end;

  ISQLGenerator = interface
    ['{8F53DC09-2A7B-4DAF-8430-8AE5B424E210}']

    // Generators
    function GetGeneratorName: string;
    property GeneratorName: string read GetGeneratorName;

    // Mapping to the connection driver
    function GetSqlDialect: string;
    property SqlDialect: string read GetSqlDialect;

    // standard DML methods
    function GenerateSelect(Command: TSelectCommand): string;
    function GenerateInsert(Command: TInsertCommand): string;
    function GenerateUpdate(Command: TUpdateCommand): string;
    function GenerateDelete(Command: TDeleteCommand): string;
    function GetQualifiedColumnName(Field: TSQLSelectField): string;

    // specific DML methods
    function GenerateGetNextSequenceValue(Command: TGetNextSequenceValueCommand): string;
    function GenerateGetLastInsertId(SQLField: TSQLField): string;

    // DDL methods
    function GenerateCreateTable(Table: TTableMetadata; CreateForeignKeys: boolean): string;
    function GenerateCreateForeignKey(ForeignKey: TForeignKeyMetadata): string;
    function GenerateCreateSequence(Sequence: TSequenceMetadata): string;
    function GenerateCreateUniqueKey(UniqueKey: TUniqueKeyMetadata): string;
    function GenerateCreateDBIndex(DBIndex: TDBIndexMetadata): string;
    function GenerateDropDBIndex(DBIndex: TDBIndexMetadata): string;
    function GenerateDropTable(Table: TTableMetadata): string;
    function GenerateDropForeignKey(ForeignKey: TForeignKeyMetadata): string;
    function GenerateDropSequence(Sequence: TSequenceMetadata): string;
    function GenerateDropUniqueKey(UniqueKey: TUniqueKeyMetadata): string;
    function GenerateCreateColumn(Column: TColumnMetadata): string;
    function GenerateDropField(Column: TColumnMetadata): string;
    procedure DefineColumnType(Column: TColumnMetadata);

    // Disable/Enable foreign keys
    function GenerateEnableForeignKeys(AEnable: boolean): string;

    // Types/constants methods
    function GetSqlLiteral(AValue: Variant; AType: TFieldType): string;

    // Methods for compatibility between different databases
    function GetSupportedFeatures: TDBFeatures;
    property SupportedFeatures: TDBFeatures read GetSupportedFeatures;

    // Methods for field type/value conversion
    function GetSupportedFieldTypes: TFieldTypeSet;
    property SupportedFieldTypes: TFieldTypeSet read GetSupportedFieldTypes;
    function GetEquivalentFieldTypes: TFieldTypeEquivArray;
    property EquivalentFieldTypes: TFieldTypeEquivArray read GetEquivalentFieldTypes;
    function ConvertValue(Value: Variant; FromType, ToType: TFieldType): Variant;

    // Methods for fields/param naming
    function GetDefaultParamName(Field: TSQLField): string;
    function GetDefaultColumnName(Field: TSQLSelectField): string;

    function GetForeignKeyName(ForeignKey: TForeignKeyMetadata): string;
    function GetUniqueKeyName(UniqueKey: TUniqueKeyMetadata): string;
    function GetFullTableName(const ATable, ASchema: string): string;

    // Function to be called right before each command is executed
    procedure ProcessCommand(var SQL: string);

    function GetOptimalGuidMode: TSequentialGuidMode;

    function FindSQLFunction(const AFunctionName: string): ISQLFunction;
    procedure RegisterFunction(const AFunctionName: string; ASQLFunction: ISQLFunction);
  end;

  ISQLPerformer = interface
    function ExecuteQuery(SQL: string; Params: TList<TDBParam>): IDBResultSet;
    function Execute(SQL: string; Params: TList<TDBParam>): Integer;
  end;

  ICommandPerformer = interface(ISQLPerformer)
    function CreateSQLTable: TSQLTable;
  end;

implementation

end.
