Files
lazarus-ccr/components/tvplanit/source/vpsqlds.pas

446 lines
14 KiB
ObjectPascal
Raw Normal View History

{*********************************************************}
{* VPSQLDS.PAS 1.03 *}
{*********************************************************}
{* ***** BEGIN LICENSE BLOCK ***** *}
{* Version: MPL 1.1 *}
{* *}
{* The contents of this file are subject to the Mozilla Public License *}
{* Version 1.1 (the "License"); you may not use this file except in *}
{* compliance with the License. You may obtain a copy of the License at *}
{* http://www.mozilla.org/MPL/ *}
{* *}
{* Software distributed under the License is distributed on an "AS IS" basis, *}
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
{* for the specific language governing rights and limitations under the *}
{* License. *}
{* *}
{* The Original Code is TurboPower Visual PlanIt *}
{* *}
{* The Initial Developer of the Original Code is TurboPower Software *}
{* *}
{* Portions created by TurboPower Software Inc. are Copyright (C) 2002 *}
{* TurboPower Software Inc. All Rights Reserved. *}
{* *}
{* Contributor(s): *}
{* Hannes Danzl *}
{* *}
{* ***** END LICENSE BLOCK ***** *}
{This unit was provided by Hannes Danzl and is used here with permission }
// implements a Visual PlanIt datastore for SQL databases. uses interfaced
// tdataset descendants to create datasets of different dbengines and
// descendants of TBaseSQLDialect for being as independent from the sql
// dialect as possible
unit VPSQLDS;
interface
uses
classes, VPSQLDialect, db, sysutils, vpDBDs, VPDbIntf, dialogs,
vpConst, vpBase, vpData, vpBaseDS, vpException;
type
// the datastore class; for easier extension and flexibilitiy, the datastore
// handles every VPI table as an internal store; these stores are created
// in the CreateStores method and linked into the fStores Stringlist. The
// objects are TBaseSQLDialect descendants. Access from an app to this stores
// is over the Stores property
TVPSQLDataStore = class(TVpCustomDBDataStore)
protected
// internal list of stores and the according objects;
// for every "dataset" an internal store of type TBaseSQLDialect is
// created, it's DBEngine is assigned the correct value
fStores: TStringlist;
// see ConnectionParams
fConnectionParams: TStrings;
// see Session
fSession: TComponent;
// see SQLDialect
fSQLDialect: String;
// see DBEngine
fDBEngine: String;
// see Stores
function GetStore(StoreName: String): TVpBaseSQLDialect;
// see ConnectionParams
procedure SetConnectionParams(const Value: TStrings); virtual;
// see Session
procedure SetSession(const Value: TComponent); virtual;
// see SQLDialect
procedure SetSQLDialect(const Value: String); virtual;
// see DBEngine
procedure SetDBEngine(const Value: String); virtual;
// creates one store (internal use)
function CreateStore(DBEngine: String): TVpBaseSQLDialect; virtual;
// (should) create all stores
procedure CreateStores; virtual;
// frees all stores
procedure FreeStores; virtual;
// calls the TVpBaseSQLDialect.CreateTable method for the correct store
procedure CreateTable(aTableName: String); virtual;
// sets ConnectionParams and Session for all stores; typically called before
// Connected is set to true
procedure SetSessionAndParams; virtual;
// returns the Dataset of the Resource store
function GetResourceTable : TDataset; override;
// returns the Dataset of the Events store
function GetEventsTable : TDataset; override;
// returns the Dataset of the Contacts store
function GetContactsTable : TDataset; override;
// returns the Dataset of the Tasks store
function GetTasksTable : TDataset; override;
// handles AutoConnect and AutoCreate properties
procedure Loaded; override;
// connects the datastore to the database
procedure SetConnected(const Value: boolean);override;
public
// constructor
constructor Create(aOwner:TComponent); override;
// destructor
destructor Destroy; override;
// returns the next id for a store by doing an equivalent of select max(id) from table
// and increasing the number by one
function GetNextID(TableName: string): Integer; override;
// post changes to the store
procedure PostResources; override;
// post changes to the store
procedure PostEvents; override;
// post changes to the store
procedure PostContacts; override;
// post changes to the store
procedure PostTasks; override;
// purge the given resource
procedure PurgeResource(Res: TVpResource); override;
// purge all items of the store belonging to the given resource
procedure PurgeContacts(Res: TVpResource); override;
// purge all items of the store belonging to the given resource
procedure PurgeEvents(Res: TVpResource); override;
// purge all items of the store belonging to the given resource
procedure PurgeTasks(Res: TVpResource); override;
// returns the named store
property Stores[StoreName: String]: TVpBaseSQLDialect read GetStore;
published
// DBEninge to use; see swhDatabaseIntf.pas for more info
property DBEngine: String read fDBEngine write SetDBEngine;
// SQL Dialect to use; see swhSQLDialect.pas for more info
property SQLDialect: String read fSQLDialect write SetSQLDialect;
// optional connection parameters for creating the dataset or alternatively
// use the Session property
property ConnectionParams: TStrings read fConnectionParams write SetConnectionParams;
// an untyped session that is passed through to the ISQLDataset; it's the
// responsisbility of the dataset to handle it
property Session: TComponent read fSession write SetSession;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Visual PlanIt', [TVPSQLDataStore]);
end;
{ TVPSQLDataStore }
procedure TVPSQLDataStore.CreateTable(aTableName: String);
var
aDs: TDataset;
aTable: TVpBaseSQLDialect;
fDefs: TFieldDefs;
begin
aDs:=TDataset.Create(nil);
fDefs:=TFieldDefs.Create(ads);
try
CreateFieldDefs(aTableName, fDefs);
assert(FDefs.Count>0);
aTable:=Stores[aTableName];
if aTable<>nil then
aTable.CreateTable(aTableName, FDefs, nil);
finally
fDefs.Free;
aDs.free;
end;
end;
function TVPSQLDataStore.GetStore(StoreName: String): TVpBaseSQLDialect;
begin
result := nil;
if fStores.IndexOf(StoreName) > -1 then
result := TVpBaseSQLDialect(fStores.Objects[fStores.IndexOf(StoreName)]);
end;
function TVPSQLDataStore.CreateStore(DBEngine: String): TVpBaseSQLDialect;
begin
result:=TVpBaseSQLDialect(sSQLDialectFactory.CreateInstance(SQLDialect));
Result.DBEngine:=DBEngine;
end;
procedure TVPSQLDataStore.SetDBEngine(const Value: String);
begin
fDBEngine := Value;
end;
procedure TVPSQLDataStore.CreateStores;
var
aStore: TVpBaseSQLDialect;
begin
aStore := CreateStore(fDbEngine);
fStores.AddObject(ResourceTableName, aStore);
aStore := CreateStore(fDbEngine);
fStores.AddObject(EventsTableName, aStore);
aStore := CreateStore(fDbEngine);
fStores.AddObject(ContactsTableName, aStore);
aStore := CreateStore(fDbEngine);
fStores.AddObject(TasksTableName, aStore);
aStore := CreateStore(fDbEngine);
// CreateFieldDefs('_Temp', aStore.Fields);
fStores.AddObject('_Temp', aStore);
end;
constructor TVPSQLDataStore.Create(aOwner: TComponent);
begin
inherited;
fStores := TStringlist.Create;
fConnectionParams := TStringlist.Create;
end;
destructor TVPSQLDataStore.Destroy;
begin
FreeStores;
fStores.free;
fConnectionParams.free;
inherited;
end;
procedure TVPSQLDataStore.FreeStores;
begin
while fStores.Count > 0 do // Iterate
begin
if fStores.Objects[0] <> nil then
fStores.Objects[0].free;
fStores.Delete(0);
end;
end;
procedure TVPSQLDataStore.SetConnectionParams(const Value: TStrings);
begin
fConnectionParams.Assign(Value);
SetSessionAndParams;
end;
procedure TVPSQLDataStore.SetSessionAndParams;
var
j: Integer;
begin
for j:=0 to fStores.Count-1 do
begin
TVpBaseSQLDialect(fStores.Objects[j]).Session:=fSession;
TVpBaseSQLDialect(fStores.Objects[j]).ConnectionParams:=fConnectionParams;
end;
end;
procedure TVPSQLDataStore.SetSession(const Value: TComponent);
begin
fSession := Value;
SetSessionAndParams;
end;
procedure TVPSQLDataStore.SetSQLDialect(const Value: String);
begin
fSQLDialect := Value;
end;
procedure TVPSQLDataStore.SetConnected(const Value: boolean);
var
j: Integer;
aStore: TVpBaseSQLDialect;
begin
{ Don't connect at designtime }
if csDesigning in ComponentState then Exit;
{ Don't try to connect until we're all loaded up }
if csLoading in ComponentState then Exit;
FreeStores;
CreateStores;
SetSessionAndParams;
try
for j := 0 to fStores.Count-1 do // Iterate
begin
if (fStores[j]<>'') and (fStores[j][1]<>'_') then
try
aStore:=Stores[fStores[j]];
aStore.Close;
aStore.SQL:=StringReplace(aStore.SelectSQL, '%TableName%', fStores[j], [rfIgnoreCase]);
aStore.Open;
except
if AutoCreate then
begin
TVpBaseSQLDialect(fStores.Objects[j]).EnsureDatabaseExists;
CreateTable(fStores[j]);
aStore.SQL:=StringReplace(aStore.SelectSQL, '%TableName%', fStores[j], [rfIgnoreCase]);
aStore.Open;
end;
end;
end; // for
inherited;
Load;
except
on e: exception do
showmessage(e.message);
end;
end;
procedure TVPSQLDataStore.Loaded;
begin
inherited;
if not (csDesigning in ComponentState) then
Connected := AutoConnect;
end;
function TVPSQLDataStore.GetContactsTable: TDataset;
begin
result:=Stores[ContactsTableName].Dataset;
end;
function TVPSQLDataStore.GetEventsTable: TDataset;
begin
result:=Stores[EventsTableName].Dataset;
end;
function TVPSQLDataStore.GetResourceTable: TDataset;
begin
result:=Stores[ResourceTableName].Dataset;
end;
function TVPSQLDataStore.GetTasksTable: TDataset;
begin
result:=Stores[TasksTableName].Dataset;
end;
function TVPSQLDataStore.GetNextID(TableName: string): Integer;
var
FldName : string;
begin
try
if TableName = ResourceTableName then
FldName := 'ResourceID'
else
FldName := 'RecordID';
Stores['_Temp'].Close;
Stores['_Temp'].SQL := 'Select Max(' + FldName + ') as LastID from ' + TableName;
Stores['_Temp'].Open;
result := Stores['_Temp'].Dataset.FieldByName('LastID').AsInteger + 1;
if result < 0 then
result := 0;
finally
Stores['_Temp'].Close;
end;
end;
{=====}
procedure TVPSQLDataStore.PostResources;
var
TableName: String;
begin
TableName:=ResourceTableName;
Stores[TableName].SQL := StringReplace(
Stores[TableName].SelectSQL, '%TableName%', TableName, [rfIgnoreCase]);
Stores[TableName].Open;
inherited;
end;
{=====}
procedure TVPSQLDataStore.PostEvents;
var
TableName: String;
begin
TableName:=EventsTableName;
Stores[TableName].SQL := StringReplace(
Stores[TableName].SelectSQL, '%TableName%', TableName, [rfIgnoreCase]);
Stores[TableName].Open;
inherited;
end;
{=====}
procedure TVPSQLDataStore.PostContacts;
var
TableName: String;
begin
TableName:=ContactsTableName;
Stores[TableName].SQL := StringReplace(
Stores[TableName].SelectSQL, '%TableName%', TableName, [rfIgnoreCase]);
Stores[TableName].Open;
inherited;
end;
{=====}
procedure TVPSQLDataStore.PostTasks;
var
TableName: String;
begin
TableName:=TasksTableName;
Stores[TableName].SQL := StringReplace(
Stores[TableName].SelectSQL, '%TableName%', TableName, [rfIgnoreCase]);
Stores[TableName].Open;
inherited;
end;
{=====}
procedure TVPSQLDataStore.PurgeResource(Res: TVpResource);
begin
Res.Deleted := true;
PostResources;
Load;
end;
{=====}
procedure TVPSQLDataStore.PurgeEvents(Res: TVpResource);
begin
Stores[EventsTableName].sql := 'delete from ' + EventsTableName
+ ' where ResourceID = ' + IntToStr(Res.ResourceID);
Stores[EventsTableName].ExecSQL;
Res.Schedule.ClearEvents;
end;
{=====}
procedure TVPSQLDataStore.PurgeContacts(Res: TVpResource);
begin
Stores[ContactsTableName].sql := 'delete from ' + ContactsTableName
+ ' where ResourceID = ' + IntToStr(Res.ResourceID);
Stores[ContactsTableName].ExecSQL;
Res.Contacts.ClearContacts;
end;
{=====}
procedure TVPSQLDataStore.PurgeTasks(Res: TVpResource);
begin
Stores[TasksTableName].sql := 'delete from ' + TasksTableName
+ ' where ResourceID = ' + IntToStr(Res.ResourceID);
Stores[TasksTableName].ExecSQL;
Res.Tasks.ClearTasks;
end;
{=====}
end.