|
From: <na...@us...> - 2009-08-16 17:00:02
|
Revision: 830
http://instantobjects.svn.sourceforge.net/instantobjects/revision/?rev=830&view=rev
Author: nandod
Date: 2009-08-16 16:59:53 +0000 (Sun, 16 Aug 2009)
Log Message:
-----------
+ New validation framework; initial implementation substitutes TInstantAttributeMatadata.ValidChars; can be extended. Tests added.
- Removed unused TChars support in filers. Limited use of TChars (ANSI-only) to where strictly necessary.
* Fixed: writing to a blob did not always correctly set IsChanged (historical error, probably).
* Fixed: ValidChars was not always correctly applied in blob fields (historical error, probably),
* Removed a few warnings on D2007/D2009.
Modified Paths:
--------------
trunk/Source/Brokers/ADO/InstantADOTools.pas
trunk/Source/Brokers/ADS/InstantADS.pas
trunk/Source/Core/D2007/IOCore.dpk
trunk/Source/Core/D2007/IOCore.dproj
trunk/Source/Core/D2009/IOCore.dpk
trunk/Source/Core/D2009/IOCore.dproj
trunk/Source/Core/D2009/IOCore.res
trunk/Source/Core/InstantClasses.pas
trunk/Source/Core/InstantCode.pas
trunk/Source/Core/InstantConsts.pas
trunk/Source/Core/InstantMetadata.pas
trunk/Source/Core/InstantPersistence.pas
trunk/Source/Core/InstantPresentation.pas
trunk/Source/Core/InstantUtils.pas
trunk/Source/Design/InstantModelExpert.pas
trunk/Source/Design/InstantModelImport.pas
trunk/Tests/TestIO.dproj
trunk/Tests/TestIO_D2009.mdr
trunk/Tests/TestIO_D2009.mdrt
trunk/Tests/TestIO_D2009.mdx
trunk/Tests/TestIO_D2009.mdxt
trunk/Tests/TestInstantAttributeMetadata.pas
trunk/Tests/TestInstantBlob.pas
trunk/Tests/TestInstantParts.pas
trunk/Tests/TestInstantReferences.pas
trunk/Tests/TestModel.pas
trunk/Tests/ubmock/src/fpcunit.pas
Added Paths:
-----------
trunk/Source/Core/InstantStandardValidators.pas
trunk/Source/Core/InstantValidation.pas
Property Changed:
----------------
trunk/Source/Brokers/ADO/
trunk/Source/Brokers/ADS/
trunk/Source/Core/D2009/
trunk/Tests/ubmock/src/
Property changes on: trunk/Source/Brokers/ADO
___________________________________________________________________
Modified: svn:ignore
- *.dcu
*.~pas
*.~dfm
+ *.dcu
*.~pas
*.~dfm
__history
Modified: trunk/Source/Brokers/ADO/InstantADOTools.pas
===================================================================
--- trunk/Source/Brokers/ADO/InstantADOTools.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Brokers/ADO/InstantADOTools.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -32,7 +32,7 @@
interface
uses
- ADODB, InstantADOJRO, SysUtils;
+ ADODB, InstantADOJRO;
type
TInstantADOSyncType = (stSend, stReceive, stSendReceive);
@@ -51,6 +51,9 @@
implementation
+uses
+ Windows, SysUtils;
+
const
SMSJetProvider = 'Microsoft.Jet.OLEDB.4.0';
Property changes on: trunk/Source/Brokers/ADS
___________________________________________________________________
Added: svn:ignore
+ __history
Modified: trunk/Source/Brokers/ADS/InstantADS.pas
===================================================================
--- trunk/Source/Brokers/ADS/InstantADS.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Brokers/ADS/InstantADS.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -178,13 +178,13 @@
function TInstantADSConnectionDef.GetDatabaseName: string;
const
- ValidChars = ['a'..'z', 'A'..'Z', '0'..'9', '_'];
+ LValidChars = ['a'..'z', 'A'..'Z', '0'..'9', '_'];
var
I: Integer;
begin
Result := Name;
for I := 1 to Length(Result) do
- if not (Result[I] in ValidChars) then
+ if not (Result[I] in LValidChars) then
Result[I] := '_';
end;
Modified: trunk/Source/Core/D2007/IOCore.dpk
===================================================================
--- trunk/Source/Core/D2007/IOCore.dpk 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/D2007/IOCore.dpk 2009-08-16 16:59:53 UTC (rev 830)
@@ -56,6 +56,8 @@
InstantDBBuilderFormUnit in '..\InstantDBBuilderFormUnit.pas' {InstantDBBuilderForm},
InstantTypes in '..\InstantTypes.pas',
InstantBrokers in '..\InstantBrokers.pas',
- InstantMetadata in '..\InstantMetadata.pas';
+ InstantMetadata in '..\InstantMetadata.pas',
+ InstantStandardValidators in '..\InstantStandardValidators.pas',
+ InstantValidation in '..\InstantValidation.pas';
end.
Modified: trunk/Source/Core/D2007/IOCore.dproj
===================================================================
--- trunk/Source/Core/D2007/IOCore.dproj 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/D2007/IOCore.dproj 2009-08-16 16:59:53 UTC (rev 830)
@@ -6,7 +6,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
- <DCC_DependencyCheckOutputName>..\..\..\..\..\..\..\Documents\RAD Studio\5.0\Bpl\IOCore_D11.bpl</DCC_DependencyCheckOutputName>
+ <DCC_DependencyCheckOutputName>C:\Users\nandod\Documents\RAD Studio\5.0\Bpl\IOCore_D11.bpl</DCC_DependencyCheckOutputName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Version>7.0</Version>
@@ -24,17 +24,16 @@
<Borland.Personality>Delphi.Personality</Borland.Personality>
<Borland.ProjectType>Package</Borland.ProjectType>
<BorlandProject>
-<BorlandProject><Delphi.Personality><Compiler><Compiler Name="UsePackages">False</Compiler><Compiler Name="Packages"></Compiler></Compiler><Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Package_Options><Package_Options Name="PackageDescription">InstantObjects Run-Time Package (Delphi 2007)</Package_Options><Package_Options Name="ImplicitBuild">False</Package_Options><Package_Options Name="DesigntimeOnly">False</Package_Options><Package_Options Name="RuntimeOnly">True</Package_Options><Package_Options Name="LibSuffix">_D11</Package_Options></Package_Options><VersionInfo><VersionInfo Name="IncludeVerInfo">True</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">2</VersionInfo><VersionInfo Name="MinorVer">1</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1040</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName">www.instantobjects.org</VersionInfoKeys><VersionInfoKeys Name="FileDescription">InstantObjects</VersionInfoKeys><VersionInfoKeys Name="FileVersion">2.1.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName">InstantObjects</VersionInfoKeys><VersionInfoKeys Name="ProductVersion">2.1.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">IOCore.dpk</Source></Source>
- </Delphi.Personality></BorlandProject></BorlandProject>
+<BorlandProject><Delphi.Personality><Compiler><Compiler Name="UsePackages">False</Compiler><Compiler Name="Packages"></Compiler></Compiler><Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Package_Options><Package_Options Name="PackageDescription">InstantObjects Run-Time Package (Delphi 2007)</Package_Options><Package_Options Name="ImplicitBuild">False</Package_Options><Package_Options Name="DesigntimeOnly">False</Package_Options><Package_Options Name="RuntimeOnly">True</Package_Options><Package_Options Name="LibSuffix">_D11</Package_Options></Package_Options><VersionInfo><VersionInfo Name="IncludeVerInfo">True</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">2</VersionInfo><VersionInfo Name="MinorVer">1</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1040</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName">www.instantobjects.org</VersionInfoKeys><VersionInfoKeys Name="FileDescription">InstantObjects</VersionInfoKeys><VersionInfoKeys Name="FileVersion">2.1.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName">InstantObjects</VersionInfoKeys><VersionInfoKeys Name="ProductVersion">2.1.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">IOCore.dpk</Source></Source></Delphi.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Delphi.Targets" />
<ItemGroup>
<DelphiCompile Include="IOCore.dpk">
<MainSource>MainSource</MainSource>
</DelphiCompile>
- <DCCReference Include="..\..\PackageGroups\D2007\rtl.dcp" />
- <DCCReference Include="..\..\PackageGroups\D2007\vcl.dcp" />
- <DCCReference Include="..\..\PackageGroups\D2007\vcldb.dcp" />
+ <DCCReference Include="..\..\..\Tests\rtl.dcp" />
+ <DCCReference Include="..\..\..\Tests\vcl.dcp" />
+ <DCCReference Include="..\..\..\Tests\vcldb.dcp" />
<DCCReference Include="..\InstantAccessors.pas" />
<DCCReference Include="..\InstantBrokers.pas" />
<DCCReference Include="..\InstantClasses.pas" />
@@ -64,8 +63,10 @@
<DCCReference Include="..\InstantPresentation.pas" />
<DCCReference Include="..\InstantPump.pas" />
<DCCReference Include="..\InstantRtti.pas" />
+ <DCCReference Include="..\InstantStandardValidators.pas" />
<DCCReference Include="..\InstantTextFiler.pas" />
<DCCReference Include="..\InstantTypes.pas" />
<DCCReference Include="..\InstantUtils.pas" />
+ <DCCReference Include="..\InstantValidation.pas" />
</ItemGroup>
</Project>
\ No newline at end of file
Property changes on: trunk/Source/Core/D2009
___________________________________________________________________
Modified: svn:ignore
- *.dcu
*.local
*.identcache
+ *.dcu
*.local
*.identcache
__history
Modified: trunk/Source/Core/D2009/IOCore.dpk
===================================================================
--- trunk/Source/Core/D2009/IOCore.dpk 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/D2009/IOCore.dpk 2009-08-16 16:59:53 UTC (rev 830)
@@ -56,6 +56,8 @@
InstantDBBuilderFormUnit in '..\InstantDBBuilderFormUnit.pas' {InstantDBBuilderForm},
InstantTypes in '..\InstantTypes.pas',
InstantBrokers in '..\InstantBrokers.pas',
- InstantMetadata in '..\InstantMetadata.pas';
+ InstantMetadata in '..\InstantMetadata.pas',
+ InstantStandardValidators in '..\InstantStandardValidators.pas',
+ InstantValidation in '..\InstantValidation.pas';
end.
Modified: trunk/Source/Core/D2009/IOCore.dproj
===================================================================
--- trunk/Source/Core/D2009/IOCore.dproj 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/D2009/IOCore.dproj 2009-08-16 16:59:53 UTC (rev 830)
@@ -86,6 +86,8 @@
<DCCReference Include="..\InstantTypes.pas"/>
<DCCReference Include="..\InstantBrokers.pas"/>
<DCCReference Include="..\InstantMetadata.pas"/>
+ <DCCReference Include="..\InstantStandardValidators.pas"/>
+ <DCCReference Include="..\InstantValidation.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
Modified: trunk/Source/Core/D2009/IOCore.res
===================================================================
(Binary files differ)
Modified: trunk/Source/Core/InstantClasses.pas
===================================================================
--- trunk/Source/Core/InstantClasses.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantClasses.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -50,11 +50,7 @@
InstantBufferSize = 4096;
type
-{$IFDEF D12+}
- TChars = set of AnsiChar; // Avoid WideChar reduced to byte warning
-{$ELSE}
- TChars = set of Char;
-{$ENDIF}
+ TChars = set of AnsiChar;
{$IFDEF LINUX}
TDate = type TDateTime;
@@ -179,7 +175,6 @@
public
constructor Create(Stream: TStream; BufSize: Integer = InstantBufferSize);
procedure ReadBinary(ReadData: TStreamProc);
- function ReadCharSet: TChars;
function ReadObject(AObject: TPersistent = nil;
Arg: Pointer = nil): TPersistent; virtual;
procedure ReadProperties(AObject: TPersistent);
@@ -195,7 +190,6 @@
public
constructor Create(Stream: TStream; BufSize: Integer = InstantBufferSize);
procedure WriteBinary(WriteData: TStreamProc);
- procedure WriteCharSet(CharSet: TChars);
procedure WriteObject(AObject: TPersistent); virtual;
procedure WriteProperties(AObject: TPersistent);
{$IFNDEF UNICODE}
@@ -976,11 +970,6 @@
end;
end;
-function TInstantReader.ReadCharSet: TChars;
-begin
- Result := InstantStrToCharSet(ReadStr);
-end;
-
function TInstantReader.ReadObject(AObject: TPersistent;
Arg: Pointer): TPersistent;
@@ -1068,11 +1057,6 @@
inherited WriteBinary(WriteData);
end;
-procedure TInstantWriter.WriteCharSet(CharSet: TChars);
-begin
- WriteStr(InstantCharSetToStr(CharSet));
-end;
-
procedure TInstantWriter.WriteObject(AObject: TPersistent);
begin
WriteUTF8Str(AObject.ClassName);
Modified: trunk/Source/Core/InstantCode.pas
===================================================================
--- trunk/Source/Core/InstantCode.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantCode.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -871,12 +871,12 @@
function GetSubClass(Index: Integer): TInstantCodeClass;
function GetSubClassCount: Integer;
function GetSubClassList: TList;
- function GetUnitName: string;
+ function GetPascalUnitName: string;
procedure SetBaseClass(const Value: TInstantCodeClass);
procedure SetBaseClassName(const Value: string);
procedure SetPersistence(const Value: TInstantPersistence);
procedure SetStorageName(const Value: string);
- procedure SetUnitName(const Value: string);
+ procedure SetPascalUnitName(const Value: string);
procedure RemoveDivision(Division: TInstantCodeDivision);
procedure SetSubClass(Index: Integer; const Value: TInstantCodeClass);
protected
@@ -959,7 +959,7 @@
property BaseClassName: string read GetBaseClassName write SetBaseClassName;
property Persistence: TInstantPersistence read GetPersistence write SetPersistence;
property StorageName: string read GetStorageName write SetStorageName;
- property UnitName: string read GetUnitName write SetUnitName;
+ property PascalUnitName: string read GetPascalUnitName write SetPascalUnitName;
end;
TInstantCodeClassList = class(TList)
@@ -1258,7 +1258,7 @@
function GetProgramSection: TInstantCodeProgramSection;
function GetTypeCount: Integer;
function GetTypes(Index: Integer): TInstantCodeType;
- function GetUnitName: string;
+ function GetPascalUnitName: string;
procedure SetModuleTypeName(const Value: string);
protected
function GetModule: TInstantCodeModule; override;
@@ -1291,7 +1291,7 @@
property TypeCount: Integer read GetTypeCount;
property Types[Index: Integer]: TInstantCodeType read GetTypes;
published
- property UnitName: string read GetUnitName;
+ property PascalUnitName: string read GetPascalUnitName;
end;
TInstantCodeProject = class(TInstantCodeObject)
@@ -5251,9 +5251,9 @@
Result := FSubClassList;
end;
-function TInstantCodeClass.GetUnitName: string;
+function TInstantCodeClass.GetPascalUnitName: string;
begin
- Result := Module.UnitName;
+ Result := Module.PascalUnitName;
end;
class function TInstantCodeClass.Identifier: string;
@@ -5439,7 +5439,7 @@
SubClassList[Index] := Value;
end;
-procedure TInstantCodeClass.SetUnitName(const Value: string);
+procedure TInstantCodeClass.SetPascalUnitName(const Value: string);
var
NewModule: TInstantCodeModule;
begin
@@ -6986,7 +6986,7 @@
Result := TInstantCodeType(FTypes[Index]);
end;
-function TInstantCodeModule.GetUnitName: string;
+function TInstantCodeModule.GetPascalUnitName: string;
begin
Result := ChangeFileExt(ExtractFileName(Name), '');
end;
@@ -7006,7 +7006,7 @@
procedure TInstantCodeModule.InternalWrite(Writer: TInstantCodeWriter);
begin
- Writer.WriteLnFmt('%s %s;', [ModuleTypeName, UnitName]);
+ Writer.WriteLnFmt('%s %s;', [ModuleTypeName, PascalUnitName]);
Writer.WriteLn;
InterfaceSection.Write(Writer);
ImplementationSection.Write(Writer);
Modified: trunk/Source/Core/InstantConsts.pas
===================================================================
--- trunk/Source/Core/InstantConsts.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantConsts.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -132,7 +132,7 @@
SInitializationFailed = 'Initialization failed for object of class %s: "%s"';
SInvalidArgument = 'Invalid argument for object of class %s. Expected argument of class %s';
SInvalidAttributeValue = 'Invalid value "%s" for attribute %s(''%s'')';
- SInvalidChar = 'Invalid character ''%s'' (#%d) for attribute %s(''%s'')';
+ SInvalidChar = 'Invalid character ''%s'' (#%d). Valid characters are ''%s''';
SInvalidClass = 'Invalid class %s. Expected %s';
SInvalidConnector = 'Invalid connector for object %s(''%s'') in attribute %s(''%s'')';
SInvalidDataType = 'Invalid data type';
Modified: trunk/Source/Core/InstantMetadata.pas
===================================================================
--- trunk/Source/Core/InstantMetadata.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantMetadata.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -40,7 +40,8 @@
interface
-uses Classes, Contnrs, Db, InstantClasses, InstantTypes, InstantConsts;
+uses
+ Classes, Contnrs, Db, InstantClasses, InstantTypes, InstantConsts;
type
TInstantAttributeMap = class;
@@ -430,6 +431,33 @@
write SetItems; default;
end;
+ TInstantValidator = class
+ private
+ FMetadata: TInstantAttributeMetadata;
+ public
+ // A reference to the metadata. Should be set by CreateValidator on
+ // the created instance.
+ property Metadata: TInstantAttributeMetadata read FMetadata write FMetadata;
+ // Creates and returns a validator instance suitable for the specified
+ // metadata, or nil if the class doesn't apply to the metadata.
+ { TODO : extend this to support class-level validation? }
+ class function CreateValidator(const AMetadata: TInstantAttributeMetadata):
+ TInstantValidator; virtual;
+ // Should check the value against the validation settings
+ // that are specific for each derived class, and return
+ // True if the value is valid for the attribute.
+ // Otherwise, this method should return False and set an appropriate
+ // error message in AValidationErrorText.
+ // When this method is called, AAttribute is guaranteed to be assigned.
+ function IsValid(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string; out AValidationErrorText: string): Boolean; virtual; abstract;
+ // Raises an exception if the proposed value is not valid for
+ // the attribute.
+ procedure Validate(const AAttribute: TInstantAbstractAttribute; const AValue: string);
+ end;
+
+ TInstantValidatorClass = class of TInstantValidator;
+
TInstantAttributeMetadata = class(TInstantMetadata)
private
FAttributeType: TInstantAttributeType;
@@ -442,9 +470,10 @@
FObjectClassName: string;
FSize: Integer;
FStorageName: string;
- FValidChars: TChars;
+ FValidCharsString: string;
FStorageKind: TInstantStorageKind;
FExternalStorageName: string;
+ FValidator: TInstantValidator;
function GetAttributeClass: TInstantAbstractAttributeClass;
function GetAttributeClassName: string;
function GetAttributeTypeName: string;
@@ -458,7 +487,6 @@
function GetObjectClass: TInstantAbstractObjectClass;
function GetObjectClassMetadata: TInstantClassMetadata;
function GetTableName: string;
- function GetValidChars: TChars;
function GetValidCharsString: string;
procedure SetAttributeClass(const AClass: TInstantAbstractAttributeClass);
procedure SetAttributeClassName(const Value: string);
@@ -466,15 +494,22 @@
procedure SetCollection(Value: TInstantAttributeMetadatas);
procedure SetFieldName(const Value: string);
procedure SetIsDefault(const Value: Boolean);
- procedure SetValidCharsString(const Value: string);
+ procedure SetValidCharsString(const AValue: string);
+ function GetValidator: TInstantValidator;
+ // Should be called whenever a validation-related property,
+ // such as ValidCharsString, changes.
+ procedure FreeValidator;
+ protected
+ property Validator: TInstantValidator read GetValidator;
public
- function CreateAttribute(AObject: TInstantAbstractObject):
- TInstantAbstractAttribute;
+ function CreateAttribute(
+ AObject: TInstantAbstractObject): TInstantAbstractAttribute;
procedure Assign(Source: TPersistent); override;
procedure CheckAttributeClass(AClass: TInstantAbstractAttributeClass);
procedure CheckCategory(ACategory: TInstantAttributeCategory);
procedure CheckIsIndexed;
function IsAttributeClass(AClass: TInstantAbstractAttributeClass): Boolean;
+ destructor Destroy; override;
property AttributeClass: TInstantAbstractAttributeClass
read GetAttributeClass write SetAttributeClass;
property AttributeClassName: string read GetAttributeClassName
@@ -490,7 +525,8 @@
property FieldName: string read GetFieldName write SetFieldName;
property HasValidChars: Boolean read GetHasValidChars;
property TableName: string read GetTableName;
- property ValidChars: TChars read GetValidChars write FValidChars;
+ procedure ValidateAttribute(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string);
published
property AttributeType: TInstantAttributeType read FAttributeType
write FAttributeType default atUnknown;
@@ -535,7 +571,9 @@
implementation
-uses SysUtils, TypInfo, InstantPersistence, InstantUtils;
+uses
+ SysUtils, TypInfo, InstantPersistence, InstantUtils, InstantValidation,
+ InstantStandardValidators {registers the standard validators - do not remove};
const
AttributeClasses: array[TInstantAttributeType] of TInstantAttributeClass = (
@@ -1655,7 +1693,7 @@
Self.FStorageName := FStorageName;
Self.FStorageKind := FStorageKind;
Self.FExternalStorageName := FExternalStorageName;
- Self.FValidChars := FValidChars;
+ Self.FValidCharsString := FValidCharsString;
end;
end;
@@ -1700,6 +1738,17 @@
Result := AClass.Create(TInstantObject(AObject), Self);
end;
+destructor TInstantAttributeMetadata.Destroy;
+begin
+ FreeAndNil(FValidator);
+ inherited;
+end;
+
+procedure TInstantAttributeMetadata.FreeValidator;
+begin
+ FreeAndNil(FValidator);
+end;
+
function TInstantAttributeMetadata.GetAttributeClass:
TInstantAbstractAttributeClass;
begin
@@ -1766,7 +1815,7 @@
function TInstantAttributeMetadata.GetHasValidChars: Boolean;
begin
- Result := FValidChars <> [];
+ Result := FValidCharsString <> '';
end;
function TInstantAttributeMetadata.GetIsDefault: Boolean;
@@ -1798,14 +1847,16 @@
Result := '';
end;
-function TInstantAttributeMetadata.GetValidChars: TChars;
+function TInstantAttributeMetadata.GetValidator: TInstantValidator;
begin
- Result := FValidChars;
+ if not Assigned(FValidator) then
+ FValidator := InstantValidatorFactory.CreateValidator(Self);
+ Result := FValidator;
end;
function TInstantAttributeMetadata.GetValidCharsString: string;
begin
- Result := InstantCharSetToStr(FValidChars);
+ Result := FValidCharsString;
end;
function TInstantAttributeMetadata.IsAttributeClass(AClass:
@@ -1883,11 +1934,21 @@
end;
end;
-procedure TInstantAttributeMetadata.SetValidCharsString(const Value: string);
+procedure TInstantAttributeMetadata.SetValidCharsString(const AValue: string);
begin
- FValidChars := InstantStrToCharSet(Value);
+ if AValue <> FValidCharsString then
+ begin
+ FreeValidator;
+ FValidCharsString := AValue;
+ end;
end;
+procedure TInstantAttributeMetadata.ValidateAttribute(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string);
+begin
+ Validator.Validate(AAttribute, AValue);
+end;
+
constructor TInstantAttributeMetadatas.Create(AOwner: TInstantClassMetadata);
begin
inherited Create(AOwner, TInstantAttributeMetadata);
@@ -1942,5 +2003,23 @@
inherited Items[Index] := Value;
end;
+{ TInstantValidator }
+
+class function TInstantValidator.CreateValidator(
+ const AMetadata: TInstantAttributeMetadata): TInstantValidator;
+begin
+ Result := Create;
+ Result.Metadata := AMetadata;
+end;
+
+procedure TInstantValidator.Validate(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string);
+var
+ LValidationErrorText: string;
+begin
+ if not IsValid(AAttribute, AValue, LValidationErrorText) then
+ raise EInstantValidationError.Create(LValidationErrorText);
+end;
+
end.
Modified: trunk/Source/Core/InstantPersistence.pas
===================================================================
--- trunk/Source/Core/InstantPersistence.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantPersistence.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -196,8 +196,8 @@
procedure SetAsVariant(AValue: Variant); virtual;
procedure SetIsChanged(Value: Boolean);
procedure SetOwner(AOwner: TInstantObject); virtual;
- procedure StringValidationError(InvalidChar: Char);
procedure WriteName(Writer: TInstantWriter);
+ procedure Validate(const AValue: string); virtual;
public
constructor Create(AOwner: TInstantAbstractObject = nil; AMetadata:
TInstantCollectionItem = nil); override;
@@ -1613,23 +1613,6 @@
ObjectNotifiers: TInstantObjectNotifiers;
DefaultConnector: TInstantConnector;
-{ Local Routines }
-
-function ValidateChars(Buffer: PChar; BufferLength: Integer;
- ValidChars: TChars; var InvalidChar: Char): Boolean;
-var
- I: Integer;
-begin
- Result := True;
- for I := 0 to Pred(BufferLength div SizeOf(Char)) do
- if (ValidChars <> []) and not (InstantCharInSet(Buffer[I], ValidChars + [#8, #10, #13])) then
- begin
- Result := False;
- InvalidChar := Buffer[I];
- Break;
- end;
-end;
-
{ Global routines }
procedure AssignInstantStreamFormat(Strings: TStrings);
@@ -2537,15 +2520,15 @@
AsVariant := AValue;
end;
-procedure TInstantAttribute.StringValidationError(InvalidChar: Char);
+procedure TInstantAttribute.Unchanged;
begin
- raise EInstantValidationError.CreateFmt(SInvalidChar,
- [InvalidChar, Ord(InvalidChar), ClassName, Name]);
+ IsChanged := False;
end;
-procedure TInstantAttribute.Unchanged;
+procedure TInstantAttribute.Validate(const AValue: string);
begin
- IsChanged := False;
+ if Assigned(Metadata) then
+ Metadata.ValidateAttribute(Self, AValue);
end;
procedure TInstantAttribute.WriteName(Writer: TInstantWriter);
@@ -3257,12 +3240,8 @@
end;
procedure TInstantString.SetValue(const AValue: string);
-var
- InvalidChar: Char;
begin
- if Assigned(Metadata) and not ValidateChars(PChar(AValue), Length(AValue),
- Metadata.ValidChars, InvalidChar) then
- StringValidationError(InvalidChar);
+ Validate(AValue);
if AValue <> FValue then
begin
FValue:= AValue;
@@ -3590,16 +3569,18 @@
function TInstantBlob.Write(const Buffer; Position, Count: Integer): Integer;
var
- C: Char;
+ LValue: AnsiString;
+ LBufferPointer: {$IFDEF D12+}PByte{$ELSE}PChar{$ENDIF};
function CompareBuffers: Boolean;
var
I: Integer;
+ B: {$IFDEF D12+}Byte{$ELSE}Char{$ENDIF};
begin
Stream.Position := Position;
- for I := 0 to Pred(Count) do
+ for I := Position to Pred(Position + Count) do
begin
- Result := (Stream.Read(C, 1) = 1) and (C = PChar(@Buffer)[I]);
+ Result := (Stream.Read(B, 1) = 1) and (B = {$IFDEF D12+}PByte{$ELSE}PChar{$ENDIF}(@Buffer)[I]);
if not Result then
Exit;
end;
@@ -3607,13 +3588,17 @@
end;
begin
- if not ValidateChars(PChar(@Buffer), Count, Metadata.ValidChars, C) then
- StringValidationError(C);
+ SetLength(LValue, Count);
+ LBufferPointer := @Buffer;
+ Inc(LBufferPointer, Position);
+ StrLCopy(PAnsiChar(LValue), PAnsiChar(LBufferPointer), Count);
+ Validate(string(LValue));
if not CompareBuffers then
begin
Stream.Position := Position;
Result := Stream.Write(Buffer, Count);
- end else
+ end
+ else
Result := 0;
end;
Modified: trunk/Source/Core/InstantPresentation.pas
===================================================================
--- trunk/Source/Core/InstantPresentation.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantPresentation.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -3654,6 +3654,32 @@
Field: TField);
var
Metadata: TInstantAttributeMetadata;
+
+ function InstantStrToCharSet(const Str: AnsiString): TFieldChars;
+ const
+ Dots: array[0..1] of Char = '..';
+ var
+ I, J: Integer;
+ begin
+ Result := [];
+ I := 1;
+ while I <= Length(Str) do
+ begin
+ if CompareMem(@Str[I], @Dots, Length(Dots)) and
+ (I > 1) and (Length(Str) > I + 1) then
+ begin
+ for J := Ord(Str[I - 1]) to Ord(Str[I + 2]) do
+ Result := Result + [Chr(J)];
+ Inc(I, Length(Dots));
+ end
+ else
+ begin
+ Include(Result, Str[I]);
+ Inc(I);
+ end;
+ end;
+ end;
+
begin
if AObject is TInstantObject then
begin
@@ -3663,8 +3689,8 @@
begin
if Field.EditMask <> Metadata.EditMask then
Field.EditMask := Metadata.EditMask;
- if Metadata.ValidChars <> [] then
- Field.ValidChars := Metadata.ValidChars;
+ if Metadata.ValidCharsString <> '' then
+ Field.ValidChars := InstantStrToCharSet(AnsiString(Metadata.ValidCharsString));
end;
end;
end;
@@ -3712,7 +3738,7 @@
FillChar(Buffer^, Field.DataSize, 0);
if not Empty then
begin
- S := Value;
+ S := AnsiString(Value);
Len := Length(S);
if Len >= Field.DataSize then
Len := Pred(Field.DataSize);
Added: trunk/Source/Core/InstantStandardValidators.pas
===================================================================
--- trunk/Source/Core/InstantStandardValidators.pas (rev 0)
+++ trunk/Source/Core/InstantStandardValidators.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -0,0 +1,282 @@
+(*
+ * InstantObjects
+ * Validation framework - standard validators.
+ *)
+
+(* ***** 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: Seleqt InstantObjects
+ *
+ * The Initial Developer of the Original Code is: Seleqt
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2001-2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Nando Dessena
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+unit InstantStandardValidators;
+
+{$IFDEF LINUX}
+{$I '../InstantDefines.inc'}
+{$ELSE}
+{$I '..\InstantDefines.inc'}
+{$ENDIF}
+
+interface
+
+uses
+ Contnrs, InstantClasses, InstantMetadata, InstantValidation;
+
+type
+ // Base class for classes that handle the pieces of a ValidCharsString string.
+ TInstantCharSetPieceValidator = class
+ protected
+ function GetValidCharsAsString: string; virtual;
+ public
+ function IsValidChar(const AChar: Char): Boolean; virtual; abstract;
+ property ValidCharsAsString: string read GetValidCharsAsString;
+ end;
+
+ // Validates a character against a set of distinct characters stored in a string.
+ TInstantCharsPieceValidator = class(TInstantCharSetPieceValidator)
+ private
+ FValidChars: string;
+ protected
+ function GetValidCharsAsString: string; override;
+ public
+ procedure AfterConstruction; override;
+ procedure AddChar(const AChar: Char);
+ procedure RemoveLastChar;
+ function IsValidChar(const AChar: Char): Boolean; override;
+ end;
+
+ // Validates a character against a range of characters.
+ TInstantCharRangePieceValidator = class(TInstantCharSetPieceValidator)
+ private
+ FValidFrom: Char;
+ FValidTo: Char;
+ protected
+ function GetValidCharsAsString: string; override;
+ public
+ procedure SetValidChars(const AValidFrom, AValidTo: Char);
+ function IsValidChar(const AChar: Char): Boolean; override;
+ end;
+
+ // Splits a ValidCharsString string into pieces that hands each to a
+ // different internal instance of TInstantCharSetPieceValidator.
+ TInstantCharSetValidator = class(TInstantValidator)
+ private
+ FPieces: TObjectList;
+ procedure CreatePieceValidators(const AValidChars: string);
+ function IsValidChar(const AChar: Char;
+ out AValidationErrorText: string): Boolean;
+ public
+ procedure AfterConstruction; override;
+ destructor Destroy; override;
+ class function CreateValidator(
+ const AMetadata: TInstantAttributeMetadata): TInstantValidator; override;
+ function IsValid(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string; out AValidationErrorText: string): Boolean;
+ override;
+ end;
+
+implementation
+
+uses
+ SysUtils, InstantConsts;
+
+{ TInstantCharSetValidator }
+
+procedure TInstantCharSetValidator.AfterConstruction;
+begin
+ inherited;
+ FPieces := TObjectList.Create;
+end;
+
+procedure TInstantCharSetValidator.CreatePieceValidators(
+ const AValidChars: string);
+var
+ I: Integer;
+ LCharsValidator: TInstantCharsPieceValidator;
+ LCharRangeValidator: TInstantCharRangePieceValidator;
+ LChar: Char;
+begin
+ LCharsValidator := TInstantCharsPieceValidator.Create;
+ FPieces.Add(LCharsValidator);
+ I := 1;
+ while I <= Length(AValidChars) do
+ begin
+ LChar := AValidChars[I];
+ // a..b means a range from a to b.
+ if (LChar = '.') and (I > 1) and (I < Length(AValidChars) - 1) and (AValidChars[Succ(I)] = '.') then
+ begin
+ LCharRangeValidator := TInstantCharRangePieceValidator.Create;
+ FPieces.Add(LCharRangeValidator);
+ LCharRangeValidator.SetValidChars(AValidChars[Pred(I)],
+ AValidChars[I + 2]);
+ // no need for the chars validator to take care of the first char in
+ // my range.
+ LCharsValidator.RemoveLastChar;
+ // skip the second dot and the range end char.
+ Inc(I, 2);
+ end
+ // everything else is a simple match.
+ else
+ LCharsValidator.AddChar(LChar);
+ Inc(I);
+ end;
+end;
+
+class function TInstantCharSetValidator.CreateValidator(
+ const AMetadata: TInstantAttributeMetadata): TInstantValidator;
+begin
+ if Assigned(AMetadata) and (AMetadata.ValidCharsString <> '') then
+ begin
+ Result := Create;
+ try
+ Result.Metadata := AMetadata;
+ TInstantCharSetValidator(Result).CreatePieceValidators(AMetadata.ValidCharsString);
+ except
+ FreeAndNil(Result);
+ raise;
+ end;
+ end
+ else
+ Result := nil;
+end;
+
+destructor TInstantCharSetValidator.Destroy;
+begin
+ FreeAndNil(FPieces);
+ inherited;
+end;
+
+function TInstantCharSetValidator.IsValid(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string;
+ out AValidationErrorText: string): Boolean;
+var
+ I: Integer;
+begin
+ Result := True;
+ for I := 1 to Length(AValue) do
+ begin
+ if not IsValidChar(AValue[I], AValidationErrorText) then
+ begin
+ Result := False;
+ Break;
+ end;
+ end;
+ if not Result then
+ AValidationErrorText := Format(SInvalidAttributeValue, [AValue,
+ AAttribute.ClassName, Metadata.Name]) + sLineBreak +
+ AValidationErrorText;
+end;
+
+function TInstantCharSetValidator.IsValidChar(
+ const AChar: Char; out AValidationErrorText: string): Boolean;
+var
+ I: Integer;
+begin
+ Result := False;
+ AValidationErrorText := '';
+ for I := 0 to FPieces.Count - 1 do
+ begin
+ if TInstantCharSetPieceValidator(FPieces[I]).IsValidChar(AChar) then
+ begin
+ Result := True;
+ Break;
+ end;
+ end;
+ if not Result then
+ AValidationErrorText := Format(SInvalidChar, [AChar, Ord(AChar), Metadata.ValidCharsString]);
+end;
+
+{ TInstantCharSetPieceValidator }
+
+function TInstantCharSetPieceValidator.GetValidCharsAsString: string;
+begin
+ Result := '';
+end;
+
+{ TInstantCharsPieceValidator }
+
+procedure TInstantCharsPieceValidator.AddChar(const AChar: Char);
+begin
+ if Pos(AChar, FValidChars) = 0 then
+ FValidChars := FValidChars + AChar;
+end;
+
+procedure TInstantCharsPieceValidator.AfterConstruction;
+begin
+ inherited;
+ // This is for backward compatibility, as IO has always allowed these
+ // characters in a string or memo when ValidCharsString is not empty.
+ // I don't think this is strictly correct, especially for string fields.
+ FValidChars := #8#10#13;
+end;
+
+function TInstantCharsPieceValidator.GetValidCharsAsString: string;
+begin
+ Result := FValidChars;
+end;
+
+function TInstantCharsPieceValidator.IsValidChar(const AChar: Char): Boolean;
+begin
+ Result := Pos(AChar, FValidChars) > 0;
+end;
+
+procedure TInstantCharsPieceValidator.RemoveLastChar;
+begin
+ if FValidChars <> '' then
+ Delete(FValidChars, Length(FValidChars) , 1);
+end;
+
+{ TInstantCharRangePieceValidator }
+
+function TInstantCharRangePieceValidator.GetValidCharsAsString: string;
+begin
+ Result := FValidFrom + '..' + FValidTo;
+end;
+
+function TInstantCharRangePieceValidator.IsValidChar(const AChar: Char): Boolean;
+begin
+ Result := (AChar >= FValidFrom) and (AChar <= FValidTo);
+end;
+
+procedure TInstantCharRangePieceValidator.SetValidChars(const AValidFrom,
+ AValidTo: Char);
+begin
+ if AValidFrom > AValidTo then
+ begin
+ FValidFrom := AValidTo;
+ FValidTo := AValidFrom;
+ end
+ else
+ begin
+ FValidFrom := AValidFrom;
+ FValidTo := AValidTo;
+ end;
+end;
+
+initialization
+ InstantValidatorFactory.AddValidatorClass(TInstantCharSetValidator);
+
+finalization
+ InstantValidatorFactory.RemoveValidatorClass(TInstantCharSetValidator);
+
+end.
+
Property changes on: trunk/Source/Core/InstantStandardValidators.pas
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Modified: trunk/Source/Core/InstantUtils.pas
===================================================================
--- trunk/Source/Core/InstantUtils.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Core/InstantUtils.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -50,7 +50,6 @@
Major, Minor, Release, Build: Word;
end;
-function InstantCharSetToStr(C: TChars): string;
function InstantCompareObjects(Obj1, Obj2: TObject; PropName: string;
Options: TInstantCompareOptions): Integer; overload;
function InstantCompareObjects(Obj1, Obj2: TObject; PropNames: TStrings;
@@ -82,7 +81,6 @@
function InstantSameText(const S1, S2: string; IgnoreCase: Boolean): Boolean;
function InstantStrToDate(const Str: string): TDateTime;
function InstantStrToDateTime(const Str: string): TDateTime;
-function InstantStrToCharSet(const Str: AnsiString): TChars;
procedure InstantStrToList(const Str: string; List: TStrings;
Delimiters: TChars);
function InstantStrToTime(const Str: string): TDateTime;
@@ -109,37 +107,6 @@
{$ENDIF}
{$IFDEF D6+}Variants,{$ENDIF} InstantConsts, InstantRtti;
-function InstantCharSetToStr(C: TChars): string;
-var
- I, J, L: Integer;
- S: string;
-begin
- Result := '';
- for I := 0 to 255 do
- if InstantCharInSet(Chr(I), C) then
- S := S + Chr(I);
- I := 1;
- L := Length(S);
- Result := '';
- while I <= L do
- begin
- J := 1;
- Result := Result + S[I];
- while ((I + J) <= L) and (Ord(S[I]) + J = Ord(S[I + J])) do
- Inc(J);
- if J > 3 then
- Result := Result + '..' + S[I + J - 1]
- else
- while J > 1 do
- begin
- Inc(I);
- Dec(J);
- Result := Result + S[I];
- end;
- I := I + J;
- end;
-end;
-
function InstantCompareObjects(Obj1, Obj2: TObject; PropName: string;
Options: TInstantCompareOptions): Integer;
var
@@ -541,31 +508,6 @@
end;
end;
-function InstantStrToCharSet(const Str: AnsiString): TChars;
-const
- Dots: array[0..1] of Char = '..';
-var
- I, J: Integer;
-begin
- Result := [];
- I := 1;
- while I <= Length(Str) do
- begin
- if CompareMem(@Str[I], @Dots, Length(Dots)) and
- (I > 1) and (Length(Str) > I + 1) then
- begin
- for J := Ord(Str[I - 1]) to Ord(Str[I + 2]) do
- Result := Result + [Chr(J)];
- Inc(I, Length(Dots));
- end
- else
- begin
- Include(Result, Str[I]);
- Inc(I);
- end;
- end;
-end;
-
procedure InstantStrToList(const Str: string; List: TStrings;
Delimiters: TChars);
Added: trunk/Source/Core/InstantValidation.pas
===================================================================
--- trunk/Source/Core/InstantValidation.pas (rev 0)
+++ trunk/Source/Core/InstantValidation.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -0,0 +1,230 @@
+(*
+ * InstantObjects
+ * Validation framework
+ *)
+
+(* ***** 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: Seleqt InstantObjects
+ *
+ * The Initial Developer of the Original Code is: Seleqt
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2001-2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Nando Dessena
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+unit InstantValidation;
+
+{$IFDEF LINUX}
+{$I '../InstantDefines.inc'}
+{$ELSE}
+{$I '..\InstantDefines.inc'}
+{$ENDIF}
+
+interface
+
+uses
+ Contnrs, InstantClasses, InstantMetadata, InstantPersistence;
+
+type
+ TInstantValidatorListValidationMode = (vmAll, vmAny);
+
+ // A validator that is a list of validators (composite).
+ // Shouldn't be registered as it's used directly by the
+ // factory as a wrapper for multiple validators and also as a null object,
+ // for when no validators apply. It is also a base class for other
+ // validators.
+ TInstantValidatorList = class(TInstantValidator)
+ private
+ FValidators: TObjectList;
+ FConcatMode: TInstantValidatorListValidationMode;
+ function AllValid(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string; out AValidationErrorText: string): Boolean;
+ function AnyValid(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string; out AValidationErrorText: string): Boolean;
+ public
+ function IsValid(const AAttribute: TInstantAbstractAttribute;
+ const AValue: string; out AValidationErrorText: string): Boolean;
+ override;
+ procedure AfterConstruction; override;
+ destructor Destroy; override;
+ // Adds a validator to the inner list.
+ procedure Add(const AValidator: TInstantValidator);
+ // Decides whether validators in lists should all pass for a value to be
+ // accepted (vmAll) or if any one of them suffices (vmAny).
+ property ConcatMode: TInstantValidatorListValidationMode
+ read FConcatMode write FConcatMode default vmAll;
+ end;
+
+ // Creates validators based on metadata contents.
+ TInstantValidatorFactory = class
+ private
+ FClasses: TClassList;
+ public
+ procedure AfterConstruction; override;
+ destructor Destroy; override;
+
+ procedure AddValidatorClass(const AValidatorClass: TInstantValidatorClass);
+ procedure RemoveValidatorClass(const AValidatorClass: TInstantValidatorClass);
+
+ { TODO : Extend this for class-level validation? }
+ function CreateValidator(const AMetadata: TInstantAttributeMetadata): TInstantValidator;
+ end;
+
+function InstantValidatorFactory: TInstantValidatorFactory;
+
+implementation
+
+uses
+ SysUtils;
+
+var
+ _InstantValidatorFactory: TInstantValidatorFactory;
+
+function InstantValidatorFactory: TInstantValidatorFactory;
+begin
+ if not Assigned(_InstantValidatorFactory) then
+ _InstantValidatorFactory := TInstantValidatorFactory.Create;
+ Result := _InstantValidatorFactory;
+end;
+
+{ TInstantValidatorFactory }
+
+procedure TInstantValidatorFactory.AddValidatorClass(
+ const AValidatorClass: TInstantValidatorClass);
+begin
+ FClasses.Add(AValidatorClass);
+end;
+
+procedure TInstantValidatorFactory.AfterConstruction;
+begin
+ inherited;
+ FClasses := TClassList.Create;
+end;
+
+function TInstantValidatorFactory.CreateValidator(
+ const AMetadata: TInstantAttributeMetadata): TInstantValidator;
+var
+ I: Integer;
+begin
+ Result := TInstantValidatorList.Create;
+ try
+ for I := 0 to FClasses.Count - 1 do
+ TInstantValidatorList(Result).Add(
+ TInstantValidatorClass(FClasses[I]).CreateValidator(AMetadata));
+ except
+ FreeAndNil(Result);
+ raise;
+ end;
+end;
+
+destructor TInstantValidatorFactory.Destroy;
+begin
+ FreeAndNil(FClasses);
+ inherited;
+end;
+
+procedure TInstantValidatorFactory.RemoveValidatorClass(
+ const AValidatorClass: TInstantValidatorClass);
+begin
+ FClasses.Remove(AValidatorClass);
+end;
+
+{ TInstantValidatorList }
+
+procedure TInstantValidatorList.Add(const AValidator: TInstantValidator);
+begin
+ // It is valid for this method to receive nil and don't do anything.
+ if Assigned(AValidator) then
+ FValidators.Add(AValidator);
+end;
+
+procedure TInstantValidatorList.AfterConstruction;
+begin
+ inherited;
+ FValidators := TObjectList.Create;
+ FConcatMode := vmAll;
+end;
+
+destructor TInstantValidatorList.Destroy;
+begin
+ FreeAndNil(FValidators);
+ inherited;
+end;
+
+function TInstantValidatorList.IsValid(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string;
+ out AValidationErrorText: string): Boolean;
+begin
+ if FConcatMode = vmAll then
+ Result := AllValid(AAttribute, AValue, AValidationErrorText)
+ else
+ Result := AnyValid(AAttribute, AValue, AValidationErrorText);
+end;
+
+function TInstantValidatorList.AllValid(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string;
+ out AValidationErrorText: string): Boolean;
+var
+ I: Integer;
+begin
+ Result := True;
+ AValidationErrorText := '';
+ for I := 0 to FValidators.Count - 1 do
+ begin
+ if not TInstantValidator(FValidators[I]).IsValid(AAttribute, AValue, AValidationErrorText) then
+ begin
+ Result := False;
+ Break;
+ end;
+ end;
+end;
+
+function TInstantValidatorList.AnyValid(
+ const AAttribute: TInstantAbstractAttribute; const AValue: string;
+ out AValidationErrorText: string): Boolean;
+var
+ I: Integer;
+ LErrorText: string;
+begin
+ Result := False;
+ AValidationErrorText := '';
+ for I := 0 to FValidators.Count - 1 do
+ begin
+ if TInstantValidator(FValidators[I]).IsValid(AAttribute, AValue, LErrorText) then
+ begin
+ Result := True;
+ Break;
+ end
+ else
+ begin
+ if AValidationErrorText = '' then
+ AValidationErrorText := LErrorText
+ else
+ AValidationErrorText := AValidationErrorText + sLineBreak + LErrorText;
+ end;
+ end;
+end;
+
+initialization
+
+finalization
+ FreeAndNil(_InstantValidatorFactory);
+
+end.
+
Property changes on: trunk/Source/Core/InstantValidation.pas
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Modified: trunk/Source/Design/InstantModelExpert.pas
===================================================================
--- trunk/Source/Design/InstantModelExpert.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Design/InstantModelExpert.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -504,7 +504,7 @@
Editor: IOTASourceEditor;
OldLen: Integer;
begin
- Module := FIDEInterface.FindModule(AClass.Module.UnitName);
+ Module := FIDEInterface.FindModule(AClass.Module.PascalUnitName);
if not Assigned(Module) then
Exit;
Editor := FIDEInterface.SourceEditor(Module);
Modified: trunk/Source/Design/InstantModelImport.pas
===================================================================
--- trunk/Source/Design/InstantModelImport.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Source/Design/InstantModelImport.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -114,7 +114,7 @@
for I := 0 to FModel.ModuleCount - 1 do
begin
Module := FModel.Modules[I];
- ImportModuleCombo.Items.AddObject(Module.UnitName, Module)
+ ImportModuleCombo.Items.AddObject(Module.PascalUnitName, Module)
end;
end;
Modified: trunk/Tests/TestIO.dproj
===================================================================
--- trunk/Tests/TestIO.dproj 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Tests/TestIO.dproj 2009-08-16 16:59:53 UTC (rev 830)
@@ -37,7 +37,8 @@
<Borland.Personality>Delphi.Personality</Borland.Personality>
<Borland.ProjectType>VCLApplication</Borland.ProjectType>
<BorlandProject>
-<BorlandProject><Delphi.Personality><Compiler><Compiler Name="UsePackages">False</Compiler><Compiler Name="Packages">vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;adortl;vclactnband;vclshlctrls;CS30Logging70;Rz30Ctls70;Rz30DBCtls70;ip4000v7;Rave60VCL;Rave60CLX;madBasic_;madDisAsm_;CLXIB;ibxpress;VCLIB;IOCore;IOIBX</Compiler></Compiler><Parameters><Parameters Name="DebugSourceDirs">..\Source\Core</Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Language><Language Name="RootDir">C:\Program Files\Borland\Delphi7\Bin\</Language></Language><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">3081</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">TestIO.dpr</Source></Source></Delphi.Personality></BorlandProject></BorlandProject>
+<BorlandProject><Delphi.Personality><Compiler><Compiler Name="UsePackages">False</Compiler><Compiler Name="Packages">vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;adortl;vclactnband;vclshlctrls;CS30Logging70;Rz30Ctls70;Rz30DBCtls70;ip4000v7;Rave60VCL;Rave60CLX;madBasic_;madDisAsm_;CLXIB;ibxpress;VCLIB;IOCore;IOIBX</Compiler></Compiler><Parameters><Parameters Name="DebugSourceDirs">..\Source\Core</Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Language><Language Name="RootDir">C:\Program Files\Borland\Delphi7\Bin\</Language></Language><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">3081</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">TestIO.dpr</Source></Source></Delphi.Personality> <ModelSupport>False</ModelSupport>
+</BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Delphi.Targets" />
<ItemGroup>
Modified: trunk/Tests/TestIO_D2009.mdr
===================================================================
(Binary files differ)
Modified: trunk/Tests/TestIO_D2009.mdrt
===================================================================
(Binary files differ)
Modified: trunk/Tests/TestIO_D2009.mdx
===================================================================
--- trunk/Tests/TestIO_D2009.mdx 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Tests/TestIO_D2009.mdx 2009-08-16 16:59:53 UTC (rev 830)
@@ -230,7 +230,7 @@
<AttributeType>atCurrency</AttributeType>
<IsIndexed>FALSE</IsIndexed>
<IsRequired>FALSE</IsRequired>
- <ValidCharsString>,.09?</ValidCharsString>
+ <ValidCharsString>,.0..9€</ValidCharsString>
</TInstantAttributeMetadata>
<TInstantAttributeMetadata>
<Name>Employed</Name>
Modified: trunk/Tests/TestIO_D2009.mdxt
===================================================================
--- trunk/Tests/TestIO_D2009.mdxt 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Tests/TestIO_D2009.mdxt 2009-08-16 16:59:53 UTC (rev 830)
@@ -214,7 +214,7 @@
<AttributeType>atCurrency</AttributeType>
<IsIndexed>FALSE</IsIndexed>
<IsRequired>FALSE</IsRequired>
- <ValidCharsString>,.09?</ValidCharsString>
+ <ValidCharsString>,.0..9€</ValidCharsString>
</TInstantAttributeMetadata>
<TInstantAttributeMetadata>
<Name>Employed</Name>
Modified: trunk/Tests/TestInstantAttributeMetadata.pas
===================================================================
--- trunk/Tests/TestInstantAttributeMetadata.pas 2009-08-16 06:01:49 UTC (rev 829)
+++ trunk/Tests/TestInstantAttributeMetadata.pas 2009-08-16 16:59:53 UTC (rev 830)
@@ -41,6 +41,8 @@
// Extended test methods for class TTestCase
TTestCaseEx = class(TTestCase)
+ private
+ FTempAttr: TInstantAttribute;
public
class procedure AssertException(const AMessage: string;
AExceptionClass: ExceptClass;
@@ -85,6 +87,7 @@
private
FConn: TInstantMockConnector;
FInstantAttributeMetadata: TInstantAttributeMetadata;
+ procedure SetInvalidValueInTempAttr;
public
procedure SetUp; override;
procedure TearDown; override;
@@ -95,6 +98,7 @@
procedure TestCheckCategory;
procedure TestCheckIsIndexed;
procedure TestIsAttributeClass;
+ procedure TestAttributeValidation;
end;
// Test methods for class TInstantAttributeMetadatas
@@ -235,7 +239,7 @@
FInstantAttributeMetadata.StorageName := 'StorageName';
FInstantAttributeMetadata.StorageKind := skEmbedded;
FInstantAttributeMetadata.ExternalStorageName := 'ExternalStorageName';
- FInstantAttributeMetadata.ValidChars := ['a'..'z'];
+ FInstantAttributeMetadata.ValidCharsString := 'a..y0..9\x80 ';
end;
procedure TestTInstantAttributeMetadata.TearDown;
@@ -266,7 +270,7 @@
vSource.StorageName := 'StorageName';
vSource.StorageKind := skEmbedded;
vSource.ExternalStorageName := 'ExternalStorageName';
- vSource.ValidChars := ['a'..'z'];
+ vSource.ValidCharsString := 'a..z';
vDest.Assign(vSource);
vStr := GetEnumName(TypeInfo(TInstantAttributeType),
@@ -286,7 +290,7 @@
AssertEquals('StorageKind incorrect', 'skEmbedded', vStr);
AssertEquals('ExternalStorageName incorrect', 'ExternalStorageName',
vDest.ExternalStorageName);
- AssertTrue('ValidChars incorrect', 'i' in vDest.ValidChars);
+ AssertEquals('ValidChars incorrect', 'a..z', vDest.ValidCharsString);
finally
vSource.Free;
vDest.Free;
@@ -323,11 +327,14 @@
try
vReturnValue := FInstantAttributeMetadata.CreateAttribute(vObject)
as TInstantAttribute;
- AssertNotNull('vReturnValue', vReturnValue);
- AssertEquals('AsString', 'Default', vReturnValue.AsString);
- AssertNotNull('Metadata ', vReturnValue.Metadata);
- AssertEquals('Classname', 'TInstantString', vReturnValue.ClassName);
- vReturnValue.Free;
+ try
+ AssertNotNull('vReturnValue', vReturnValue);
+ AssertEquals('AsString', 'Default', vReturnValue.AsString);
+ AssertNotNull('Metadata ', vReturnValue.Metadata);
+ AssertEquals('Classname', 'TInstantString', vReturnValue.ClassName);
+ finally
+ vReturnValue.Free;
+ end;
finally
vObject.Free;
end;
@@ -343,6 +350,32 @@
AssertTrue('IsAttributeClass error for TInstantMetadata!', vReturnValue);
end;
+procedure TestTInstantAttributeMetadata.TestAttributeValidation;
+var
+ vObject: TInstantObject;
+begin
+ vObject := TInstantObject.Create(FConn);
+ try
+ FTempAttr := FInstantAttributeMetadata.CreateAttribute(vObject)
+ as TInstantAttribute;
+ try
+ FTempAttr.AsString := 'only valid chars';
+ AssertException(EInstantValidationError, SetInvalidValueInTempAttr);
+ AssertEquals('AsString', 'only valid chars', FTempAttr.AsString);
+ finally
+ FreeAndNil(FTempAttr);
+ end;
+ finally
+ vObject.Free;
+ end;
+end;
+
+procedure TestTInstantAttributeMetadata.SetInvalidValueInTempAttr;
+begin
+ Assert(Assigned(FTempAttr));
+ FTempAttr.AsString := 'char z not allowed';
+end;
+
{ TestTInstantAttributeMetadatas }
procedure TestTInstantAttributeMetadatas.SetUp;
Modified: trunk...
[truncated message content] |