unit uDataBase; interface uses System.SysUtils, System.Classes, FireDAC.Comp.Client, FireDAC.Stan.Param, FMX.Grid, FireDAC.Stan.Def, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteWrapper.Stat, FireDAC.VCLUI.Wait, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.FMXUI.Wait, FireDAC.Comp.UI, uRecords, System.Generics.Collections; type TSettingsDatabase = class private FConnection: TFDConnection; procedure InitializeDatabase; function GetSetting(const Name: string): string; procedure SetSetting(const Name, Value: string); function GetColumnsDefinition(Grid: TStringGrid): string; function GetColumnsList(Grid: TStringGrid): string; function GetValuesPlaceholders(Grid: TStringGrid): string; function CheckTableExists(const TableName: string): Boolean; public FChannel: string; constructor Create(const DatabasePath: string); destructor Destroy; override; // Методы для работы с настройками function ReadSetting(const Name: string; Default: string = ''): string; procedure WriteSetting(const Name, Value: string); function getLoginData(): TLogin; // Методы для работы с TStringGrid procedure SaveGridToTable(const TableName: string; Grid: TStringGrid); procedure LoadGridFromTable(const TableName: string; Grid: TStringGrid); // Методы для работы с Users // procedure SaveUsers(const Users: array of User); procedure LoadUsers(var users: tlist); // Методы для работы с Групповыми ответами procedure addGroupResponse(Name, Respons: string); procedure getGroupResponse(aName: string; const lbResponse: Tstrings); procedure getGroupName(const lbName: Tstrings); procedure delGroupName(aName: string); procedure delGroupResponse(aName, aResponse: string); end; implementation uses uGeneral; constructor TSettingsDatabase.Create(const DatabasePath: string); begin FConnection := TFDConnection.Create(nil); try FConnection.DriverName := 'SQLite'; FConnection.Params.Database := DatabasePath; FConnection.Connected := True; InitializeDatabase; except on E: Exception do begin FreeAndNil(FConnection); raise Exception.Create('Ошибка при подключении к базе данных: ' + E.Message); end; end; end; procedure TSettingsDatabase.delGroupName(aName: string); var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := 'delete FROM GroupResponse where Name = "' + aName + '"'; Query.ExecSQL; finally Query.Free; end; end; procedure TSettingsDatabase.delGroupResponse(aName, aResponse: string); var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := 'delete FROM GroupResponse where Name = :name' + ' and Response = :response'; Query.Params.ParamByName('name').AsString := aName; Query.Params.ParamByName('response').AsString := aResponse; Query.ExecSQL; finally Query.Free; end; end; destructor TSettingsDatabase.Destroy; begin if Assigned(FConnection) then FConnection.Connected := False; FreeAndNil(FConnection); inherited; end; procedure TSettingsDatabase.InitializeDatabase; var FDQuery: TFDQuery; FieldExists: Boolean; begin // Создаем таблицу, если она не существует FConnection.ExecSQL('CREATE TABLE IF NOT EXISTS params (' + ' name TEXT PRIMARY KEY,' + ' value TEXT' + ');'); // Создаем таблицу для пользователей, если она не существует FConnection.ExecSQL('CREATE TABLE IF NOT EXISTS users (' + ' id TEXT PRIMARY KEY,' + ' login TEXT,' + ' DisplayName TEXT,' + ' created_at DATETIME,' + ' follow_at DATETIME,' + ' isVip TEXT,' + ' isModer TEXT,' + ' isO TEXT,' + ' streamer TEXT' + ');'); FDQuery := TFDQuery.Create(nil); try FDQuery.Connection := FConnection; FieldExists := False; FDQuery.SQL.Text := 'PRAGMA table_info(users)'; FDQuery.Open; while not FDQuery.EOF do begin if FDQuery.FieldByName('name').AsString = 'streamer' then begin FieldExists := True; Break; end; FDQuery.Next; end; FDQuery.Close; if not FieldExists then begin FConnection.ExecSQL('ALTER TABLE users ADD COLUMN streamer TEXT'); end; finally FDQuery.Free; end; FConnection.ExecSQL ('CREATE TABLE IF NOT EXISTS GroupResponse (ID INTEGER PRIMARY KEY, Name TEXT, Response TEXT);'); end; { procedure TSettingsDatabase.SaveUsers(const Users: array of User); var Query: TFDQuery; UserItem: User; s: string; begin if Length(Users) < 1 then exit; // Вставляем данные из массива пользователей в таблицу Query := TFDQuery.Create(nil); try Query.Connection := FConnection; for UserItem in Users do begin Query.SQL.Text := 'INSERT OR REPLACE INTO users (id, login, DisplayName, created_at, follow_at, isVip, isModer, isO, streamer) ' + 'VALUES (:id, :login, :DisplayName, :created_at, :follow_at, :isVip, :isModer, :isO, :streamer);'; Query.ParamByName('id').AsString := UserItem.id; Query.ParamByName('login').AsString := UserItem.login; Query.ParamByName('DisplayName').AsString := UserItem.DisplayName; Query.ParamByName('created_at').AsDateTime := UserItem.created_at; Query.ParamByName('follow_at').AsDateTime := UserItem.follow_at; Query.ParamByName('streamer').AsString := FChannel; if UserItem.isVip then s := 'True' else s := 'False'; Query.ParamByName('isVip').AsString := s; if UserItem.isModer then s := 'True' else s := 'False'; Query.ParamByName('isModer').AsString := s; if UserItem.isO then s := 'True' else s := 'False'; Query.ParamByName('isO').AsString := s; Query.ExecSQL; end; finally Query.Free; end; end; } procedure TSettingsDatabase.LoadUsers(var users: tlist); var Query: TFDQuery; UserItem: tuser; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := 'SELECT * FROM users WHERE streamer = :streamer'; Query.ParamByName('streamer').AsString := FChannel; Query.Open; while not Query.EOF do begin UserItem.id := Query.FieldByName('id').AsString; UserItem.login := Query.FieldByName('login').AsString; UserItem.DisplayName := Query.FieldByName('DisplayName').AsString; UserItem.created_at := Query.FieldByName('created_at').AsDateTime; UserItem.follow_at := Query.FieldByName('follow_at').AsDateTime; UserItem.isVip := Query.FieldByName('isVip').AsString = 'True'; UserItem.isModer := Query.FieldByName('isModer').AsString = 'True'; UserItem.isO := Query.FieldByName('isO').AsString = 'True'; UserItem.isO_today := False; users.Add(UserItem); Query.Next; end; finally Query.Free; end; end; function TSettingsDatabase.GetColumnsDefinition(Grid: TStringGrid): string; var Col: Integer; begin Result := ''; for Col := 0 to Grid.ColumnCount - 1 do begin if Result <> '' then Result := Result + ', '; Result := Result + 'col' + IntToStr(Col) + ' TEXT'; end; end; function TSettingsDatabase.GetColumnsList(Grid: TStringGrid): string; var Col: Integer; begin Result := ''; for Col := 0 to Grid.ColumnCount - 1 do begin if Result <> '' then Result := Result + ', '; Result := Result + 'col' + IntToStr(Col); end; end; procedure TSettingsDatabase.getGroupName(const lbName: Tstrings); var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; lbName.Clear; Query.SQL.Text := 'SELECT DISTINCT Name FROM GroupResponse'; Query.Open; while not Query.EOF do begin lbName.Add(Query.FieldByName('Name').AsString); Query.Next; end; finally Query.Free; end; end; procedure TSettingsDatabase.getGroupResponse(aName: string; const lbResponse: Tstrings); var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; lbResponse.Clear; Query.SQL.Text := 'SELECT * FROM GroupResponse WHERE name=:TableName'; Query.ParamByName('TableName').AsString := aName; Query.Open; while not Query.EOF do begin lbResponse.Add(Query.FieldByName('Response').AsString); Query.Next; end; finally Query.Free; end; end; function TSettingsDatabase.getLoginData: TLogin; begin Result.TTV_Token_Bot := ReadSetting('edtBotToken'); Result.TTV_Token_Strimer := ReadSetting('edtBotTokenStreamer'); Result.TTV_Name_Bot := ReadSetting('edtBotName'); Result.TTV_Name_Strimer := ReadSetting('edtChannel'); Result.TTV_ClientID := ReadSetting('edtBotClientID'); Result.DA_ClientID := ReadSetting('edtDAClientID'); Result.DA_Client_Sictert := ReadSetting('edtDAClientSecret'); Result.DA_RedirectURL := ReadSetting('edtDARedirectURL'); Result.DA_Code := ReadSetting('edtDACode'); Result.AI_Gigachat_ClientID := ReadSetting('edtGPTClientID'); Result.AI_Gigachat_AutorizationCode := ReadSetting('edtGPTAC'); Result.AI_ChatGPT_Token := ReadSetting('edtGPTATChatGPT'); Result.AI_DeepSeek_Token := ReadSetting('edtGPTATDeepSeek'); end; function TSettingsDatabase.GetValuesPlaceholders(Grid: TStringGrid): string; var Col: Integer; begin Result := ''; for Col := 0 to Grid.ColumnCount - 1 do begin if Result <> '' then Result := Result + ', '; Result := Result + ':col' + IntToStr(Col); end; end; procedure TSettingsDatabase.addGroupResponse(Name, Respons: string); var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := Format('INSERT INTO GroupResponse (Name, Response) VALUES (''%s'', ''%s'')', [Name, Respons]); Query.ExecSQL; finally Query.Free; end; end; function TSettingsDatabase.CheckTableExists(const TableName: string): Boolean; var Query: TFDQuery; begin Result := False; Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := 'SELECT COUNT(*) FROM sqlite_master WHERE type=''table'' AND name=:TableName'; Query.ParamByName('TableName').AsString := TableName; Query.Open; Result := (Query.Fields[0].AsInteger > 0); finally Query.Free; end; end; procedure TSettingsDatabase.LoadGridFromTable(const TableName: string; Grid: TStringGrid); var Query: TFDQuery; Col, Row: Integer; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; // Проверить наличие таблицы if not CheckTableExists(TableName) then begin // Таблица не существует, выходим из процедуры exit; end; Query.SQL.Text := 'SELECT * FROM ' + TableName; Query.Open; // Очищаем Grid Grid.RowCount := 0; // Заполняем Grid данными из таблицы while not Query.EOF do begin Row := Grid.RowCount; Grid.RowCount := Grid.RowCount + 1; for Col := 0 to Grid.ColumnCount - 1 do begin Grid.Cells[Col, Row] := Query.FieldByName('col' + IntToStr(Col) ).AsString; end; Query.Next; end; finally Query.Free; end; end; procedure TSettingsDatabase.SaveGridToTable(const TableName: string; Grid: TStringGrid); var Query: TFDQuery; Col, Row: Integer; begin // Удаляем старую таблицу, если она существует FConnection.ExecSQL('DROP TABLE IF EXISTS ' + TableName); // Создаем новую таблицу FConnection.ExecSQL('CREATE TABLE ' + TableName + ' (' + ' id INTEGER PRIMARY KEY AUTOINCREMENT,' + ' ' + GetColumnsDefinition(Grid) + ');'); // Вставляем данные из Grid в таблицу Query := TFDQuery.Create(nil); try Query.Connection := FConnection; for Row := 0 to Grid.RowCount - 1 do begin Query.SQL.Text := 'INSERT INTO ' + TableName + ' (' + GetColumnsList(Grid) + ') VALUES (' + GetValuesPlaceholders(Grid) + ')'; for Col := 0 to Grid.ColumnCount - 1 do begin Query.ParamByName('col' + IntToStr(Col)).AsString := Grid.Cells[Col, Row]; end; Query.ExecSQL; end; finally Query.Free; end; end; function TSettingsDatabase.GetSetting(const Name: string): string; var Query: TFDQuery; begin Query := TFDQuery.Create(nil); try Query.Connection := FConnection; Query.SQL.Text := 'SELECT value FROM params WHERE name = :name'; Query.ParamByName('name').AsString := Name; Query.Open; if not Query.IsEmpty then Result := Query.FieldByName('value').AsString else Result := ''; finally Query.Free; end; end; procedure TSettingsDatabase.SetSetting(const Name, Value: string); begin FConnection.ExecSQL ('INSERT OR REPLACE INTO params (name, value) VALUES (:name, :value)', [Name, Value]); end; function TSettingsDatabase.ReadSetting(const Name: string; Default: string = ''): string; begin Result := GetSetting(Name); if Result = '' then Result := Default; end; procedure TSettingsDatabase.WriteSetting(const Name, Value: string); begin SetSetting(Name, Value); end; end.