├── Tools
└── SchemaGenerator
│ ├── .gitignore
│ ├── SchemaGenerator.identcache
│ ├── SchemaGenerator.res
│ ├── SchemaGenerator.stat
│ ├── SchemaGenerator.dproj.local
│ ├── SchemaGenerator.dpr
│ └── SchemaGenerator.dproj
├── Demo
├── ORMDemo.res
├── ORMDemo_project.tvsconfig
├── SchemaGenerator.exe
├── ORMDemo.eof
├── Migrations
│ ├── migration_003_add_seeds_to_test_table.pas
│ ├── migration_007_drop_index_on_users_table.pas
│ ├── migration_009_add_avatar_to_users_table.pas
│ ├── migration_008_drop_foreign_on_test_table.pas
│ ├── migration_005_delete_birthday_from_users_table.pas
│ ├── migration_004_update_price_in_users_table.pas
│ ├── migration_006_create_images_table.pas
│ ├── migration_002_create_test_table.pas
│ ├── migration_010_create_pivot_user_friend_table.pas
│ └── migration_001_create_users_table.pas
├── ORMDemo.stat
├── Models
│ ├── OlfeiImage.pas
│ ├── OlfeiTest.pas
│ └── OlfeiUser.pas
├── Collections
│ ├── OlfeiUsers.pas
│ └── OlfeiImages.pas
├── schema.inc
├── ORMDemo.identcache
├── ORMDemo.dpr
├── ORMDemoMain.fmx
├── ORMDemoMain.pas
├── ORMDemo.deployproj
└── ORMDemo.dproj.local
├── Core
├── Bin
│ ├── MySQL
│ │ ├── libmysql.dll
│ │ └── libmysql.lib
│ └── SQLite
│ │ ├── sqlite3.dll
│ │ └── sqlite3.def
├── OlfeiPool.pas
├── OlfeiSQL.pas
├── OlfeiSchema.pas
└── OlfeiCollection.pas
├── .gitignore
├── Drivers
├── OlfeiSQLDriver.pas
├── OlfeiDriverMySQL.pas
└── OlfeiDriverSQLite.pas
└── README.md
/Tools/SchemaGenerator/.gitignore:
--------------------------------------------------------------------------------
1 | /win32
--------------------------------------------------------------------------------
/Demo/ORMDemo.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Demo/ORMDemo.res
--------------------------------------------------------------------------------
/Demo/ORMDemo_project.tvsconfig:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/SchemaGenerator.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Demo/SchemaGenerator.exe
--------------------------------------------------------------------------------
/Core/Bin/MySQL/libmysql.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Core/Bin/MySQL/libmysql.dll
--------------------------------------------------------------------------------
/Core/Bin/MySQL/libmysql.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Core/Bin/MySQL/libmysql.lib
--------------------------------------------------------------------------------
/Core/Bin/SQLite/sqlite3.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Core/Bin/SQLite/sqlite3.dll
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.identcache:
--------------------------------------------------------------------------------
1 | :F:\My\delphi-orm\Tools\SchemaGenerator\SchemaGenerator.dpr
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /demo/win32
2 | /demo/android
3 | /bin
4 | AndroidManifest.template.xml
5 | __history
6 | __recovery
7 | *.dcu
8 | *.o
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Tools/SchemaGenerator/SchemaGenerator.res
--------------------------------------------------------------------------------
/Demo/ORMDemo.eof:
--------------------------------------------------------------------------------
1 |
2 | [Exception Log]
3 | EurekaLog Version=7007
4 | Activate=0
5 | DeleteMapAfterCompile=0
6 | Encrypt Password=""
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_003_add_seeds_to_test_table.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/HEAD/Demo/Migrations/migration_003_add_seeds_to_test_table.pas
--------------------------------------------------------------------------------
/Demo/ORMDemo.stat:
--------------------------------------------------------------------------------
1 | [Stats]
2 | EditorSecs=68599
3 | DesignerSecs=242
4 | InspectorSecs=3
5 | CompileSecs=1946110
6 | OtherSecs=4565
7 | StartTime=12.08.2015 9:57:00
8 | RealKeys=0
9 | EffectiveKeys=0
10 | DebugSecs=11713
11 |
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.stat:
--------------------------------------------------------------------------------
1 | [Stats]
2 | EditorSecs=75
3 | DesignerSecs=1
4 | InspectorSecs=1
5 | CompileSecs=1349
6 | OtherSecs=11
7 | StartTime=22.01.2017 21:12:45
8 | RealKeys=0
9 | EffectiveKeys=0
10 | DebugSecs=1
11 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_007_drop_index_on_users_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_007_drop_index_on_users_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := UpdateTable('users');
12 |
13 | OlfeiTable.DropIndex('name');
14 | end.
15 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_009_add_avatar_to_users_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_009_add_avatar_to_users_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := UpdateTable('users');
12 |
13 | OlfeiTable.NewBlob('avatar');
14 | end.
15 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_008_drop_foreign_on_test_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_008_drop_foreign_on_test_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := UpdateTable('test');
12 |
13 | OlfeiTable.DropForeign('user_id');
14 | end.
15 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_005_delete_birthday_from_users_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_005_delete_birthday_from_users_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := UpdateTable('users');
12 |
13 | OlfeiTable.Drop('test');
14 | end.
15 |
16 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_004_update_price_in_users_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_004_update_price_in_users_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := UpdateTable('users');
12 |
13 | OlfeiTable.UpdateInteger('test');
14 | end.
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Demo/Models/OlfeiImage.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiImage;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, OlfeiORM;
7 |
8 | type
9 | [TOlfeiTable('images')]
10 | TOlfeiImage = class(TOlfeiCoreORM)
11 | public
12 | [TOlfeiField('name')]
13 | property Name: String index 0 read GetString write SetString;
14 | end;
15 |
16 | implementation
17 |
18 | end.
19 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_006_create_images_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_006_create_images_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := NewTable('images');
12 |
13 | OlfeiTable.NewText('name');
14 | OlfeiTable.NewIntegerUnsigned('user_id');
15 | OlfeiTable.NewForeign('users', 'user_id', 'id');
16 | end.
17 |
--------------------------------------------------------------------------------
/Demo/Collections/OlfeiUsers.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiUsers;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, OlfeiCollection, OlfeiUser;
7 |
8 | type
9 | TOlfeiUsers = class(TOlfeiCollection)
10 | public
11 | constructor Create(FDB: TOlfeiDB); overload;
12 | end;
13 |
14 | implementation
15 |
16 | constructor TOlfeiUsers.Create(FDB: TOlfeiDB);
17 | begin
18 | inherited Create(FDB, TOlfeiUser);
19 | end;
20 |
21 | end.
22 |
--------------------------------------------------------------------------------
/Demo/Collections/OlfeiImages.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiImages;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, OlfeiCollection, OlfeiImage;
7 |
8 | type
9 | TOlfeiImages = class(TOlfeiCollection)
10 | public
11 | constructor Create(FDB: TOlfeiDB); overload;
12 | end;
13 |
14 | implementation
15 |
16 | constructor TOlfeiImages.Create(FDB: TOlfeiDB);
17 | begin
18 | inherited Create(FDB, TOlfeiImage);
19 | end;
20 |
21 | end.
22 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_002_create_test_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_002_create_test_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := NewTable('test');
12 |
13 | OlfeiTable.NewString('name');
14 | OlfeiTable.NewInteger('years');
15 | OlfeiTable.NewIntegerUnsigned('user_id');
16 |
17 | OlfeiTable.NewForeign('users', 'user_id', 'id', 'CASCADE');
18 | end.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Demo/schema.inc:
--------------------------------------------------------------------------------
1 | migration_001_create_users_table,
2 | migration_002_create_test_table,
3 | migration_003_add_seeds_to_test_table,
4 | migration_004_update_price_in_users_table,
5 | migration_005_delete_birthday_from_users_table,
6 | migration_006_create_images_table,
7 | migration_007_drop_index_on_users_table,
8 | migration_008_drop_foreign_on_test_table,
9 | migration_009_add_avatar_to_users_table,
10 | migration_010_create_pivot_user_friend_table,
11 |
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.dproj.local:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1899.12.30 00:00:00.000.867,=C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Unit1.pas
5 | 1899.12.30 00:00:00.000.424,C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Project1.dproj=F:\My\delphi-orm\Tools\SchemaGenerator\SchemaGenerator.dproj
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_010_create_pivot_user_friend_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_010_create_pivot_user_friend_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := PivotTable('user_friend');
12 |
13 | OlfeiTable.NewIntegerUnsigned('user_id');
14 | OlfeiTable.NewIntegerUnsigned('friend_id');
15 |
16 | OlfeiTable.NewForeign('users', 'user_id', 'id');
17 | OlfeiTable.NewForeign('users', 'friend_id', 'id');
18 | end.
19 |
--------------------------------------------------------------------------------
/Demo/Migrations/migration_001_create_users_table.pas:
--------------------------------------------------------------------------------
1 | unit migration_001_create_users_table;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSchema;
7 |
8 | implementation
9 |
10 | begin
11 | OlfeiTable := NewTable('users');
12 |
13 | OlfeiTable.NewString('name');
14 | OlfeiTable.NewInteger('count');
15 | OlfeiTable.NewFloat('price');
16 | OlfeiTable.NewText('description');
17 | OlfeiTable.NewBoolean('active');
18 | OlfeiTable.NewDate('birthday');
19 | OlfeiTable.NewDateTime('last');
20 | OlfeiTable.NewTimestamps();
21 |
22 | OlfeiTable.NewFloat('test');
23 |
24 | OlfeiTable.NewIndex('name');
25 | end.
--------------------------------------------------------------------------------
/Demo/Models/OlfeiTest.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiTest;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, OlfeiORM, OlfeiUser;
7 |
8 | type
9 | [TOlfeiTable('test')]
10 | TOlfeiTest = class(TOlfeiCoreORM)
11 | protected
12 | function GetOlfeiUser(index: Integer): TOlfeiUser;
13 | public
14 | [TOlfeiField('name')]
15 | property Name: String index 0 read GetString write SetString;
16 |
17 | [TOlfeiField('years')]
18 | property Years: Integer index 1 read GetInteger write SetInteger;
19 |
20 | [TOlfeiForeignField('user_id', 'id')]
21 | property User: TOlfeiUser index 2 read GetOlfeiUser;
22 | end;
23 |
24 | implementation
25 |
26 | function TOlfeiTest.GetOlfeiUser(index: Integer): TOlfeiUser;
27 | begin
28 | Result := TOlfeiUser(Self.GetForeignObject(index, TOlfeiUser));
29 | end;
30 |
31 | end.
32 |
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.dpr:
--------------------------------------------------------------------------------
1 | program SchemaGenerator;
2 |
3 | {$APPTYPE CONSOLE}
4 |
5 | {$R *.res}
6 |
7 | uses
8 | System.SysUtils, Classes;
9 |
10 | var
11 | i: Integer;
12 | SL, SLFiles: TStringList;
13 | SearchResult: TSearchRec;
14 |
15 | begin
16 | try
17 | SL := TStringList.Create;
18 |
19 | for i := 1 to ParamCount do
20 | SL.Add(ParamStr(i));
21 |
22 | if SL.IndexOfName('project') = -1 then
23 | SL.Values['project'] := ExtractFilePath(ParamStr(0));
24 |
25 | if SL.IndexOfName('migration') = -1 then
26 | SL.Values['migration'] := ExtractFilePath(ParamStr(0)) + 'Migrations';
27 |
28 | SLFiles := TStringList.Create;
29 | if FindFirst(SL.Values['migration'] + '\migration_*.pas', faAnyFile, searchResult) = 0 then
30 | begin
31 | repeat
32 | SLFiles.Add(StringReplace(SearchResult.Name, '.pas', '', []) + ',');
33 | until FindNext(SearchResult) <> 0;
34 |
35 | FindClose(searchResult);
36 | end;
37 |
38 | SLFiles.SaveToFile(SL.Values['project'] + '\schema.inc');
39 |
40 | SLFiles.Free;
41 | SL.Free;
42 | except
43 | on E: Exception do
44 | Writeln(E.ClassName, ': ', E.Message);
45 | end;
46 | end.
47 |
--------------------------------------------------------------------------------
/Demo/ORMDemo.identcache:
--------------------------------------------------------------------------------
1 | JE:\Projects\delphi-orm\Demo\Migrations\migration_002_create_test_table.pas PE:\Projects\delphi-orm\Demo\Migrations\migration_003_add_seeds_to_test_table.pas LE:\Projects\delphi-orm\Demo\Migrations\migration_006_create_images_table.pas RE:\Projects\delphi-orm\Demo\Migrations\migration_007_drop_index_on_users_table.pas 7E:\Projects\delphi-orm\Demo\Collections\OlfeiImages.pas SE:\Projects\delphi-orm\Demo\Migrations\migration_008_drop_foreign_on_test_table.pas 6E:\Projects\delphi-orm\Demo\Collections\OlfeiUsers.pas KE:\Projects\delphi-orm\Demo\Migrations\migration_001_create_users_table.pas 0E:\Projects\delphi-orm\Demo\Models\OlfeiUser.pas 0E:\Projects\delphi-orm\Demo\Models\OlfeiTest.pas YE:\Projects\delphi-orm\Demo\Migrations\migration_005_delete_birthday_from_users_table.pas +E:\Projects\delphi-orm\Demo\ORMDemoMain.pas (E:\Projects\delphi-orm\Core\OlfeiSQL.pas 'E:\Projects\delphi-orm\Demo\ORMDemo.dpr 1E:\Projects\delphi-orm\Demo\Models\OlfeiImage.pas RE:\Projects\delphi-orm\Demo\Migrations\migration_009_add_avatar_to_users_table.pas WE:\Projects\delphi-orm\Demo\Migrations\migration_010_create_pivot_user_friend_table.pas TE:\Projects\delphi-orm\Demo\Migrations\migration_004_update_price_in_users_table.pas
--------------------------------------------------------------------------------
/Demo/ORMDemo.dpr:
--------------------------------------------------------------------------------
1 | program ORMDemo;
2 |
3 | uses
4 | System.StartUpCopy,
5 | FMX.Forms,
6 | ORMDemoMain in 'ORMDemoMain.pas' {frmMain},
7 | OlfeiUsers in 'Collections\OlfeiUsers.pas',
8 | migration_001_create_users_table in 'Migrations\migration_001_create_users_table.pas',
9 | migration_002_create_test_table in 'Migrations\migration_002_create_test_table.pas',
10 | migration_003_add_seeds_to_test_table in 'Migrations\migration_003_add_seeds_to_test_table.pas',
11 | OlfeiTest in 'Models\OlfeiTest.pas',
12 | OlfeiUser in 'Models\OlfeiUser.pas',
13 | migration_004_update_price_in_users_table in 'Migrations\migration_004_update_price_in_users_table.pas',
14 | migration_005_delete_birthday_from_users_table in 'Migrations\migration_005_delete_birthday_from_users_table.pas',
15 | migration_006_create_images_table in 'Migrations\migration_006_create_images_table.pas',
16 | OlfeiImages in 'Collections\OlfeiImages.pas',
17 | OlfeiImage in 'Models\OlfeiImage.pas',
18 | migration_007_drop_index_on_users_table in 'Migrations\migration_007_drop_index_on_users_table.pas',
19 | migration_008_drop_foreign_on_test_table in 'Migrations\migration_008_drop_foreign_on_test_table.pas',
20 | migration_009_add_avatar_to_users_table in 'Migrations\migration_009_add_avatar_to_users_table.pas',
21 | migration_010_create_pivot_user_friend_table in 'Migrations\migration_010_create_pivot_user_friend_table.pas';
22 |
23 | {$R *.res}
24 |
25 | begin
26 | Application.Initialize;
27 | Application.CreateForm(TfrmMain, frmMain);
28 | Application.Run;
29 | end.
30 |
--------------------------------------------------------------------------------
/Drivers/OlfeiSQLDriver.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiSQLDriver;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, Classes;
7 |
8 | type
9 | TOlfeiSQLDriver = class
10 | public
11 | OlfeiDB: TOlfeiDB;
12 |
13 | function CheckTable(TableName: string): Boolean; virtual; abstract;
14 | function FieldTypeToSQL(AType: Word; ASize, ADecimalSize: integer): string; virtual; abstract;
15 | procedure NewTable(OlfeiTable: TObject); virtual; abstract;
16 | procedure UpdateTable(OlfeiTable: TObject); virtual; abstract;
17 | procedure DropTable(OlfeiTable: TObject); virtual; abstract;
18 | procedure Init(Parameters: TStringList); virtual; abstract;
19 | function Convert(Parameters: TStringList): TStringList; virtual; abstract;
20 | function RandomOrder: string; virtual; abstract;
21 |
22 | function PrepareDefault(ADefault: string): String;
23 | function IsMigrate(MigrationName: string): Boolean;
24 |
25 | constructor Create(DB: TOlfeiDB); overload;
26 | end;
27 |
28 | implementation
29 |
30 | constructor TOlfeiSQLDriver.Create(DB: TOlfeiDB);
31 | begin
32 | Self.OlfeiDB := DB;
33 | end;
34 |
35 | function TOlfeiSQLDriver.IsMigrate(MigrationName: string): boolean;
36 | begin
37 | Result := Self.OlfeiDB.GetOnce('SELECT COUNT(id) FROM `migrations` WHERE name LIKE "' + MigrationName + '"', 'integer') <> '0';
38 | end;
39 |
40 | function TOlfeiSQLDriver.PrepareDefault(ADefault: string): string;
41 | begin
42 | if ADefault = 'NULL' then
43 | Result := 'DEFAULT NULL'
44 | else if ADefault = 'NOT NULL' then
45 | Result := 'NOT NULL'
46 | else
47 | Result := 'DEFAULT "' + ADefault + '"';
48 | end;
49 |
50 | end.
51 |
52 |
--------------------------------------------------------------------------------
/Demo/Models/OlfeiUser.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiUser;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, OlfeiORM, OlfeiImage, System.Classes, OlfeiCollection;
7 |
8 | type
9 | [TOlfeiTable('users')]
10 | TOlfeiUser = class(TOlfeiORM)
11 | private
12 | function GetOlfeiImage(index: Integer): TOlfeiImage;
13 | function GetOlfeiFriends(index: integer): TOlfeiCollection;
14 | public
15 | [TOlfeiField('name')]
16 | property Name: String index 0 read GetString write SetString;
17 |
18 | [TOlfeiField('count')]
19 | property Count: Integer index 1 read GetInteger write SetInteger;
20 |
21 | [TOlfeiField('price')]
22 | property Price: Real index 2 read GetFloat write SetFloat;
23 |
24 | [TOlfeiField('description')]
25 | property Description: String index 3 read GetString write SetString;
26 |
27 | [TOlfeiField('active')]
28 | property Active: Boolean index 4 read GetBoolean write SetBoolean;
29 |
30 | [TOlfeiField('birthday')]
31 | property Birthday: TDate index 5 read GetDate write SetDate;
32 |
33 | [TOlfeiField('last')]
34 | property Last: TDateTime index 6 read GetDateTime write SetDateTime;
35 |
36 | [TOlfeiBlobField('avatar')]
37 | property Avatar: TStringStream index 0 read GetBlob;
38 |
39 | [TOlfeiForeignField('id', 'user_id')]
40 | property Images: TOlfeiImage index 0 read GetOlfeiImage;
41 |
42 | [TOlfeiPivotField('user_friend', 'user_id', 'id', 'friend_id', 'id')]
43 | property Friends: TOlfeiCollection index 1 read GetOlfeiFriends;
44 | end;
45 |
46 | implementation
47 |
48 | function TOlfeiUser.GetOlfeiImage(index: Integer): TOlfeiImage;
49 | begin
50 | Result := TOlfeiImage(Self.GetForeignObject(index, TOlfeiImage));
51 | end;
52 |
53 | function TOlfeiUser.GetOlfeiFriends(index: Integer): TOlfeiCollection;
54 | begin
55 | Result := TOlfeiCollection(Self.GetPivotCollection(index, TOlfeiUser));
56 | end;
57 |
58 | end.
59 |
--------------------------------------------------------------------------------
/Core/OlfeiPool.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiPool;
2 |
3 | interface
4 |
5 | uses
6 | FireDAC.Comp.Client, Classes, System.SysUtils;
7 |
8 | type
9 | TOlfeiPoolResult = record
10 | name: string;
11 | end;
12 |
13 | TOlfeiPool = class
14 | private
15 | ConnectionManager: TFDManager;
16 | CountConnection: TStringList;
17 |
18 | public
19 | constructor Create;
20 | destructor Destroy; override;
21 |
22 | function AddConnection(Driver: string; SL: TStringList): TOlfeiPoolResult;
23 | end;
24 |
25 | implementation
26 |
27 | { TOlfeiPool }
28 |
29 | uses
30 | OlfeiDriverMySQL, OlfeiDriverSQLite;
31 |
32 | constructor TOlfeiPool.Create;
33 | begin
34 | inherited;
35 |
36 | Self.ConnectionManager := TFDManager.Create(nil);
37 | Self.ConnectionManager.SilentMode := True;
38 |
39 | Self.ConnectionManager.Active := True;
40 |
41 | CountConnection := TStringList.Create;
42 | end;
43 |
44 | destructor TOlfeiPool.Destroy;
45 | begin
46 | Self.ConnectionManager.Free;
47 | CountConnection.Free;
48 | end;
49 |
50 | function TOlfeiPool.AddConnection(Driver: string; SL: TStringList): TOlfeiPoolResult;
51 | var
52 | tmp: string;
53 | Parameters: TStringList;
54 | DriverConnect: TObject;
55 | begin
56 | Driver := SL.Values['driver'];
57 | Parameters := TStringList.Create;
58 |
59 | if Driver = 'sqlite' then
60 | begin
61 | DriverConnect := TOlfeiDriverSQLite.Create(nil);
62 | Parameters := (DriverConnect as TOlfeiDriverSQLite).Convert(SL);
63 | (DriverConnect as TOlfeiDriverSQLite).Free;
64 | end;
65 |
66 | if Driver = 'mysql' then
67 | begin
68 | {$IFDEF MSWINDOWS}
69 | DriverConnect := TOlfeiDriverMySQL.Create(nil);
70 | Parameters := (DriverConnect as TOlfeiDriverMySQL).Convert(SL);
71 | (DriverConnect as TOlfeiDriverMySQL).Free;
72 | {$ELSE}
73 | raise Exception.Create('Mobile platforms support only SQLite');
74 | {$ENDIF}
75 | end;
76 |
77 | Parameters.Values['Pooled'] := 'True';
78 | Parameters.Values['POOL_MaximumItems'] := '500';
79 |
80 | tmp := '1';
81 | if CountConnection.IndexOf(Driver) > -1 then
82 | tmp := (CountConnection.Values[Driver].ToInteger + 1).ToString;
83 |
84 | Self.ConnectionManager.AddConnectionDef('Connection_' + Driver + '_' + tmp, Driver, Parameters);
85 |
86 | CountConnection.Values[Driver] := tmp;
87 |
88 | Result.name := 'Connection_' + Driver + '_' + tmp;
89 |
90 | Parameters.Free;
91 | end;
92 |
93 | end.
94 |
--------------------------------------------------------------------------------
/Demo/ORMDemoMain.fmx:
--------------------------------------------------------------------------------
1 | object frmMain: TfrmMain
2 | Left = 0
3 | Top = 0
4 | Caption = 'HRC ORM Demo'
5 | ClientHeight = 480
6 | ClientWidth = 640
7 | FormFactor.Width = 320
8 | FormFactor.Height = 480
9 | FormFactor.Devices = [Desktop]
10 | DesignerMasterStyle = 0
11 | object btnCollection: TButton
12 | Align = Bottom
13 | Margins.Left = 10.000000000000000000
14 | Margins.Top = 10.000000000000000000
15 | Margins.Right = 10.000000000000000000
16 | Margins.Bottom = 10.000000000000000000
17 | Position.X = 10.000000000000000000
18 | Position.Y = 336.000000000000000000
19 | Size.Width = 620.000000000000000000
20 | Size.Height = 38.000000000000000000
21 | Size.PlatformDefault = False
22 | TabOrder = 0
23 | Text = 'Collection'
24 | OnClick = btnCollectionClick
25 | end
26 | object mmoTest: TMemo
27 | Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
28 | DataDetectorTypes = []
29 | Align = Client
30 | Margins.Left = 10.000000000000000000
31 | Margins.Top = 10.000000000000000000
32 | Margins.Right = 10.000000000000000000
33 | Size.Width = 620.000000000000000000
34 | Size.Height = 316.000000000000000000
35 | Size.PlatformDefault = False
36 | TabOrder = 1
37 | Viewport.Width = 616.000000000000000000
38 | Viewport.Height = 312.000000000000000000
39 | end
40 | object btnSingle: TButton
41 | Align = Bottom
42 | Margins.Left = 10.000000000000000000
43 | Margins.Right = 10.000000000000000000
44 | Margins.Bottom = 10.000000000000000000
45 | Position.X = 10.000000000000000000
46 | Position.Y = 384.000000000000000000
47 | Size.Width = 620.000000000000000000
48 | Size.Height = 38.000000000000000000
49 | Size.PlatformDefault = False
50 | TabOrder = 4
51 | Text = 'Single'
52 | OnClick = btnSingleClick
53 | end
54 | object btnNew: TButton
55 | Align = Bottom
56 | Margins.Left = 10.000000000000000000
57 | Margins.Right = 10.000000000000000000
58 | Margins.Bottom = 10.000000000000000000
59 | Position.X = 10.000000000000000000
60 | Position.Y = 432.000000000000000000
61 | Size.Width = 620.000000000000000000
62 | Size.Height = 38.000000000000000000
63 | Size.PlatformDefault = False
64 | TabOrder = 3
65 | Text = ' New'
66 | OnClick = btnNewClick
67 | end
68 | object fdgxwtcrstTest: TFDGUIxWaitCursor
69 | Provider = 'FMX'
70 | Left = 456
71 | Top = 328
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/Demo/ORMDemoMain.pas:
--------------------------------------------------------------------------------
1 | unit ORMDemoMain;
2 |
3 | interface
4 |
5 | uses
6 | System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
7 | FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
8 | FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo,
9 | FireDAC.UI.Intf, FireDAC.FMXUI.Wait, FireDAC.Stan.Intf, FireDAC.Comp.UI,
10 | System.IniFiles, FireDac.Comp.Client, System.Generics.Collections, System.Threading;
11 |
12 | type
13 | TfrmMain = class(TForm)
14 | btnCollection: TButton;
15 | mmoTest: TMemo;
16 | fdgxwtcrstTest: TFDGUIxWaitCursor;
17 | btnSingle: TButton;
18 | btnNew: TButton;
19 | procedure btnCollectionClick(Sender: TObject);
20 | procedure btnSingleClick(Sender: TObject);
21 | procedure btnNewClick(Sender: TObject);
22 | private
23 | { Private declarations }
24 | public
25 | { Public declarations }
26 | end;
27 |
28 | var
29 | frmMain: TfrmMain;
30 |
31 | implementation
32 |
33 | {$R *.fmx}
34 |
35 | uses
36 | OlfeiSQL, OlfeiUser, OlfeiUsers, OlfeiTest,
37 | OlfeiORM, OlfeiCollection, OlfeiImage;
38 |
39 | procedure TfrmMain.btnNewClick(Sender: TObject);
40 | var
41 | OlfeiDB: TOlfeiDB;
42 | OlfeiUser, OlfeiFriend: TOlfeiUser;
43 | OlfeiImage: TOlfeiImage;
44 | begin
45 | OlfeiDB := TOlfeiDB.Create;
46 |
47 | OlfeiDB.Parameters.Values['driver'] := 'mysql';
48 | OlfeiDB.Parameters.Values['host'] := '127.0.0.1';
49 | OlfeiDB.Parameters.Values['database'] := 'test';
50 | OlfeiDB.Parameters.Values['user'] := 'root';
51 | OlfeiDB.Parameters.Values['password'] := '';
52 |
53 | //OlfeiDB.Parameters.Values['driver'] := 'sqlite';
54 | //OlfeiDB.Parameters.Values['database'] := './test.sqlite';
55 |
56 | OlfeiDB.Connect;
57 |
58 | OlfeiUser := TOlfeiUser.Create(OlfeiDB);
59 | OlfeiUser.Find(1);
60 |
61 | // OlfeiUser.Attach();
62 | OlfeiUser.Avatar.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'test.txt');
63 |
64 | OlfeiUser.Save;
65 |
66 | mmoTest.Lines.Add(OlfeiUser.Avatar.DataString);
67 | mmoTest.Lines.Add(OlfeiUser.Avatar.DataString);
68 | mmoTest.Lines.Add(OlfeiUser.Avatar.DataString);
69 | mmoTest.Lines.Add(OlfeiUser.Avatar.DataString);
70 |
71 | {for OlfeiImage in OlfeiUser.Images.All do
72 | mmoTest.Lines.Add(OlfeiImage.Name); }
73 |
74 | for OlfeiFriend in OlfeiUser.Friends.All do
75 | mmoTest.Lines.Add('Friend: ' + OlfeiFriend.Name);
76 |
77 | OlfeiUser.Name := OlfeiUser.Name;
78 |
79 | OlfeiUser.Save;
80 |
81 | OlfeiUser.Free;
82 |
83 | OlfeiDB.Backup('test.sql');
84 |
85 | OlfeiDB.Free;
86 | end;
87 |
88 | procedure TfrmMain.btnSingleClick(Sender: TObject);
89 | begin
90 | TTask.Run(procedure
91 | var
92 | OlfeiDB: TOlfeiDB;
93 | OlfeiTest: TOlfeiTest;
94 | OlfeiUsers: TOlfeiUsers;
95 | // OlfeiImage: TOlfeiImage;
96 |
97 | //OlfeiTest: TOlfeiTest;
98 | OlfeiTestCollection: TOlfeiCollection;
99 |
100 | i: integer;
101 | begin
102 | OlfeiDB := TOlfeiDB.Create;
103 |
104 | OlfeiDB.Parameters.Values['driver'] := 'sqlite';
105 | OlfeiDB.Parameters.Values['database'] := './test.sqlite';
106 |
107 | {OlfeiDB.Parameters.Values['driver'] := 'mysql';
108 | OlfeiDB.Parameters.Values['host'] := '192.168.1.6';
109 | OlfeiDB.Parameters.Values['database'] := 'menu';
110 | OlfeiDB.Parameters.Values['user'] := 'hrc';
111 | OlfeiDB.Parameters.Values['password'] := 'hrc.lan';}
112 |
113 | OlfeiDB.Connect;
114 |
115 | OlfeiTest := TOlfeiTest.Create(OlfeiDB, 1);
116 | Self.mmoTest.Lines.Add(OlfeiTest.User.Images.ID.ToString);
117 |
118 | {for i := 0 to 10 do
119 | begin
120 | // OlfeiUser := OlfeiUsers.Where('id', '=', '1').First;
121 | // OlfeiTest := OlfeiTestCollection.Where('id', '=', '1').First;
122 | //for OlfeiImage in OlfeiUser.Images.All do
123 |
124 |
125 | {
126 | OlfeiUser := TOlfeiUser.Create(OlfeiDB, 1);
127 | OlfeiUser.Free;
128 | }
129 |
130 | {if OlfeiImage.Exists then
131 | TThread.Synchronize(nil, procedure
132 | begin
133 | mmoTest.Lines.Add(OlfeiImage.Name);
134 | end);
135 | end;
136 |
137 | OlfeiTestCollection.Free;
138 | OlfeiUsers.Free; }
139 | OlfeiTest.Free;
140 | OlfeiDB.Free;
141 | end);
142 | end;
143 |
144 | procedure TfrmMain.btnCollectionClick(Sender: TObject);
145 | begin
146 | TTask.Run(procedure
147 | var
148 | OlfeiDB: TOlfeiDB;
149 | OlfeiUser: TOlfeiUser;
150 | OlfeiUsers: TOlfeiUsers;
151 |
152 | Str: string;
153 | i: Integer;
154 | begin
155 | OlfeiDB := TOlfeiDB.Create;
156 |
157 | OlfeiDB.Parameters.Values['driver'] := 'sqlite';
158 | OlfeiDB.Parameters.Values['database'] := './test.sqlite';
159 |
160 | OlfeiDB.Connect;
161 |
162 | OlfeiUsers := TOlfeiUsers.Create(OlfeiDB);
163 | str := OlfeiUsers.Where('id', '>', '0').ToJSON().ToJSON;
164 |
165 | mmoTest.Lines.Add(str);
166 |
167 | for i := 0 to 10 do
168 | begin
169 | for OlfeiUser in OlfeiUsers.Where('id', '>', '0').All do
170 | begin
171 | TThread.Synchronize(nil, procedure
172 | begin
173 | mmoTest.Lines.Add(OlfeiUser.Name);
174 | end);
175 | end;
176 | end;
177 |
178 | OlfeiUsers.Free;
179 | OlfeiDB.Free;
180 | end);
181 | end;
182 |
183 | end.
184 |
--------------------------------------------------------------------------------
/Core/Bin/SQLite/sqlite3.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | sqlite3_aggregate_context
3 | sqlite3_aggregate_count
4 | sqlite3_auto_extension
5 | sqlite3_backup_finish
6 | sqlite3_backup_init
7 | sqlite3_backup_pagecount
8 | sqlite3_backup_remaining
9 | sqlite3_backup_step
10 | sqlite3_bind_blob
11 | sqlite3_bind_blob64
12 | sqlite3_bind_double
13 | sqlite3_bind_int
14 | sqlite3_bind_int64
15 | sqlite3_bind_null
16 | sqlite3_bind_parameter_count
17 | sqlite3_bind_parameter_index
18 | sqlite3_bind_parameter_name
19 | sqlite3_bind_text
20 | sqlite3_bind_text16
21 | sqlite3_bind_text64
22 | sqlite3_bind_value
23 | sqlite3_bind_zeroblob
24 | sqlite3_bind_zeroblob64
25 | sqlite3_blob_bytes
26 | sqlite3_blob_close
27 | sqlite3_blob_open
28 | sqlite3_blob_read
29 | sqlite3_blob_reopen
30 | sqlite3_blob_write
31 | sqlite3_busy_handler
32 | sqlite3_busy_timeout
33 | sqlite3_cancel_auto_extension
34 | sqlite3_changes
35 | sqlite3_clear_bindings
36 | sqlite3_close
37 | sqlite3_close_v2
38 | sqlite3_collation_needed
39 | sqlite3_collation_needed16
40 | sqlite3_column_blob
41 | sqlite3_column_bytes
42 | sqlite3_column_bytes16
43 | sqlite3_column_count
44 | sqlite3_column_database_name
45 | sqlite3_column_database_name16
46 | sqlite3_column_decltype
47 | sqlite3_column_decltype16
48 | sqlite3_column_double
49 | sqlite3_column_int
50 | sqlite3_column_int64
51 | sqlite3_column_name
52 | sqlite3_column_name16
53 | sqlite3_column_origin_name
54 | sqlite3_column_origin_name16
55 | sqlite3_column_table_name
56 | sqlite3_column_table_name16
57 | sqlite3_column_text
58 | sqlite3_column_text16
59 | sqlite3_column_type
60 | sqlite3_column_value
61 | sqlite3_commit_hook
62 | sqlite3_compileoption_get
63 | sqlite3_compileoption_used
64 | sqlite3_complete
65 | sqlite3_complete16
66 | sqlite3_config
67 | sqlite3_context_db_handle
68 | sqlite3_create_collation
69 | sqlite3_create_collation16
70 | sqlite3_create_collation_v2
71 | sqlite3_create_function
72 | sqlite3_create_function16
73 | sqlite3_create_function_v2
74 | sqlite3_create_module
75 | sqlite3_create_module_v2
76 | sqlite3_data_count
77 | sqlite3_db_cacheflush
78 | sqlite3_db_config
79 | sqlite3_db_filename
80 | sqlite3_db_handle
81 | sqlite3_db_mutex
82 | sqlite3_db_readonly
83 | sqlite3_db_release_memory
84 | sqlite3_db_status
85 | sqlite3_declare_vtab
86 | sqlite3_enable_load_extension
87 | sqlite3_enable_shared_cache
88 | sqlite3_errcode
89 | sqlite3_errmsg
90 | sqlite3_errmsg16
91 | sqlite3_errstr
92 | sqlite3_exec
93 | sqlite3_expanded_sql
94 | sqlite3_expired
95 | sqlite3_extended_errcode
96 | sqlite3_extended_result_codes
97 | sqlite3_file_control
98 | sqlite3_finalize
99 | sqlite3_free
100 | sqlite3_free_table
101 | sqlite3_get_autocommit
102 | sqlite3_get_auxdata
103 | sqlite3_get_table
104 | sqlite3_global_recover
105 | sqlite3_initialize
106 | sqlite3_interrupt
107 | sqlite3_last_insert_rowid
108 | sqlite3_libversion
109 | sqlite3_libversion_number
110 | sqlite3_limit
111 | sqlite3_load_extension
112 | sqlite3_log
113 | sqlite3_malloc
114 | sqlite3_malloc64
115 | sqlite3_memory_alarm
116 | sqlite3_memory_highwater
117 | sqlite3_memory_used
118 | sqlite3_mprintf
119 | sqlite3_msize
120 | sqlite3_mutex_alloc
121 | sqlite3_mutex_enter
122 | sqlite3_mutex_free
123 | sqlite3_mutex_leave
124 | sqlite3_mutex_try
125 | sqlite3_next_stmt
126 | sqlite3_open
127 | sqlite3_open16
128 | sqlite3_open_v2
129 | sqlite3_os_end
130 | sqlite3_os_init
131 | sqlite3_overload_function
132 | sqlite3_prepare
133 | sqlite3_prepare16
134 | sqlite3_prepare16_v2
135 | sqlite3_prepare_v2
136 | sqlite3_profile
137 | sqlite3_progress_handler
138 | sqlite3_randomness
139 | sqlite3_realloc
140 | sqlite3_realloc64
141 | sqlite3_release_memory
142 | sqlite3_reset
143 | sqlite3_reset_auto_extension
144 | sqlite3_result_blob
145 | sqlite3_result_blob64
146 | sqlite3_result_double
147 | sqlite3_result_error
148 | sqlite3_result_error16
149 | sqlite3_result_error_code
150 | sqlite3_result_error_nomem
151 | sqlite3_result_error_toobig
152 | sqlite3_result_int
153 | sqlite3_result_int64
154 | sqlite3_result_null
155 | sqlite3_result_subtype
156 | sqlite3_result_text
157 | sqlite3_result_text16
158 | sqlite3_result_text16be
159 | sqlite3_result_text16le
160 | sqlite3_result_text64
161 | sqlite3_result_value
162 | sqlite3_result_zeroblob
163 | sqlite3_result_zeroblob64
164 | sqlite3_rollback_hook
165 | sqlite3_rtree_geometry_callback
166 | sqlite3_rtree_query_callback
167 | sqlite3_set_authorizer
168 | sqlite3_set_auxdata
169 | sqlite3_shutdown
170 | sqlite3_sleep
171 | sqlite3_snprintf
172 | sqlite3_soft_heap_limit
173 | sqlite3_soft_heap_limit64
174 | sqlite3_sourceid
175 | sqlite3_sql
176 | sqlite3_status
177 | sqlite3_status64
178 | sqlite3_step
179 | sqlite3_stmt_busy
180 | sqlite3_stmt_readonly
181 | sqlite3_stmt_status
182 | sqlite3_strglob
183 | sqlite3_stricmp
184 | sqlite3_strlike
185 | sqlite3_strnicmp
186 | sqlite3_system_errno
187 | sqlite3_table_column_metadata
188 | sqlite3_test_control
189 | sqlite3_thread_cleanup
190 | sqlite3_threadsafe
191 | sqlite3_total_changes
192 | sqlite3_trace
193 | sqlite3_trace_v2
194 | sqlite3_transfer_bindings
195 | sqlite3_update_hook
196 | sqlite3_uri_boolean
197 | sqlite3_uri_int64
198 | sqlite3_uri_parameter
199 | sqlite3_user_data
200 | sqlite3_value_blob
201 | sqlite3_value_bytes
202 | sqlite3_value_bytes16
203 | sqlite3_value_double
204 | sqlite3_value_dup
205 | sqlite3_value_free
206 | sqlite3_value_int
207 | sqlite3_value_int64
208 | sqlite3_value_numeric_type
209 | sqlite3_value_subtype
210 | sqlite3_value_text
211 | sqlite3_value_text16
212 | sqlite3_value_text16be
213 | sqlite3_value_text16le
214 | sqlite3_value_type
215 | sqlite3_vfs_find
216 | sqlite3_vfs_register
217 | sqlite3_vfs_unregister
218 | sqlite3_vmprintf
219 | sqlite3_vsnprintf
220 | sqlite3_vtab_config
221 | sqlite3_vtab_on_conflict
222 | sqlite3_wal_autocheckpoint
223 | sqlite3_wal_checkpoint
224 | sqlite3_wal_checkpoint_v2
225 | sqlite3_wal_hook
226 | sqlite3_win32_is_nt
227 | sqlite3_win32_mbcs_to_utf8
228 | sqlite3_win32_mbcs_to_utf8_v2
229 | sqlite3_win32_set_directory
230 | sqlite3_win32_sleep
231 | sqlite3_win32_unicode_to_utf8
232 | sqlite3_win32_utf8_to_mbcs
233 | sqlite3_win32_utf8_to_mbcs_v2
234 | sqlite3_win32_utf8_to_unicode
235 | sqlite3_win32_write_debug
236 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # delphi-orm
2 |
3 | Поддерживает работу с MySQL и SQLite
4 |
5 | Подкиньте в папку с проектом SchemaGenerator.exe. и в настройках проекта пропишите project-options-build events-prebuild events-command
6 | $(PROJECTDIR)\SchemaGenerator migration="$(PROJECTDIR)\Classes\DataBase\Migrations\" , где "$(PROJECTDIR)\Classes\DataBase\Migrations\" путь к файлам для миграций
7 |
8 | # Типы данных
9 |
10 | procedure NewString(AName: string; ASize: integer = 255; ADefault: string = 'NULL');
11 | procedure NewInteger(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
12 | procedure NewIntegerUnsigned(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
13 | procedure NewFloat(AName: string; ASize: integer = 16; ADecimalSize: integer = 2; ADefault: string = 'NULL');
14 | procedure NewText(AName: string; ASize: integer = 65535; ADefault: string = 'NULL');
15 | procedure NewBoolean(AName: string; ADefault: boolean = false);
16 | procedure NewDateTime(AName: string; ADefault: string = 'NULL');
17 | procedure NewDate(AName: string; ADefault: string = 'NULL');
18 | procedure NewBlob(AName: string);
19 |
20 | procedure NewTimestamps;
21 |
22 | # Пример миграции
23 |
24 | unit migration_001_create_users_table;
25 |
26 | interface
27 |
28 | uses
29 | OlfeiSchema;
30 |
31 | implementation
32 |
33 | begin
34 | OlfeiTable := NewTable('users');
35 |
36 | OlfeiTable.NewString('name');
37 | OlfeiTable.NewString('password');
38 | OlfeiTable.NewString('login');
39 | OlfeiTable.NewTimestamps(); // Создает поля created_at и update_at
40 |
41 | end.
42 |
43 | # Пример сида
44 |
45 | unit migration_002_add_user_seed;
46 |
47 | interface
48 |
49 | uses
50 | OlfeiSchema;
51 |
52 | implementation
53 |
54 | begin
55 | OlfeiSeed := OlfeiTable.Seed;
56 |
57 | OlfeiSeed.Values['login'] := 'admin';
58 | OlfeiSeed.Values['password'] := '123';
59 | OlfeiSeed.Values['name'] := 'Администратор';
60 | end.
61 |
62 | # Пример модели
63 |
64 | unit UserModel;
65 |
66 | interface
67 |
68 | uses
69 | OlfeiSQL, OlfeiORM;
70 |
71 | type
72 | [TOlfeiTable('users')]
73 | TUserModel = class(TOlfeiORM)
74 | public
75 | [TOlfeiField('login')]
76 | property Login: String index 0 read GetString write SetString;
77 |
78 | [TOlfeiField('password')]
79 | property Password: String index 1 read GetString write SetString;
80 |
81 | [TOlfeiField('name')]
82 | property Name: String index 2 read GetString write SetString;
83 | end;
84 |
85 | implementation
86 |
87 | end.
88 |
89 | # Пример коллекции
90 |
91 | unit UserModel;
92 |
93 | interface
94 |
95 | uses
96 | OlfeiSQL, OlfeiCollection, UserModel;
97 |
98 | type
99 | TUsersModels = class(TOlfeiCollection)
100 | public
101 | constructor Create(FDB: TOlfeiDB); overload;
102 | end;
103 |
104 | implementation
105 |
106 | constructor TUsersModels.Create(FDB: TOlfeiDB);
107 | begin
108 | inherited Create(FDB, TUserModel);
109 | end;
110 |
111 | end.
112 |
113 | # Пример модели со связанной коллекцией
114 |
115 | [TOlfeiTable('users')]
116 | TUserModel = class(TOlfeiORM)
117 | private
118 | function GetOlfeiImages(index: integer): TOlfeiCollection;
119 | function GetOlfeiFriends(index: integer): TOlfeiCollection;
120 | public
121 | [TOlfeiField('login')]
122 | property Login: String index 0 read GetString write SetString;
123 |
124 | [TOlfeiField('password')]
125 | property Password: String index 1 read GetString write SetString;
126 |
127 | [TOlfeiField('name')]
128 | property Name: String index 2 read GetString write SetString;
129 |
130 | [TOlfeiCollectionField('id', 'user_id')]
131 | property Images: TOlfeiCollection index 0 read GetOlfeiImages;
132 |
133 | [TOlfeiPivotField('user_friend', 'user_id', 'friend_id')]
134 | property Friends: TOlfeiCollection index 1 read GetOlfeiFriends;
135 | end;
136 |
137 | // Методы привязки
138 |
139 | function TUserModel.GetOlfeiImages(index: Integer): TOlfeiCollection;
140 | begin
141 | Result := TOlfeiCollection(Self.GetForeignCollection(index, TOlfeiImage));
142 | end;
143 |
144 | function TUserModel.GetOlfeiFriends(index: Integer): TOlfeiCollection;
145 | begin
146 | Result := TOlfeiCollection(Self.GetPivotCollection(index, TUserModel));
147 | end;
148 |
149 | # Работа с моделями и коллекциями
150 |
151 | DB := InitDB; // Пример можно найти в Demo
152 | Users := TUsersModels.Create(DB);
153 |
154 | User := Users.Where('login', Login).Where('password', Pass).First;
155 | Result := User.Exists;
156 |
157 | User.Images; // Коллекция связанных изображений
158 | for Image in User.Images do
159 | ShowMessage(Image.Path);
160 |
161 | Users.Free; // Очищаем коллекцию, все связанные модели очистит сборщик мусора
162 | DB.Free;
163 |
164 | # Обход данных
165 |
166 | Users := TUsersModels.Create(DB);
167 | for User in Users.All do
168 | ShowMessage(User.Name);
169 |
170 | # Удаление записи
171 |
172 | User.Delete;
173 |
174 | # Очистка таблицы
175 |
176 | Users.Truncate;
177 |
178 | # Методы для коллекций
179 |
180 | .Where('field', 'value')
181 | .Where('field', '=', 'value') // Тажке можно любое условие >, >=, <, <= и тд
182 | .Where('field, 'IN', DB.Raw('(1, 2, 3)'))
183 | .OrWhere('field', 'value')
184 | .OrWhere('field', '=', 'value') // Тажке можно любое условие >, >=, <, <= и тд
185 | .OrWhere('field, 'IN', DB.Raw('(1, 2, 3)'))
186 |
187 | .OrderBy('field', 'ASC') // Можно также указать как DESC
188 |
189 | .StartGroup
190 | .StartAndGroup
191 | .StartOrGroup
192 | .EndGroup
193 |
194 | .Join('table', 'remote_key', 'local_key')
195 | .WhereFor('table', 'field', '=', 'value') // Тажке можно любое условие >, >=, <, <= и тд
196 | .OrWhereFor('table', 'field', '=', 'value') // Тажке можно любое условие >, >=, <, <= и тд
197 | .OrderByFor('table', 'field', 'ASC') // Можно также указать как DESC
198 |
199 | .Limit('offset', 'limit')
200 | .Count
201 | .Sum('field')
202 | .All
203 | .First
204 |
205 | Продолжение следует...
206 |
207 |
208 |
209 |
210 |
211 |
212 |
--------------------------------------------------------------------------------
/Drivers/OlfeiDriverMySQL.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiDriverMySQL;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, FireDAC.Comp.Client, System.SysUtils, System.Classes, OlfeiSchema,
7 | OlfeiSQLDriver;
8 |
9 | type
10 | TOlfeiDriverMySQL = class(TOlfeiSQLDriver)
11 | procedure Init(Parameters: TStringList); override;
12 | function Convert(Parameters: TStringList): TStringList; override;
13 |
14 | function CheckTable(TableName: string): Boolean; override;
15 | procedure NewTable(OlfeiTable: TObject); override;
16 | procedure UpdateTable(OlfeiTable: TObject); override;
17 | procedure DropTable(OlfeiTable: TObject); override;
18 | function FieldTypeToSQL(AType: Word; ASize, ADecimalSize: integer): string; override;
19 | function RandomOrder: string; override;
20 |
21 | procedure ConfirmUpdate(OlfeiTable: TObject);
22 | end;
23 |
24 | implementation
25 |
26 | function TOlfeiDriverMySQL.Convert(Parameters: TStringList): TStringList;
27 | begin
28 | Result := TStringList.Create;
29 |
30 | Result.Values['DriverID'] := 'MySQL';
31 | Result.Values['Server'] := Parameters.Values['host'];
32 | Result.Values['Port'] := Parameters.Values['port'];
33 | Result.Values['CharacterSet'] := 'utf8';
34 | Result.Values['Database'] := Parameters.Values['database'];
35 | Result.Values['User_Name'] := Parameters.Values['user'];
36 | Result.Values['Password'] := Parameters.Values['password'];
37 | end;
38 |
39 | procedure TOlfeiDriverMySQL.Init(Parameters: TStringList);
40 | begin
41 | OlfeiDB.Quote := '`';
42 |
43 | if not OlfeiDB.IsPool then
44 | begin
45 | OlfeiDB.SQLConnection.DriverName := 'MySQL';
46 | OlfeiDB.SQLConnection.Params.Values['DriverID'] := 'MySQL';
47 | OlfeiDB.SQLConnection.Params.Values['Server'] := Parameters.Values['host'];
48 | OlfeiDB.SQLConnection.Params.Values['Port'] := Parameters.Values['port'];
49 | OlfeiDB.SQLConnection.Params.Values['CharacterSet'] := 'utf8';
50 | OlfeiDB.SQLConnection.Params.Values['Database'] := Parameters.Values['database'];
51 | OlfeiDB.SQLConnection.Params.Values['User_Name'] := Parameters.Values['user'];
52 | OlfeiDB.SQLConnection.Params.Values['Password'] := Parameters.Values['password'];
53 | end;
54 | end;
55 |
56 | function TOlfeiDriverMySQL.FieldTypeToSQL(AType: Word; ASize, ADecimalSize: integer): string;
57 | begin
58 | if AType = TOlfeiFieldTypeString then
59 | Result := ' VARCHAR(' + ASize.ToString() + ')';
60 |
61 | if AType = TOlfeiFieldTypeInteger then
62 | Result := ' INT(' + ASize.ToString() + ')';
63 |
64 | if AType = TOlfeiFieldTypeIntegerUnsigned then
65 | Result := ' INT(' + ASize.ToString() + ') UNSIGNED';
66 |
67 | if AType = TOlfeiFieldTypeFloat then
68 | Result := ' DECIMAL(' + ASize.ToString() + ',' + ADecimalSize.ToString + ')';
69 |
70 | if AType = TOlfeiFieldTypeText then
71 | Result := ' TEXT(' + ASize.ToString() + ')';
72 |
73 | if AType = TOlfeiFieldTypeBoolean then
74 | Result := ' BOOL';
75 |
76 | if AType = TOlfeiFieldTypeDateTime then
77 | Result := ' DATETIME';
78 |
79 | if AType = TOlfeiFieldTypeDate then
80 | Result := ' DATE';
81 |
82 | if AType = TOlfeiFieldTypeBlob then
83 | Result := ' LONGBLOB';
84 | end;
85 |
86 | function TOlfeiDriverMySQL.CheckTable(TableName: string): Boolean;
87 | var
88 | DS: TFDMemTable;
89 | begin
90 | DS := OlfeiDB.GetSQL('SHOW TABLES LIKE "' + TableName + '"');
91 | Result := not DS.Eof;
92 | DS.Free;
93 | end;
94 |
95 | procedure TOlfeiDriverMySQL.NewTable(OlfeiTable: TObject);
96 | var
97 | Table: TOlfeiTableSchema;
98 | SQL: string;
99 | i: integer;
100 | begin
101 | Table := (OlfeiTable as TOlfeiTableSchema);
102 |
103 | if not Table.Pivot then
104 | OlfeiDB.RunSQL('CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'id' + OlfeiDB.Quote + ' INT UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (' + OlfeiDB.Quote + 'id' + OlfeiDB.Quote + '))')
105 | else
106 | begin
107 | SQL := '';
108 | for i := 0 to Length(Table.NewFields) - 1 do
109 | SQL := SQL + OlfeiDB.Quote + Table.NewFields[i].FName + OlfeiDB.Quote + FieldTypeToSQL(Table.NewFields[i].FType, Table.NewFields[i].Size, Table.NewFields[i].DecimalSize) + ' ' + PrepareDefault(Table.NewFields[i].Default) + ',';
110 |
111 | if Length(SQL) > 0 then
112 | SetLength(SQL, Length(SQL) - 1);
113 |
114 | SQL := 'CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + SQL + ')';
115 | OlfeiDB.RunSQL(SQL);
116 | end;
117 |
118 | ConfirmUpdate(OlfeiTable);
119 | end;
120 |
121 | procedure TOlfeiDriverMySQL.UpdateTable(OlfeiTable: TObject);
122 | begin
123 | ConfirmUpdate(OlfeiTable);
124 | end;
125 |
126 | procedure TOlfeiDriverMySQL.DropTable(OlfeiTable: TObject);
127 | begin
128 | OlfeiDB.RunSQL('DROP TABLE ' + OlfeiDB.Quote + (OlfeiTable as TOlfeiTableSchema).Table + OlfeiDB.Quote);
129 |
130 | ConfirmUpdate(OlfeiTable);
131 | end;
132 |
133 | procedure TOlfeiDriverMySQL.ConfirmUpdate(OlfeiTable: TObject);
134 | var
135 | Table: TOlfeiTableSchema;
136 | i, j: integer;
137 | SQL, QueryFields, QueryValues: string;
138 | begin
139 | Table := (OlfeiTable as TOlfeiTableSchema);
140 |
141 | if (not Table.Pivot) or (not Table.New) then
142 | for i := 0 to Length(Table.NewFields) - 1 do
143 | begin
144 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD COLUMN ' + OlfeiDB.Quote + Table.NewFields[i].FName + OlfeiDB.Quote;
145 |
146 | SQL := SQL + FieldTypeToSQL(Table.NewFields[i].FType, Table.NewFields[i].Size, Table.NewFields[i].DecimalSize);
147 | SQL := SQL + ' ' + PrepareDefault(Table.NewFields[i].Default);
148 |
149 | OlfeiDB.RunSQL(SQL);
150 | end;
151 |
152 | for i := 0 to Length(Table.UpdateFields) - 1 do
153 | begin
154 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' MODIFY ' + OlfeiDB.Quote + Table.UpdateFields[i].FName + OlfeiDB.Quote;
155 |
156 | SQL := SQL + FieldTypeToSQL(Table.UpdateFields[i].FType, Table.UpdateFields[i].Size, Table.UpdateFields[i].DecimalSize);
157 | SQL := SQL + ' ' + PrepareDefault(Table.UpdateFields[i].Default);
158 |
159 | OlfeiDB.RunSQL(SQL);
160 | end;
161 |
162 | for i := 0 to Length(Table.DropFields) - 1 do
163 | begin
164 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' DROP ' + OlfeiDB.Quote + Table.DropFields[i].FName + OlfeiDB.Quote;
165 |
166 | OlfeiDB.RunSQL(SQL);
167 | end;
168 |
169 | for i := 0 to Length(Table.Indexes) - 1 do
170 | OlfeiDB.RunSQL('CREATE INDEX ' + OlfeiDB.Quote + Table.Table + '_' + Table.Indexes[i].FName + '_index' + OlfeiDB.Quote + ' ON ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + Table.Indexes[i].FName + OlfeiDB.Quote + ')');
171 |
172 | for i := 0 to Length(Table.DropIndexes) - 1 do
173 | OlfeiDB.RunSQL('DROP INDEX ' + OlfeiDB.Quote + Table.Table + '_' + Table.DropIndexes[i].FName + '_index' + OlfeiDB.Quote + ' ON ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote);
174 |
175 | for i := 0 to Length(Table.Foreigns) - 1 do
176 | OlfeiDB.RunSQL('ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD CONSTRAINT ' + OlfeiDB.Quote + Table.Table + '_' + Table.Foreigns[i].FLocalKey + '_foreign' + OlfeiDB.Quote + ' FOREIGN KEY (' + OlfeiDB.Quote + Table.Foreigns[i].FLocalKey + OlfeiDB.Quote + ') REFERENCES ' + OlfeiDB.Quote + Table.Foreigns[i].FTable + OlfeiDB.Quote + '(' + OlfeiDB.Quote + Table.Foreigns[i].FRemoteKey + OlfeiDB.Quote + ') ON DELETE ' + Table.Foreigns[i].FOnDelete);
177 |
178 | for i := 0 to Length(Table.DropForeigns) - 1 do
179 | OlfeiDB.RunSQL('ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' DROP FOREIGN KEY ' + OlfeiDB.Quote + Table.Table + '_' + Table.DropForeigns[i].FName + '_foreign' + OlfeiDB.Quote);
180 |
181 | for i := 0 to Length(Table.Seeds) - 1 do
182 | begin
183 | QueryFields := '';
184 | QueryValues := '';
185 |
186 | for j := 0 to Table.Seeds[i].Count - 1 do
187 | begin
188 | QueryFields := QueryFields + OlfeiDB.Quote + Table.Seeds[i].Names[j] + OlfeiDB.Quote + ',';
189 | QueryValues := QueryValues + '"' + Table.Seeds[i].ValueFromIndex[j] + '"' + ',';
190 | end;
191 |
192 | SetLength(QueryFields, Length(QueryFields) - 1);
193 | SetLength(QueryValues, Length(QueryValues) - 1);
194 |
195 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + '(' + QueryFields + ') VALUES (' + QueryValues + ')');
196 | end;
197 |
198 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + 'migrations' + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'name' + OlfeiDB.Quote + ') VALUES ("' + Table.Migration + '")');
199 | end;
200 |
201 | function TOlfeiDriverMySQL.RandomOrder: string;
202 | begin
203 | Result := 'ORDER BY rand()';
204 | end;
205 |
206 | end.
207 |
208 |
--------------------------------------------------------------------------------
/Demo/ORMDemo.deployproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 12
5 |
6 |
7 | d2ec05
8 |
9 |
10 | iPhone5
11 |
12 |
13 |
14 |
15 |
16 |
17 | ORMDemo\
18 | ORMDemo.exe
19 | ProjectOutput
20 | 0
21 |
22 |
23 | True
24 | True
25 |
26 |
27 |
28 |
29 | ORMDemo.app\Contents\MacOS\
30 | libcgsqlite3.dylib
31 | DependencyModule
32 | 1
33 |
34 |
35 | True
36 |
37 |
38 | ORMDemo.app\Contents\MacOS\
39 | libcgunwind.1.0.dylib
40 | DependencyModule
41 | 1
42 |
43 |
44 | True
45 |
46 |
47 |
48 |
49 | ORMDemo\library\lib\mips\
50 | libORMDemo.so
51 | AndroidLibnativeMipsFile
52 | 1
53 |
54 |
55 | True
56 |
57 |
58 | ORMDemo\res\drawable-ldpi\
59 | ic_launcher.png
60 | Android_LauncherIcon36
61 | 1
62 |
63 |
64 | True
65 |
66 |
67 | ORMDemo\
68 | AndroidManifest.xml
69 | ProjectAndroidManifest
70 | 1
71 |
72 |
73 | True
74 |
75 |
76 | ORMDemo\library\lib\armeabi\
77 | libORMDemo.so
78 | AndroidLibnativeArmeabiFile
79 | 1
80 |
81 |
82 | True
83 |
84 |
85 | ORMDemo\res\drawable-hdpi\
86 | ic_launcher.png
87 | Android_LauncherIcon72
88 | 1
89 |
90 |
91 | True
92 |
93 |
94 | ORMDemo\res\drawable-xxhdpi\
95 | ic_launcher.png
96 | Android_LauncherIcon144
97 | 1
98 |
99 |
100 | True
101 |
102 |
103 | ORMDemo\res\drawable-normal\
104 | splash_image.png
105 | Android_SplashImage470
106 | 1
107 |
108 |
109 | True
110 |
111 |
112 | ORMDemo\res\drawable-small\
113 | splash_image.png
114 | Android_SplashImage426
115 | 1
116 |
117 |
118 | True
119 |
120 |
121 | ORMDemo\res\drawable-large\
122 | splash_image.png
123 | Android_SplashImage640
124 | 1
125 |
126 |
127 | True
128 |
129 |
130 | ORMDemo\res\drawable-xlarge\
131 | splash_image.png
132 | Android_SplashImage960
133 | 1
134 |
135 |
136 | True
137 |
138 |
139 | ORMDemo\res\drawable-xhdpi\
140 | ic_launcher.png
141 | Android_LauncherIcon96
142 | 1
143 |
144 |
145 | True
146 |
147 |
148 | ORMDemo\res\drawable-mdpi\
149 | ic_launcher.png
150 | Android_LauncherIcon48
151 | 1
152 |
153 |
154 | True
155 |
156 |
157 | ORMDemo\library\lib\armeabi-v7a\
158 | libORMDemo.so
159 | ProjectOutput
160 | 1
161 |
162 |
163 | True
164 | True
165 |
166 |
167 | ORMDemo\library\lib\armeabi-v7a\
168 | gdbserver
169 | AndroidGDBServer
170 | 1
171 |
172 |
173 | True
174 |
175 |
176 | ORMDemo\classes\
177 | classes.dex
178 | AndroidClassesDexFile
179 | 1
180 |
181 |
182 | True
183 |
184 |
185 | ORMDemo\res\drawable\
186 | splash_image_def.xml
187 | AndroidSplashImageDef
188 | 1
189 |
190 |
191 | True
192 |
193 |
194 | ORMDemo\res\values\
195 | styles.xml
196 | AndroidSplashStyles
197 | 1
198 |
199 |
200 | True
201 |
202 |
203 |
204 |
205 | ORMDemo.app\
206 | libcgunwind.1.0.dylib
207 | DependencyModule
208 | 1
209 |
210 |
211 | True
212 |
213 |
214 | ORMDemo.app\
215 | libPCRE.dylib
216 | DependencyModule
217 | 1
218 |
219 |
220 | True
221 |
222 |
223 |
224 |
--------------------------------------------------------------------------------
/Core/OlfeiSQL.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiSQL;
2 |
3 | interface
4 |
5 | uses Classes, Sysutils,
6 | SyncObjs, FireDAC.Stan.Intf,
7 | FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf,
8 | FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys,
9 | FireDAC.Comp.Client, FireDAC.Phys.SQLite, FireDAC.DApt, Data.DB,
10 | System.IniFiles, System.Threading, System.IOUtils, JSON
11 |
12 | {$IFDEF VER340}
13 | , FireDAC.Phys.SQLiteWrapper.Stat
14 | {$ENDIF}
15 |
16 | {$IFDEF MSWINDOWS}
17 | , FireDAC.Phys.MySQL
18 | {$ENDIF};
19 |
20 | type
21 | TOlfeiStringItem = record
22 | Name, ItemType: string;
23 | end;
24 |
25 | TOlfeiStrings = array of TOlfeiStringItem;
26 | TOlfeiClasses = array of TClass;
27 |
28 | TOlfeiResultArray = array of T;
29 |
30 | TOlfeiDB = class
31 | private
32 | CriticalSection: TCriticalSection;
33 | flLoaded, flAutoMigrate: Boolean;
34 | DriverConnect: TObject;
35 | IsDebug: Boolean;
36 | DebugFileName: string;
37 |
38 | {$IFDEF MSWINDOWS}
39 | FDPhysMySQLDriverLink: TFDPhysMySQLDriverLink;
40 | {$ENDIF}
41 |
42 | function IsRaw(val: string): boolean;
43 | function ClearRaw(val: string): string;
44 | procedure DebugSQL(Query: string);
45 | public
46 | Parameters: TStringList;
47 | SQLConnection: TFDConnection;
48 | Quote: string;
49 | Driver: string;
50 | IsPool: boolean;
51 |
52 | constructor Create(AutoMigrate: boolean = True); overload;
53 | constructor Create(ConnectionName: string; AutoMigrate: Boolean = True); overload;
54 | destructor Destroy; override;
55 | function GetSQL(SQL: string): TFDMemTable;
56 | function GetOnce(SQL, ValueType: string): string;
57 | procedure RunSQL(SQL: string);
58 | procedure BeginTransaction;
59 | procedure EndTransaction;
60 | procedure RollbackTransaction;
61 | procedure Connect;
62 | procedure Migrate;
63 | function RandomOrder: string;
64 |
65 | function Quoted(val: string): string;
66 | function FullQuoted(val: string): string;
67 | function Raw(val: string): string;
68 | procedure SetDebugFile(FileName: string);
69 | procedure Backup(FileName: string; DatabaseName: string = '');
70 | end;
71 |
72 | implementation
73 |
74 | uses
75 | {$I 'schema.inc'} OlfeiDriverSQLite, OlfeiDriverMySQL, OlfeiSchema, OlfeiSQLDriver;
76 |
77 | function TOlfeiDB.RandomOrder: string;
78 | begin
79 | Result := (DriverConnect as TOlfeiSQLDriver).RandomOrder;
80 | end;
81 |
82 | destructor TOlfeiDB.Destroy;
83 | begin
84 | DriverConnect.Free;
85 |
86 | SQLConnection.Connected := false;
87 | SQLConnection.Close;
88 | SQLConnection.Free;
89 |
90 | CriticalSection.Free;
91 |
92 | Parameters.Free;
93 |
94 | {$IFDEF MSWINDOWS}
95 | FDPhysMySQLDriverLink.Free;
96 | {$ENDIF}
97 |
98 | inherited;
99 | end;
100 |
101 | function TOlfeiDB.Quoted(val: string): string;
102 | begin
103 | Result := StringReplace(trim(val), #39, #39#39, [rfReplaceAll, rfIgnoreCase]);
104 | Result := StringReplace(trim(Result), #34, #34#34, [rfReplaceAll, rfIgnoreCase]);
105 | Result := StringReplace(trim(Result), '!', '', [rfReplaceAll, rfIgnoreCase]);
106 | Result := StringReplace(trim(Result), '\', '\\', [rfReplaceAll, rfIgnoreCase]);
107 |
108 | if Result = ' ' then
109 | Result := '';
110 | end;
111 |
112 | procedure TOlfeiDB.DebugSQL(Query: string);
113 | begin
114 | if IsDebug then
115 | begin
116 | TMonitor.Enter(Self);
117 |
118 | TFile.AppendAllText(DebugFileName, Query + #13, TEncoding.UTF8);
119 |
120 | TMonitor.Exit(Self);
121 | end;
122 | end;
123 |
124 | function TOlfeiDB.FullQuoted(val: string): string;
125 | begin
126 | if Self.IsRaw(val) then
127 | Result := Self.ClearRaw(val)
128 | else
129 | Result := '"' + Self.Quoted(val) + '"';
130 | end;
131 |
132 | function TOlfeiDB.Raw(val: string): string;
133 | begin
134 | Result := 'RAWDATA={' + val + '}';
135 | end;
136 |
137 | function TOlfeiDB.ClearRaw(val: string): string;
138 | begin
139 | Result := Copy(val, 10, Length(val) - 10);
140 | end;
141 |
142 | function TOlfeiDB.IsRaw(val: string): boolean;
143 | begin
144 | Result := Pos('RAWDATA', val) > 0;
145 | end;
146 |
147 | constructor TOlfeiDB.Create(ConnectionName: string; AutoMigrate: Boolean = true);
148 | begin
149 | IsPool := True;
150 |
151 | flLoaded := true;
152 | flAutoMigrate := AutoMigrate;
153 |
154 | SQLConnection := TFDConnection.Create(nil);
155 |
156 | SQLConnection.ConnectionDefName := ConnectionName;
157 |
158 | SQLConnection.FetchOptions.Mode := fmAll;
159 | SQLConnection.FetchOptions.RowsetSize := 300;
160 | SQLConnection.FetchOptions.AutoClose := True;
161 | SQLConnection.TxOptions.AutoCommit := True;
162 |
163 | SQLConnection.ResourceOptions.SilentMode := True;
164 |
165 | CriticalSection := TCriticalSection.Create;
166 |
167 | Parameters := TStringList.Create;
168 | end;
169 |
170 | constructor TOlfeiDB.Create(AutoMigrate: boolean = True);
171 | begin
172 | IsPool := false;
173 |
174 | flLoaded := true;
175 | flAutoMigrate := AutoMigrate;
176 | IsDebug := false;
177 |
178 | SQLConnection := TFDConnection.Create(nil);
179 |
180 | SQLConnection.FetchOptions.Mode := fmAll;
181 | SQLConnection.FetchOptions.RowsetSize := 300;
182 | SQLConnection.FetchOptions.AutoClose := True;
183 | SQLConnection.TxOptions.AutoCommit := True;
184 | SQLConnection.ResourceOptions.SilentMode := True;
185 |
186 | CriticalSection := TCriticalSection.Create;
187 |
188 | {$IFDEF MSWINDOWS}
189 | FDPhysMySQLDriverLink := TFDPhysMySQLDriverLink.Create(nil);
190 | {$ENDIF}
191 |
192 | Parameters := TStringList.Create;
193 | end;
194 |
195 | procedure TOlfeiDB.Connect;
196 | begin
197 | if IsPool then
198 | begin
199 | if Pos(AnsiUpperCase('MySQL'), AnsiUpperCase(SQLConnection.ConnectionDefName)) > 0 then
200 | Driver := 'mysql';
201 |
202 | if Pos(AnsiUpperCase('SQLite'), AnsiUpperCase(SQLConnection.ConnectionDefName)) > 0 then
203 | Driver := 'sqlite';
204 | end
205 | else
206 | Driver := Parameters.Values['driver'];
207 |
208 | if Driver = '' then
209 | raise Exception.Create('ORM support only SQLite and MySQL (MariaDB)');
210 |
211 | if Driver = 'sqlite' then
212 | begin
213 | DriverConnect := TOlfeiDriverSQLite.Create(Self);
214 | (DriverConnect as TOlfeiDriverSQLite).Init(Parameters);
215 |
216 | SQLConnection.Connected := true;
217 |
218 | if flAutoMigrate then
219 | Self.Migrate;
220 | end;
221 |
222 | if Driver = 'mysql' then
223 | begin
224 | {$IFDEF MSWINDOWS}
225 | DriverConnect := TOlfeiDriverMySQL.Create(Self);
226 | (DriverConnect as TOlfeiDriverMySQL).Init(Parameters);
227 |
228 | SQLConnection.Connected := true;
229 |
230 | if flAutoMigrate then
231 | Self.Migrate;
232 | {$ELSE}
233 | raise Exception.Create('Mobile platforms support only SQLite');
234 | {$ENDIF}
235 | end;
236 | end;
237 |
238 | procedure TOlfeiDB.SetDebugFile(FileName: string);
239 | begin
240 | if FileName <> '' then
241 | begin
242 | IsDebug := True;
243 | DebugFileName := FileName;
244 | end
245 | else
246 | IsDebug := false;
247 | end;
248 |
249 | procedure TOlfeiDB.Migrate;
250 | var
251 | OlfeiSchema: TOlfeiSchema;
252 | begin
253 | OlfeiSchema := TOlfeiSchema.Create((DriverConnect as TOlfeiSQLDriver));
254 | OlfeiSchema.Run;
255 | OlfeiSchema.Free;
256 | end;
257 |
258 | function TOlfeiDB.GetSQL(SQL: string): TFDMemTable;
259 | var
260 | Query: TFDQuery;
261 | begin
262 | Self.DebugSQL(SQL);
263 |
264 | if SQLConnection.Connected then
265 | begin
266 | CriticalSection.Enter;
267 |
268 | Query := TFDQuery.Create(SQLConnection);
269 | Query.Connection := SQLConnection;
270 |
271 | Query.SQL.Clear;
272 | Query.SQL.Add(SQL);
273 | Query.Open;
274 |
275 | Query.FetchAll;
276 |
277 | Result := TFDMemTable.Create(nil);
278 | Result.Data := Query.Data;
279 | Result.First;
280 |
281 | Query.Free;
282 |
283 | CriticalSection.Leave;
284 | end
285 | else
286 | Result := TFDMemTable.Create(nil);
287 | end;
288 |
289 | procedure TOlfeiDB.RunSQL(SQL: string);
290 | begin
291 | Self.DebugSQL(SQL);
292 |
293 | if SQLConnection.Connected then
294 | begin
295 | CriticalSection.Enter;
296 |
297 | SQLConnection.ExecSQL(SQL);
298 |
299 | CriticalSection.Leave;
300 | end;
301 | end;
302 |
303 | function TOlfeiDB.GetOnce(SQL, ValueType: string): string;
304 | var
305 | DS: TFDMemTable;
306 | begin
307 | Self.DebugSQL(SQL);
308 |
309 | if SQLConnection.Connected then
310 | begin
311 | DS := GetSQL(SQL);
312 |
313 | CriticalSection.Enter;
314 |
315 | if not DS.Eof then
316 | Result := DS.Fields[0].AsString
317 | else
318 | if ValueType = 'string' then
319 | Result := ''
320 | else
321 | Result := '0';
322 |
323 | DS.Free;
324 |
325 | if (ValueType = 'integer') and (Result = '') then
326 | Result := '0';
327 |
328 | if (ValueType = 'integer') and (Result[Length(Result)] = '0') and (Result[Length(Result) - 1] = '.') then
329 | Result := StringReplace(Result, '.0', '', []);
330 |
331 | if (ValueType = 'integer') and (Result[Length(Result)] = '0') and (Result[Length(Result) - 1] = ',') then
332 | Result := StringReplace(Result, ',0', '', []);
333 |
334 | if ValueType = 'integer' then
335 | Result := StringReplace(Result, '.', ',', [rfReplaceAll]);
336 |
337 | if Result = 'False' then
338 | Result := '0';
339 |
340 | if Result = 'True' then
341 | Result := '1';
342 |
343 | CriticalSection.Leave;
344 | end;
345 | end;
346 |
347 | procedure TOlfeiDB.BeginTransaction;
348 | begin
349 | SQLConnection.TxOptions.AutoCommit := False;
350 | SQLConnection.TxOptions.AutoStart := False;
351 | SQLConnection.TxOptions.AutoStop := False;
352 |
353 | SQLConnection.StartTransaction;
354 | end;
355 |
356 | procedure TOlfeiDB.EndTransaction;
357 | begin
358 | SQLConnection.Commit;
359 |
360 | SQLConnection.TxOptions.AutoCommit := True;
361 | SQLConnection.TxOptions.AutoStart := True;
362 | SQLConnection.TxOptions.AutoStop := True;
363 | end;
364 |
365 | procedure TOlfeiDB.RollbackTransaction;
366 | begin
367 | SQLConnection.Rollback;
368 |
369 | SQLConnection.TxOptions.AutoCommit := True;
370 | SQLConnection.TxOptions.AutoStart := True;
371 | SQLConnection.TxOptions.AutoStop := True;
372 | end;
373 |
374 | procedure TOlfeiDB.Backup(FileName: string; DatabaseName: string = '');
375 | var
376 | DSMain, DSFields, DSSchema: TFDMemTable;
377 | TableName, Schema, InsertData: string;
378 | i: integer;
379 | SL: TStringList;
380 | begin
381 | DSMain := Self.GetSQL('SHOW TABLES');
382 | SL := TStringList.Create;
383 |
384 | while not DSMain.Eof do
385 | begin
386 | if DatabaseName = '' then
387 | TableName := DSMain.FieldByName('Tables_in_' + Parameters.Values['database']).AsString
388 | else
389 | TableName := DSMain.FieldByName('Tables_in_' + DatabaseName).AsString;
390 |
391 | DSSchema := Self.GetSQL('SHOW CREATE TABLE ' + TableName);
392 | Schema := DSSchema.Fields[1].AsString + ';' + #10#13;
393 |
394 | SL.Add(Schema);
395 |
396 | DSSchema.Close;
397 | DSSchema.Free;
398 |
399 | DSFields := Self.GetSQL('SELECT * FROM ' + TableName);
400 | InsertData := '';
401 |
402 | while not DSFields.Eof do
403 | begin
404 | InsertData := 'INSERT INTO ' + TableName + ' VALUES (';
405 |
406 | for i := 0 to DSFields.FieldCount - 1 do
407 | InsertData := InsertData + '"' + DSFields.Fields[i].AsString + '",';
408 |
409 | SetLength(InsertData, Length(InsertData) - 1);
410 | InsertData := InsertData + ');';
411 |
412 | SL.Add(InsertData);
413 |
414 | DSFields.Next;
415 | end;
416 |
417 | SL.Add(#10#13);
418 |
419 | DSFields.Close;
420 | DSFields.Free;
421 |
422 | DSMain.Next;
423 | end;
424 |
425 | SL.SaveToFile(FileName);
426 |
427 | SL.Free;
428 |
429 | DSMain.Close;
430 | DSMain.Free;
431 | end;
432 |
433 | end.
434 |
435 |
436 |
437 |
438 |
439 |
--------------------------------------------------------------------------------
/Demo/ORMDemo.dproj.local:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1899.12.30 00:00:00.000.998,F:\My\delphi-orm\HRCQuery.pas=
5 | 1899.12.30 00:00:00.000.030,F:\My\delphi-orm\HRCQuery.pas=F:\My\delphi-orm\Unit1.pas
6 | 1899.12.30 00:00:00.000.989,C:\Users\olfei\Projects\HoReCa\Work\orm\HRCUser.pas=C:\Users\olfei\Projects\HoReCa\Work\orm\Unit1.pas
7 | 1899.12.30 00:00:00.000.138,=F:\My\delphi-orm\Demo\Collections\OlfeiImages.pas
8 | 1899.12.30 00:00:00.000.640,F:\My\delphi-orm\OlfeiSchema.pas=F:\My\delphi-orm\HRCSchema.pas
9 | 1899.12.30 00:00:00.000.212,F:\My\delphi-orm\OlfeiCollection.pas=F:\My\delphi-orm\HRCCollection.pas
10 | 1899.12.30 00:00:00.000.761,C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemo.pas=C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemoMain.pas
11 | 1899.12.30 00:00:00.000.742,C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\SchemaDemo.pas=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\HRCSchema.pas
12 | 1899.12.30 00:00:00.000.236,C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\SchemaDemo.pas=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas
13 | 1899.12.30 00:00:00.000.407,=F:\My\delphi-orm\Migrations\migration_001_create_users_table.pas
14 | 1899.12.30 00:00:00.000.137,=F:\My\delphi-orm\Migrations\migration_001_create_users_table.pas
15 | 1899.12.30 00:00:00.000.812,F:\My\delphi-orm\Migrations\migration_001_create_users_table.pas=
16 | 1899.12.30 00:00:00.000.443,=F:\My\delphi-orm\Demo\Models\OlfeiImage.pas
17 | 1899.12.30 00:00:00.000.174,=F:\My\delphi-orm\Migrations\S002_create_test_table.pas
18 | 1899.12.30 00:00:00.000.170,F:\My\delphi-orm\OlfeiSQL.pas=F:\My\delphi-orm\HRCSQL.pas
19 | 1899.12.30 00:00:00.000.707,=F:\My\delphi-orm\Schema\Migrations\migration_003_add_seeds_to_test_table.pas
20 | 1899.12.30 00:00:00.000.039,C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Unit1.pas=C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemo.pas
21 | 1899.12.30 00:00:00.000.938,F:\My\delphi-orm\Demo\Collections\Additional\OlfeiFriends.pas=
22 | 1899.12.30 00:00:00.000.261,=C:\Users\olfei\Projects\HoReCa\Work\orm\HRCSQL.pas
23 | 1899.12.30 00:00:00.000.700,=F:\My\delphi-orm\Demo\Collections\OlfeiUsers.pas
24 | 1899.12.30 00:00:00.000.039,C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Unit1.fmx=C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemo.fmx
25 | 1899.12.30 00:00:00.000.816,=F:\My\delphi-orm\Models\OlfeiTest.pas
26 | 1899.12.30 00:00:00.000.790,=F:\My\delphi-orm\Demo\Models\OlfeiTest.pas
27 | 1899.12.30 00:00:00.000.047,=F:\My\delphi-orm\Demo\Migrations\migration_002_create_test_table.pas
28 | 1899.12.30 00:00:00.000.411,=F:\My\delphi-orm\Migrations\migration_002_create_test_table.pas
29 | 1899.12.30 00:00:00.000.099,=F:\My\delphi-orm\Unit1.pas
30 | 1899.12.30 00:00:00.000.406,=F:\My\delphi-orm\Unit1.pas
31 | 1899.12.30 00:00:00.000.135,=F:\My\delphi-orm\Unit1.pas
32 | 1899.12.30 00:00:00.000.207,F:\My\delphi-orm\Unit1.pas=F:\My\delphi-orm\OlfeiSchema.pas
33 | 1899.12.30 00:00:00.000.114,F:\My\delphi-orm\Unit1.pas=F:\My\delphi-orm\OlfeiUsers.pas
34 | 1899.12.30 00:00:00.000.193,=F:\My\delphi-orm\Unit1.pas
35 | 1899.12.30 00:00:00.000.720,F:\My\delphi-orm\Unit1.pas=F:\My\delphi-orm\OlfeiTest.pas
36 | 1899.12.30 00:00:00.000.604,F:\My\delphi-orm\Unit1.pas=F:\My\delphi-orm\Migrations\create_test_table.pas
37 | 1899.12.30 00:00:00.000.451,F:\My\delphi-orm\OlfeiSchemaHeader.pas=F:\My\delphi-orm\Unit1.pas
38 | 1899.12.30 00:00:00.000.342,=F:\My\delphi-orm\Unit1.pas
39 | 1899.12.30 00:00:00.000.713,=F:\My\delphi-orm\Unit1.pas
40 | 1899.12.30 00:00:00.000.996,=F:\My\delphi-orm\Unit1.pas
41 | 1899.12.30 00:00:00.000.998,F:\My\delphi-orm\OlfeiORM.pas=F:\My\delphi-orm\HRCORM.pas
42 | 1899.12.30 00:00:00.000.918,=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas
43 | 1899.12.30 00:00:00.000.278,=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas
44 | 1899.12.30 00:00:00.000.551,=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas
45 | 1899.12.30 00:00:00.000.253,=C:\Users\olfei\Projects\HoReCa\Work\orm\HRCORM.pas
46 | 1899.12.30 00:00:00.000.992,C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\HRCDriverSQLite.pas
47 | 1899.12.30 00:00:00.000.018,=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas
48 | 1899.12.30 00:00:00.000.477,F:\My\delphi-orm\HRCCollection.pas=F:\My\delphi-orm\Unit1.pas
49 | 1899.12.30 00:00:00.000.467,=F:\My\delphi-orm\Schema\OlfeiSchemaHeader.pas
50 | 1899.12.30 00:00:00.000.512,F:\My\delphi-orm\Schema\OlfeiSchemaHeader.pas=
51 | 1899.12.30 00:00:00.000.302,C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\HRCDriverMySQL.pas
52 | 1899.12.30 00:00:00.000.692,C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\Unit1.pas=C:\Users\olfei\Projects\HoReCa\Work\hrc-orm\HRCDriverFireBird.pas
53 | 1899.12.30 00:00:00.000.715,F:\My\delphi-orm\Demo\Migrations\migration_010_create_friends_table.pas=
54 | 1899.12.30 00:00:00.000.395,=C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Unit1.pas
55 | 1899.12.30 00:00:00.000.105,=F:\My\delphi-orm\Demo\Unit1.pas
56 | 1899.12.30 00:00:00.000.100,=F:\My\delphi-orm\Demo\Unit1.pas
57 | 1899.12.30 00:00:00.000.717,=F:\My\delphi-orm\Demo\Unit1.pas
58 | 1899.12.30 00:00:00.000.120,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_007_drop_index_on_users_table.pas
59 | 1899.12.30 00:00:00.000.797,=F:\My\delphi-orm\Demo\Unit1.pas
60 | 1899.12.30 00:00:00.000.240,=F:\My\delphi-orm\Demo\Unit1.pas
61 | 1899.12.30 00:00:00.000.810,=F:\My\delphi-orm\Demo\Unit1.pas
62 | 1899.12.30 00:00:00.000.048,=F:\My\delphi-orm\Demo\Unit1.pas
63 | 1899.12.30 00:00:00.000.872,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Models\Additional\OlfeiFriend.pas
64 | 1899.12.30 00:00:00.000.336,=F:\My\delphi-orm\Demo\Unit1.pas
65 | 1899.12.30 00:00:00.000.006,=F:\My\delphi-orm\Demo\Unit1.pas
66 | 1899.12.30 00:00:00.000.759,=F:\My\delphi-orm\Demo\Unit1.pas
67 | 1899.12.30 00:00:00.000.412,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_008_drop_foreign_on_test_table.pas
68 | 1899.12.30 00:00:00.000.793,=F:\My\delphi-orm\Demo\Models\OlfeiUser.pas
69 | 1899.12.30 00:00:00.000.340,=F:\My\delphi-orm\Schema\Migrations\migration_001_create_users_table.pas
70 | 1899.12.30 00:00:00.000.818,=F:\My\delphi-orm\Models\OlfeiUser.pas
71 | 1899.12.30 00:00:00.000.936,=C:\Users\olfei\Projects\HoReCa\Work\orm\Unit1.pas
72 | 1899.12.30 00:00:00.000.821,F:\My\delphi-orm\Demo\Migrations\migration_006_create_images_table.pas=F:\My\delphi-orm\Demo\Unit1.pas
73 | 1899.12.30 00:00:00.000.045,=F:\My\delphi-orm\Demo\Migrations\migration_001_create_users_table.pas
74 | 1899.12.30 00:00:00.000.266,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Collections\Additional\OlfeiFriends.pas
75 | 1899.12.30 00:00:00.000.932,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_005_delete_birthday_from_users_table.pas
76 | 1899.12.30 00:00:00.000.338,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_010_create_friends_table.pas
77 | 1899.12.30 00:00:00.000.329,F:\My\delphi-orm\Drivers\IOlfeiSQLDriver.pas=F:\My\delphi-orm\Demo\Unit1.pas
78 | 1899.12.30 00:00:00.000.050,=F:\My\delphi-orm\Demo\Migrations\migration_003_add_seeds_to_test_table.pas
79 | 1899.12.30 00:00:00.000.116,F:\My\delphi-orm\Demo\Models\Additional\OlfeiFriend.pas=
80 | 1899.12.30 00:00:00.000.379,F:\My\delphi-orm\Core\OlfeiCollection.pas=
81 | 1899.12.30 00:00:00.000.218,=F:\My\delphi-orm\Core\OlfeiCollection.pas
82 | 1899.12.30 00:00:00.000.462,F:\My\delphi-orm\OlfeiUser.pas=F:\My\delphi-orm\HRCUser.pas
83 | 1899.12.30 00:00:00.000.186,=F:\My\delphi-orm\Core\OlfeiSQL.pas
84 | 1899.12.30 00:00:00.000.733,=F:\My\delphi-orm\Collections\OlfeiUsers.pas
85 | 1899.12.30 00:00:00.000.399,=F:\My\delphi-orm\Migrations\migration_003_add_seeds_to_test_table.pas
86 | 1899.12.30 00:00:00.000.358,F:\My\delphi-orm\Demo\Migrations\migration_011_create_pivot_user_friend_table.pas=F:\My\delphi-orm\Demo\Migrations\migration_010_create_pivot_user_friend_table.pas
87 | 1899.12.30 00:00:00.000.787,=F:\My\delphi-orm\Migrations\S001_create_users_table.pas
88 | 1899.12.30 00:00:00.000.923,=F:\My\delphi-orm\Migrations\create_users_table.pas
89 | 1899.12.30 00:00:00.000.488,F:\My\delphi-orm\OlfeiDriverMySQL.pas=F:\My\delphi-orm\HRCDriverMySQL.pas
90 | 1899.12.30 00:00:00.000.634,F:\My\delphi-orm\Core\OlfeiORM.pas=
91 | 1899.12.30 00:00:00.000.649,=F:\My\delphi-orm\Core\OlfeiORM.pas
92 | 1899.12.30 00:00:00.000.531,F:\My\delphi-orm\Core\OlfeiSQL.pas=
93 | 1899.12.30 00:00:00.000.066,=F:\My\delphi-orm\Demo\Unit1.pas
94 | 1899.12.30 00:00:00.000.876,C:\Users\olfei\Documents\Embarcadero\Studio\Projects\Project1.dproj=C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemo.dproj
95 | 1899.12.30 00:00:00.000.403,=F:\My\delphi-orm\Migrations\schema.inc
96 | 1899.12.30 00:00:00.000.350,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_009_add_avatar_to_users_table.pas
97 | 1899.12.30 00:00:00.000.887,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_004_update_price_in_users_table.pas
98 | 1899.12.30 00:00:00.000.057,F:\My\delphi-orm\Demo\Unit1.pas=F:\My\delphi-orm\Demo\Migrations\migration_011_create_pivot_user_friend_table.pas
99 | 1899.12.30 00:00:00.000.059,=F:\My\delphi-orm\Schema\schema.inc
100 | 1899.12.30 00:00:00.000.403,F:\My\delphi-orm\OlfeiDriverSQLite.pas=F:\My\delphi-orm\HRCDriverSQLite.pas
101 | 1899.12.30 00:00:00.000.761,C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemo.fmx=C:\Users\olfei\Projects\HoReCa\Work\orm\ORMDemoMain.fmx
102 | 1899.12.30 00:00:00.000.149,=F:\My\delphi-orm\Schema\Migrations\migration_002_create_test_table.pas
103 | 1899.12.30 00:00:00.000.586,F:\My\delphi-orm\Migrations\migartion_002_create_test_table.pas=
104 | 1899.12.30 00:00:00.000.150,=F:\My\delphi-orm\Migrations\migartion_002_create_test_table.pas
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/Drivers/OlfeiDriverSQLite.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiDriverSQLite;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, FireDAC.Comp.Client, System.SysUtils, System.Classes,
7 | System.IOUtils, OlfeiSQLDriver;
8 |
9 | type
10 | TOlfeiDriverSQLite = class(TOlfeiSQLDriver)
11 | procedure Init(Parameters: TStringList); override;
12 | function Convert(Parameters: TStringList): TStringList; override;
13 |
14 | function CheckTable(TableName: string): Boolean; override;
15 | procedure NewTable(OlfeiTable: TObject); override;
16 | procedure UpdateTable(OlfeiTable: TObject); override;
17 | procedure DropTable(OlfeiTable: TObject); override;
18 | function FieldTypeToSQL(AType: Word; ASize, ADecimalSize: integer): string; override;
19 | function RandomOrder: string; override;
20 |
21 | procedure ConfirmUpdate(OlfeiTable: TObject);
22 | end;
23 |
24 | implementation
25 |
26 | uses
27 | OlfeiSchema;
28 |
29 | function TOlfeiDriverSQLite.Convert(Parameters: TStringList): TStringList;
30 |
31 | function PreparePath(FilePath: string): string;
32 | begin
33 | {$IF DEFINED(iOS) or DEFINED(ANDROID)}
34 | Result := StringReplace(FilePath, '.\', TPath.GetDocumentsPath, []);
35 | Result := StringReplace(FilePath, './', TPath.GetDocumentsPath, []);
36 | {$ELSE}
37 | Result := StringReplace(FilePath, '.\', ExtractFilePath(ParamStr(0)), []);
38 | Result := StringReplace(FilePath, './', ExtractFilePath(ParamStr(0)), []);
39 | {$ENDIF}
40 | end;
41 |
42 | begin
43 | Result := TStringList.Create;
44 |
45 | Result.Values['DriverID'] := 'SQLite';
46 | Result.Values['Database'] := PreparePath(Parameters.Values['database']);
47 | end;
48 |
49 | function TOlfeiDriverSQLite.FieldTypeToSQL(AType: Word; ASize, ADecimalSize: integer): string;
50 | begin
51 | if AType = TOlfeiFieldTypeString then
52 | Result := ' VARCHAR(' + ASize.ToString() + ')';
53 |
54 | if AType = TOlfeiFieldTypeInteger then
55 | Result := ' INTEGER(' + ASize.ToString() + ')';
56 |
57 | if AType = TOlfeiFieldTypeIntegerUnsigned then
58 | Result := ' INTEGER(' + ASize.ToString() + ')';
59 |
60 | if AType = TOlfeiFieldTypeFloat then
61 | Result := ' REAL(' + ASize.ToString() + ',' + ADecimalSize.ToString() + ')';
62 |
63 | if AType = TOlfeiFieldTypeText then
64 | Result := ' TEXT(' + ASize.ToString() + ')';
65 |
66 | if AType = TOlfeiFieldTypeBoolean then
67 | Result := ' SMALLINT(1)';
68 |
69 | if AType = TOlfeiFieldTypeDateTime then
70 | Result := ' DATETIME';
71 |
72 | if AType = TOlfeiFieldTypeDate then
73 | Result := ' DATE';
74 |
75 | if AType = TOlfeiFieldTypeBlob then
76 | Result := ' BLOB';
77 | end;
78 |
79 | procedure TOlfeiDriverSQLite.ConfirmUpdate(OlfeiTable: TObject);
80 | var
81 | i, j: integer;
82 | Table: TOlfeiTableSchema;
83 | QueryFields, QueryValues: string;
84 | ForeignText, SQL: string;
85 | DS, DSInfo: TFDMemTable;
86 | begin
87 | Table := (OlfeiTable as TOlfeiTableSchema);
88 |
89 | if Length(Table.Foreigns) > 0 then
90 | begin
91 | ForeignText := '';
92 | for i := 0 to Length(Table.Foreigns) - 1 do
93 | ForeignText := ForeignText + 'FOREIGN KEY(' + OlfeiDB.Quote + Table.Foreigns[i].FLocalKey + OlfeiDB.Quote + ') REFERENCES ' + OlfeiDB.Quote + Table.Foreigns[i].FTable + OlfeiDB.Quote + '(' + OlfeiDB.Quote + Table.Foreigns[i].FRemoteKey + OlfeiDB.Quote + ') ON DELETE ' + Table.Foreigns[i].FOnDelete + ',';
94 |
95 | DS := OlfeiDB.GetSQL('PRAGMA table_info(`' + Table.Table + '`)');
96 |
97 | QueryFields := '';
98 | SQL := '';
99 | while not DS.Eof do
100 | begin
101 | if DS.FieldByName('name').AsString <> 'id' then
102 | SQL := SQL + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote + ' ' + DS.FieldByName('type').AsString + ' ' + PrepareDefault(StringReplace(DS.FieldByName('dflt_value').AsString, '"', '', [rfReplaceAll])) + ',';
103 |
104 | QueryFields := QueryFields + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote + ',';
105 |
106 | DS.Next;
107 | end;
108 |
109 | DS.Free;
110 |
111 | if Length(QueryFields) > 0 then
112 | SetLength(QueryFields, Length(QueryFields) - 1);
113 |
114 | if Length(SQL) > 0 then
115 | SetLength(SQL, Length(SQL) - 1);
116 |
117 | if Length(ForeignText) > 0 then
118 | SetLength(ForeignText, Length(ForeignText) - 1);
119 |
120 | OlfeiDB.RunSQL('ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' RENAME TO ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
121 | OlfeiDB.RunSQL('CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'id' + OlfeiDB.Quote + ' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, ' + SQL + ',' + ForeignText + ')');
122 |
123 | DS := OlfeiDB.GetSQL('PRAGMA index_list(`tmp_' + Table.Table + '`)');
124 | while not DS.Eof do
125 | begin
126 | DSInfo := OlfeiDB.GetSQL('PRAGMA index_info(' + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote + ')');
127 | Table.NewIndex(DSInfo.FieldByName('name').AsString);
128 | DSInfo.Free;
129 |
130 | DS.Next;
131 | end;
132 |
133 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + QueryFields + ') SELECT ' + QueryFields + ' FROM ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
134 | OlfeiDB.RunSQL('DROP TABLE ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
135 | end;
136 |
137 | for i := 0 to Length(Table.Indexes) - 1 do
138 | OlfeiDB.RunSQL('CREATE INDEX ' + OlfeiDB.Quote + Table.Table + '_' + Table.Indexes[i].FName + '_index' + OlfeiDB.Quote + ' ON ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + Table.Indexes[i].FName + OlfeiDB.Quote + ')');
139 |
140 | for i := 0 to Length(Table.Seeds) - 1 do
141 | begin
142 | QueryFields := '';
143 | QueryValues := '';
144 |
145 | for j := 0 to Table.Seeds[i].Count - 1 do
146 | begin
147 | QueryFields := QueryFields + OlfeiDB.Quote + Table.Seeds[i].Names[j] + OlfeiDB.Quote + ',';
148 | QueryValues := QueryValues + '"' + Table.Seeds[i].ValueFromIndex[j] + '"' + ',';
149 | end;
150 |
151 | SetLength(QueryFields, Length(QueryFields) - 1);
152 | SetLength(QueryValues, Length(QueryValues) - 1);
153 |
154 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + '(' + QueryFields + ') VALUES (' + QueryValues + ')');
155 | end;
156 |
157 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + 'migrations' + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'name' + OlfeiDB.Quote + ') VALUES ("' + Table.Migration + '")');
158 | end;
159 |
160 | procedure TOlfeiDriverSQLite.NewTable(OlfeiTable: TObject);
161 | var
162 | i: integer;
163 | Table: TOlfeiTableSchema;
164 | SQL: string;
165 | begin
166 | Table := (OlfeiTable as TOlfeiTableSchema);
167 |
168 | if not Table.Pivot then
169 | begin
170 | OlfeiDB.RunSQL('CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'id' + OlfeiDB.Quote + ' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)');
171 |
172 | for i := 0 to Length(Table.NewFields) - 1 do
173 | begin
174 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD COLUMN ' + OlfeiDB.Quote + Table.NewFields[i].FName + OlfeiDB.Quote;
175 |
176 | SQL := SQL + FieldTypeToSQL(Table.NewFields[i].FType, Table.NewFields[i].Size, Table.NewFields[i].DecimalSize);
177 | SQL := SQL + ' ' + PrepareDefault(Table.NewFields[i].Default);
178 |
179 | OlfeiDB.RunSQL(SQL);
180 | end;
181 | end
182 | else
183 | begin
184 | SQL := '';
185 | for i := 0 to Length(Table.NewFields) - 1 do
186 | SQL := SQL + OlfeiDB.Quote + Table.NewFields[i].FName + OlfeiDB.Quote + FieldTypeToSQL(Table.NewFields[i].FType, Table.NewFields[i].Size, Table.NewFields[i].DecimalSize) + ' ' + PrepareDefault(Table.NewFields[i].Default) + ',';
187 |
188 | if Length(SQL) > 0 then
189 | SetLength(SQL, Length(SQL) - 1);
190 |
191 | SQL := 'CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + SQL + ')';
192 | OlfeiDB.RunSQL(SQL);
193 | end;
194 |
195 | ConfirmUpdate(OlfeiTable);
196 | end;
197 |
198 | procedure TOlfeiDriverSQLite.DropTable(OlfeiTable: TObject);
199 | begin
200 | OlfeiDB.RunSQL('DROP TABLE ' + OlfeiDB.Quote + (OlfeiTable as TOlfeiTableSchema).Table + OlfeiDB.Quote);
201 |
202 | ConfirmUpdate(OlfeiTable);
203 | end;
204 |
205 | procedure TOlfeiDriverSQLite.UpdateTable(OlfeiTable: TObject);
206 | var
207 | i, key: integer;
208 | Table: TOlfeiTableSchema;
209 | SQL, QueryFields: string;
210 | DS, DSInfo: TFDMemTable;
211 | flUpdate, flSkip: boolean;
212 | begin
213 | OlfeiDB.RunSQL('PRAGMA foreign_keys=OFF');
214 |
215 | Table := (OlfeiTable as TOlfeiTableSchema);
216 |
217 | if (Length(Table.UpdateFields) > 0) or (Length(Table.DropFields) > 0) then
218 | begin
219 | OlfeiDB.RunSQL('ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' RENAME TO ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
220 | OlfeiDB.RunSQL('CREATE TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + OlfeiDB.Quote + 'id' + OlfeiDB.Quote + ' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)');
221 |
222 | DS := OlfeiDB.GetSQL('PRAGMA table_info(`tmp_' + Table.Table + '`)');
223 |
224 | QueryFields := '';
225 | while not DS.Eof do
226 | begin
227 | flSkip := false;
228 |
229 | if DS.FieldByName('name').AsString <> 'id' then
230 | begin
231 | flUpdate := false;
232 | key := 0;
233 |
234 | for i := 0 to Length(Table.DropFields) - 1 do
235 | begin
236 | if AnsiLowerCase(Table.DropFields[i].FName) = AnsiLowerCase(DS.FieldByName('name').AsString) then
237 | begin
238 | flSkip := True;
239 | Break;
240 | end;
241 | end;
242 |
243 | if not flSkip then
244 | begin
245 | for i := 0 to Length(Table.UpdateFields) - 1 do
246 | begin
247 | if AnsiLowerCase(Table.UpdateFields[i].FName) = AnsiLowerCase(DS.FieldByName('name').AsString) then
248 | begin
249 | flUpdate := true;
250 | key := i;
251 |
252 | break;
253 | end;
254 | end;
255 |
256 | if flUpdate then
257 | begin
258 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD COLUMN ' + OlfeiDB.Quote + Table.UpdateFields[key].FName + OlfeiDB.Quote;
259 |
260 | SQL := SQL + FieldTypeToSQL(Table.UpdateFields[key].FType, Table.UpdateFields[key].Size, Table.UpdateFields[key].DecimalSize);
261 | SQL := SQL + ' ' + PrepareDefault(Table.UpdateFields[key].Default);
262 |
263 | OlfeiDB.RunSQL(SQL);
264 | end
265 | else
266 | begin
267 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD COLUMN ' + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote;
268 |
269 | SQL := SQL + ' ' + DS.FieldByName('type').AsString;
270 | SQL := SQL + ' ' + PrepareDefault(StringReplace(DS.FieldByName('dflt_value').AsString, '"', '', [rfReplaceAll]));
271 |
272 | OlfeiDB.RunSQL(SQL);
273 | end;
274 | end;
275 | end;
276 |
277 | if not flSkip then
278 | QueryFields := QueryFields + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote + ',';
279 |
280 | DS.Next;
281 | end;
282 |
283 | DS.Free;
284 |
285 | SetLength(QueryFields, Length(QueryFields) - 1);
286 |
287 | DS := OlfeiDB.GetSQL('PRAGMA index_list(' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote + ')');
288 | while not DS.Eof do
289 | begin
290 | DSInfo := OlfeiDB.GetSQL('PRAGMA index_info(' + OlfeiDB.Quote + DS.FieldByName('name').AsString + OlfeiDB.Quote + ')');
291 |
292 | flSkip := false;
293 | for i := 0 to Length(Table.DropIndexes) - 1 do
294 | if Table.DropIndexes[i].FName = DSInfo.FieldByName('name').AsString then
295 | begin
296 | flSkip := True;
297 | Break;
298 | end;
299 |
300 | if not flSkip then
301 | Table.NewIndex(DSInfo.FieldByName('name').AsString);
302 |
303 | DSInfo.Free;
304 |
305 | DS.Next;
306 | end;
307 |
308 | DS.Free;
309 |
310 | try
311 | DS := OlfeiDB.GetSQL('PRAGMA foreign_key_list(' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote + ')');
312 |
313 | while not DS.Eof do
314 | begin
315 | flSkip := false;
316 | for i := 0 to Length(Table.DropForeigns) - 1 do
317 | if Table.DropForeigns[i].FName = DS.FieldByName('from').AsString then
318 | begin
319 | flSkip := True;
320 | Break;
321 | end;
322 |
323 | if not flSkip then
324 | Table.NewForeign(DS.FieldByName('table').AsString, DS.FieldByName('from').AsString, DS.FieldByName('to').AsString);
325 |
326 | DS.Next;
327 | end;
328 |
329 | DS.Free;
330 | except
331 | end;
332 |
333 | OlfeiDB.RunSQL('INSERT INTO ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' (' + QueryFields + ') SELECT ' + QueryFields + ' FROM ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
334 | OlfeiDB.RunSQL('DROP TABLE ' + OlfeiDB.Quote + 'tmp_' + Table.Table + OlfeiDB.Quote);
335 | end;
336 |
337 | for i := 0 to Length(Table.NewFields) - 1 do
338 | begin
339 | SQL := 'ALTER TABLE ' + OlfeiDB.Quote + Table.Table + OlfeiDB.Quote + ' ADD COLUMN ' + OlfeiDB.Quote + Table.NewFields[i].FName + OlfeiDB.Quote;
340 |
341 | SQL := SQL + FieldTypeToSQL(Table.NewFields[i].FType, Table.NewFields[i].Size, Table.NewFields[i].DecimalSize);
342 | SQL := SQL + ' ' + PrepareDefault(Table.NewFields[i].Default);
343 |
344 | OlfeiDB.RunSQL(SQL);
345 | end;
346 |
347 | ConfirmUpdate(OlfeiTable);
348 |
349 | OlfeiDB.RunSQL('PRAGMA foreign_keys=ON');
350 | end;
351 |
352 | procedure TOlfeiDriverSQLite.Init(Parameters: TStringList);
353 |
354 | function PreparePath(FilePath: string): string;
355 | begin
356 | {$IF DEFINED(iOS) or DEFINED(ANDROID)}
357 | Result := StringReplace(FilePath, '.\', TPath.GetDocumentsPath, []);
358 | Result := StringReplace(FilePath, './', TPath.GetDocumentsPath, []);
359 | {$ELSE}
360 | Result := StringReplace(FilePath, '.\', ExtractFilePath(ParamStr(0)), []);
361 | Result := StringReplace(FilePath, './', ExtractFilePath(ParamStr(0)), []);
362 | {$ENDIF}
363 | end;
364 |
365 | begin
366 | OlfeiDB.Quote := '`';
367 |
368 | if not OlfeiDB.IsPool then
369 | begin
370 | OlfeiDB.SQLConnection.DriverName := 'SQLite';
371 | OlfeiDB.SQLConnection.Params.Values['DriverID'] := 'SQLite';
372 | OlfeiDB.SQLConnection.Params.Values['Database'] := PreparePath(Parameters.Values['database']);
373 | OlfeiDB.SQLConnection.LoginPrompt := false;
374 | end;
375 | end;
376 |
377 | function TOlfeiDriverSQLite.CheckTable(TableName: string): Boolean;
378 | begin
379 | Result := OlfeiDB.GetOnce('SELECT COUNT(name) FROM sqlite_master WHERE type = ''table'' AND name = ''' + TableName + '''', 'integer') = '1';
380 | end;
381 |
382 | function TOlfeiDriverSQLite.RandomOrder: string;
383 | begin
384 | Result := 'ORDER BY random()';
385 | end;
386 |
387 | end.
388 |
--------------------------------------------------------------------------------
/Core/OlfeiSchema.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiSchema;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, SysUtils, OlfeiSQLDriver, System.Classes;
7 |
8 | const
9 | TOlfeiFieldTypeString = 0;
10 | TOlfeiFieldTypeInteger = 1;
11 | TOlfeiFieldTypeIntegerUnsigned = 2;
12 | TOlfeiFieldTypeFloat = 3;
13 | TOlfeiFieldTypeText = 4;
14 | TOlfeiFieldTypeBoolean = 5;
15 | TOlfeiFieldTypeDateTime = 6;
16 | TOlfeiFieldTypeDate = 7;
17 | TOlfeiFieldTypeBlob = 8;
18 |
19 | type
20 | TOlfeiTableIndex = record
21 | FName: string;
22 | end;
23 |
24 | TOlfeiTableForeign = record
25 | FTable, FLocalKey, FRemoteKey, FOnDelete: string;
26 | end;
27 |
28 | TOlfeiTableField = record
29 | FName, Default: string;
30 | FType: word;
31 | DecimalSize, Size: integer;
32 | end;
33 |
34 | TOlfeiTableFields = array of TOlfeiTableField;
35 | TOlfeiTableSeeds = array of TStringList;
36 | TOlfeiTableIndexes = array of TOlfeiTableIndex;
37 | TOlfeiTableForeigns = array of TOlfeiTableForeign;
38 |
39 | TOlfeiTableSchema = class
40 | private
41 | IsNew: boolean;
42 | IsDrop: boolean;
43 | FNewFields: TOlfeiTableFields;
44 | FUpdateFields: TOlfeiTableFields;
45 | FDropFields: TOlfeiTableFields;
46 | FTableName: string;
47 | FMigrationName: string;
48 | FSeeds: TOlfeiTableSeeds;
49 | FIndexes: TOlfeiTableIndexes;
50 | FForeigns: TOlfeiTableForeigns;
51 | FDropIndexes: TOlfeiTableIndexes;
52 | FDropForeigns: TOlfeiTableIndexes;
53 |
54 | procedure AddField(AName: string; AType: word; ASize: Integer; ADefault: string);
55 | procedure AddDecimalField(AName: string; AType: word; ASize, ADecimalSize: Integer; ADefault: string);
56 |
57 | procedure UpdateField(AName: string; AType: word; ASize: Integer; ADefault: string);
58 | procedure UpdateDecimalField(AName: string; AType: word; ASize, ADecimalSize: Integer; ADefault: string);
59 | public
60 | Pivot: boolean;
61 |
62 | property Migration: string read FMigrationName;
63 | property Table: string read FTableName;
64 | property NewFields: TOlfeiTableFields read FNewFields;
65 | property UpdateFields: TOlfeiTableFields read FUpdateFields;
66 | property DropFields: TOlfeiTableFields read FDropFields;
67 | property Seeds: TOlfeiTableSeeds read FSeeds;
68 | property Indexes: TOlfeiTableIndexes read FIndexes;
69 | property Foreigns: TOlfeiTableForeigns read FForeigns;
70 | property DropIndexes: TOlfeiTableIndexes read FDropIndexes;
71 | property DropForeigns: TOlfeiTableIndexes read FDropForeigns;
72 | property New: boolean read IsNew;
73 |
74 | procedure NewString(AName: string; ASize: integer = 255; ADefault: string = 'NULL');
75 | procedure NewInteger(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
76 | procedure NewIntegerUnsigned(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
77 | procedure NewFloat(AName: string; ASize: integer = 16; ADecimalSize: integer = 2; ADefault: string = 'NULL');
78 | procedure NewText(AName: string; ASize: integer = 65535; ADefault: string = 'NULL');
79 | procedure NewBoolean(AName: string; ADefault: boolean = false);
80 | procedure NewDateTime(AName: string; ADefault: string = 'NULL');
81 | procedure NewDate(AName: string; ADefault: string = 'NULL');
82 | procedure NewBlob(AName: string);
83 |
84 | procedure NewTimestamps;
85 |
86 | procedure UpdateString(AName: string; ASize: integer = 255; ADefault: string = 'NULL');
87 | procedure UpdateInteger(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
88 | procedure UpdateIntegerUnsigned(AName: string; ASize: integer = 11; ADefault: string = 'NULL');
89 | procedure UpdateFloat(AName: string; ASize: integer = 16; ADecimalSize: integer = 2; ADefault: string = 'NULL');
90 | procedure UpdateText(AName: string; ASize: integer = 65525; ADefault: string = 'NULL');
91 | procedure UpdateBoolean(AName: string; ADefault: boolean = false);
92 | procedure UpdateDateTime(AName: string; ADefault: string = 'NULL');
93 | procedure UpdateDate(AName: string; ADefault: string = 'NULL');
94 | procedure UpdateBlob(AName: string);
95 |
96 | procedure NewIndex(AName: string);
97 | procedure NewForeign(ATable, ALocalKey, ARemoteKey: string; AOnDelete: string = 'NO ACTION');
98 |
99 | procedure Drop(AName: string);
100 | procedure DropIndex(AName: string);
101 | procedure DropForeign(AName: string);
102 |
103 | function Seed(AName: string = ''): TStringList;
104 |
105 | constructor Create(ATable: string; New: boolean = false; Drop: boolean = false); overload;
106 | destructor Destroy; override;
107 | end;
108 |
109 | TOlfeiSchema = class
110 | private
111 | Driver: TOlfeiSQLDriver;
112 | public
113 | constructor Create(ADriver: TOlfeiSQLDriver); overload;
114 | procedure Run;
115 | end;
116 |
117 | var
118 | OlfeiTable: TOlfeiTableSchema;
119 | OlfeiTables: array of TOlfeiTableSchema;
120 | OlfeiSeed: TStringList;
121 |
122 | function NewTable(ATable: string): TOlfeiTableSchema;
123 | function UpdateTable(ATable: string): TOlfeiTableSchema;
124 | function PivotTable(ATable: string): TOlfeiTableSchema;
125 | function DropTable(ATable: string): TOlfeiTableSchema;
126 |
127 | implementation
128 |
129 | procedure ClearMigrations;
130 | var
131 | i: integer;
132 | begin
133 | for i := Length(OlfeiTables) - 1 downto 0 do
134 | OlfeiTables[i].Free;
135 |
136 | SetLength(OlfeiTables, 0);
137 | end;
138 |
139 | function NewTable(ATable: string): TOlfeiTableSchema;
140 | begin
141 | SetLength(OlfeiTables, Length(OlfeiTables) + 1);
142 | OlfeiTables[Length(OlfeiTables) - 1] := TOlfeiTableSchema.Create(ATable, True);
143 |
144 | Result := OlfeiTables[Length(OlfeiTables) - 1];
145 | end;
146 |
147 | function UpdateTable(ATable: string): TOlfeiTableSchema;
148 | begin
149 | SetLength(OlfeiTables, Length(OlfeiTables) + 1);
150 | OlfeiTables[Length(OlfeiTables) - 1] := TOlfeiTableSchema.Create(ATable);
151 |
152 | Result := OlfeiTables[Length(OlfeiTables) - 1];
153 | end;
154 |
155 | function PivotTable(ATable: string): TOlfeiTableSchema;
156 | begin
157 | SetLength(OlfeiTables, Length(OlfeiTables) + 1);
158 | OlfeiTables[Length(OlfeiTables) - 1] := TOlfeiTableSchema.Create(ATable, True);
159 | OlfeiTables[Length(OlfeiTables) - 1].Pivot := True;
160 |
161 | Result := OlfeiTables[Length(OlfeiTables) - 1];
162 | end;
163 |
164 | function DropTable(ATable: string): TOlfeiTableSchema;
165 | begin
166 | SetLength(OlfeiTables, Length(OlfeiTables) + 1);
167 | OlfeiTables[Length(OlfeiTables) - 1] := TOlfeiTableSchema.Create(ATable, False, True);
168 |
169 | Result := OlfeiTables[Length(OlfeiTables) - 1];
170 | end;
171 |
172 | constructor TOlfeiSchema.Create(ADriver: TOlfeiSQLDriver);
173 | begin
174 | Driver := ADriver;
175 | end;
176 |
177 | constructor TOlfeiTableSchema.Create(ATable: string; New: Boolean = False; Drop: Boolean = false);
178 | begin
179 | Self.IsNew := New;
180 | Self.FTableName := ATable;
181 | Self.Pivot := false;
182 | Self.IsDrop := Drop;
183 |
184 | if Self.IsDrop then
185 | Self.FMigrationName := 'drop_table_' + AnsiLowerCase(ATable)
186 | else
187 | begin
188 | if Self.IsNew then
189 | Self.FMigrationName := 'create_table_' + AnsiLowerCase(ATable)
190 | else
191 | Self.FMigrationName := 'update_table_' + AnsiLowerCase(ATable);
192 | end;
193 | end;
194 |
195 | destructor TOlfeiTableSchema.Destroy;
196 | var
197 | i: integer;
198 | begin
199 | for i := Length(FSeeds) - 1 downto 0 do
200 | FSeeds[i].Free;
201 |
202 | SetLength(FSeeds, 0);
203 | SetLength(FNewFields, 0);
204 | SetLength(FUpdateFields, 0);
205 | SetLength(FDropFields, 0);
206 | SetLength(FIndexes, 0);
207 | SetLength(FForeigns, 0);
208 | SetLength(FDropIndexes, 0);
209 | SetLength(FDropForeigns, 0);
210 | end;
211 |
212 | procedure TOlfeiTableSchema.DropIndex(AName: string);
213 | begin
214 | Self.FMigrationName := Self.FMigrationName + '_drop_index_' + AName;
215 |
216 | SetLength(FDropIndexes, Length(FDropIndexes) + 1);
217 | FDropIndexes[Length(FDropIndexes) - 1].FName := AName;
218 | end;
219 |
220 | procedure TOlfeiTableSchema.DropForeign(AName: string);
221 | begin
222 | Self.FMigrationName := Self.FMigrationName + '_drop_foreign_' + AName;
223 |
224 | SetLength(FDropForeigns, Length(FDropForeigns) + 1);
225 | FDropForeigns[Length(FDropForeigns) - 1].FName := AName;
226 | end;
227 |
228 | function TOlfeiTableSchema.Seed(AName: string = ''): TStringList;
229 | begin
230 | Self.FMigrationName := Self.FMigrationName;
231 |
232 | if Length(AName) > 0 then
233 | Self.FMigrationName := Self.FMigrationName + '_seed_' + AName;
234 |
235 | SetLength(FSeeds, Length(FSeeds) + 1);
236 | FSeeds[Length(FSeeds) - 1] := TStringList.Create;
237 |
238 | Result := FSeeds[Length(FSeeds) - 1];
239 | end;
240 |
241 | procedure TOlfeiSchema.Run;
242 | var
243 | i: integer;
244 | MigrationTable: TOlfeiTableSchema;
245 | begin
246 | if not Self.Driver.CheckTable('migrations') then
247 | begin
248 | MigrationTable := TOlfeiTableSchema.Create('migrations', true);
249 | MigrationTable.NewText('name', 4096);
250 |
251 | Self.Driver.NewTable(MigrationTable);
252 |
253 | MigrationTable.Free;
254 | end;
255 |
256 | for i := 0 to Length(OlfeiTables) - 1 do
257 | begin
258 | Self.Driver.OlfeiDB.BeginTransaction;
259 |
260 | if not Self.Driver.IsMigrate(OlfeiTables[i].Migration) then
261 | if OlfeiTables[i].IsNew then
262 | Self.Driver.NewTable(OlfeiTables[i])
263 | else if OlfeiTables[i].IsDrop then
264 | Self.Driver.DropTable(OlfeiTables[i])
265 | else
266 | Self.Driver.UpdateTable(OlfeiTables[i]);
267 |
268 | Self.Driver.OlfeiDB.EndTransaction;
269 | end;
270 | end;
271 |
272 | procedure TOlfeiTableSchema.Drop(AName: string);
273 | begin
274 | Self.FMigrationName := Self.FMigrationName + '_drop_' + AName;
275 |
276 | SetLength(Self.FDropFields, Length(Self.FDropFields) + 1);
277 |
278 | Self.FDropFields[Length(Self.FDropFields) - 1].FName := AName;
279 | end;
280 |
281 | procedure TOlfeiTableSchema.AddField(AName: string; AType: word; ASize: Integer; ADefault: string);
282 | begin
283 | Self.FMigrationName := Self.FMigrationName + '_add_' + AName;
284 |
285 | SetLength(Self.FNewFields, Length(Self.FNewFields) + 1);
286 |
287 | Self.FNewFields[Length(Self.FNewFields) - 1].FName := AName;
288 | Self.FNewFields[Length(Self.FNewFields) - 1].FType := AType;
289 | Self.FNewFields[Length(Self.FNewFields) - 1].Default := ADefault;
290 | Self.FNewFields[Length(Self.FNewFields) - 1].Size := ASize;
291 | Self.FNewFields[Length(Self.FNewFields) - 1].DecimalSize := 0;
292 | end;
293 |
294 | procedure TOlfeiTableSchema.AddDecimalField(AName: string; AType: word; ASize, ADecimalSize: Integer; ADefault: string);
295 | begin
296 | Self.FMigrationName := Self.FMigrationName + '_add_' + AName;
297 |
298 | SetLength(Self.FNewFields, Length(Self.FNewFields) + 1);
299 |
300 | Self.FNewFields[Length(Self.FNewFields) - 1].FName := AName;
301 | Self.FNewFields[Length(Self.FNewFields) - 1].FType := AType;
302 | Self.FNewFields[Length(Self.FNewFields) - 1].Default := ADefault;
303 | Self.FNewFields[Length(Self.FNewFields) - 1].Size := ASize;
304 | Self.FNewFields[Length(Self.FNewFields) - 1].DecimalSize := ADecimalSize;
305 | end;
306 |
307 | procedure TOlfeiTableSchema.UpdateField(AName: string; AType: word; ASize: Integer; ADefault: string);
308 | begin
309 | Self.FMigrationName := Self.FMigrationName + '_update_' + AName;
310 |
311 | SetLength(Self.FUpdateFields, Length(Self.FUpdateFields) + 1);
312 |
313 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].FName := AName;
314 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].FType := AType;
315 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].Default := ADefault;
316 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].Size := ASize;
317 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].DecimalSize := 0;
318 | end;
319 |
320 | procedure TOlfeiTableSchema.UpdateDecimalField(AName: string; AType: word; ASize, ADecimalSize: Integer; ADefault: string);
321 | begin
322 | Self.FMigrationName := Self.FMigrationName + '_update_' + AName;
323 |
324 | SetLength(Self.FUpdateFields, Length(Self.FUpdateFields) + 1);
325 |
326 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].FName := AName;
327 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].FType := AType;
328 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].Default := ADefault;
329 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].Size := ASize;
330 | Self.FUpdateFields[Length(Self.FUpdateFields) - 1].DecimalSize := ADecimalSize;
331 | end;
332 |
333 | procedure TOlfeiTableSchema.NewBoolean(AName: string; ADefault: boolean);
334 | begin
335 | Self.AddField(AName, TOlfeiFieldTypeBoolean, 1, ADefault.ToString());
336 | end;
337 |
338 | procedure TOlfeiTableSchema.NewDate(AName: string; ADefault: string);
339 | begin
340 | Self.AddField(AName, TOlfeiFieldTypeDate, 0, ADefault);
341 | end;
342 |
343 | procedure TOlfeiTableSchema.NewFloat(AName: string; ASize: integer; ADecimalSize: integer;
344 | ADefault: string);
345 | begin
346 | Self.AddDecimalField(AName, TOlfeiFieldTypeFloat, ASize, ADecimalSize, ADefault);
347 | end;
348 |
349 | procedure TOlfeiTableSchema.NewForeign(ATable, ALocalKey, ARemoteKey: string; AOnDelete: string = 'NO ACTION');
350 | begin
351 | Self.FMigrationName := Self.FMigrationName + '_add_foreign_' + ALocalKey;
352 |
353 | SetLength(FForeigns, Length(FForeigns) + 1);
354 | FForeigns[Length(FForeigns) - 1].FTable := ATable;
355 | FForeigns[Length(FForeigns) - 1].FLocalKey := ALocalKey;
356 | FForeigns[Length(FForeigns) - 1].FRemoteKey := ARemoteKey;
357 | FForeigns[Length(FForeigns) - 1].FOnDelete := AOnDelete;
358 | end;
359 |
360 | procedure TOlfeiTableSchema.NewIndex(AName: string);
361 | begin
362 | Self.FMigrationName := Self.FMigrationName + '_add_index_' + AName;
363 |
364 | SetLength(FIndexes, Length(FIndexes) + 1);
365 | FIndexes[Length(FIndexes) - 1].FName := AName;
366 | end;
367 |
368 | procedure TOlfeiTableSchema.NewInteger(AName: string; ASize: integer;
369 | ADefault: string);
370 | begin
371 | Self.AddField(AName, TOlfeiFieldTypeInteger, ASize, ADefault);
372 | end;
373 |
374 | procedure TOlfeiTableSchema.NewIntegerUnsigned(AName: string; ASize: integer;
375 | ADefault: string);
376 | begin
377 | Self.AddField(AName, TOlfeiFieldTypeIntegerUnsigned, ASize, ADefault);
378 | end;
379 |
380 | procedure TOlfeiTableSchema.NewString(AName: string; ASize: integer;
381 | ADefault: string);
382 | begin
383 | Self.AddField(AName, TOlfeiFieldTypeString, ASize, ADefault);
384 | end;
385 |
386 | procedure TOlfeiTableSchema.NewBlob(AName: string);
387 | begin
388 | Self.AddField(AName, TOlfeiFieldTypeBlob, 0, 'NULL');
389 | end;
390 |
391 | procedure TOlfeiTableSchema.UpdateBlob(AName: string);
392 | begin
393 | Self.UpdateField(AName, TOlfeiFieldTypeBlob, 0, 'NULL');
394 | end;
395 |
396 | procedure TOlfeiTableSchema.NewText(AName: string; ASize: integer;
397 | ADefault: string);
398 | begin
399 | Self.AddField(AName, TOlfeiFieldTypeText, ASize, ADefault);
400 | end;
401 |
402 | procedure TOlfeiTableSchema.NewDateTime(AName: string; ADefault: string);
403 | begin
404 | Self.AddField(AName, TOlfeiFieldTypeDateTime, 0, ADefault);
405 | end;
406 |
407 | procedure TOlfeiTableSchema.NewTimestamps;
408 | begin
409 | Self.AddField('created_at', TOlfeiFieldTypeDateTime, 0, 'NULL');
410 | Self.AddField('updated_at', TOlfeiFieldTypeDateTime, 0, 'NULL');
411 | end;
412 |
413 | procedure TOlfeiTableSchema.UpdateBoolean(AName: string; ADefault: boolean);
414 | begin
415 | Self.UpdateField(AName, TOlfeiFieldTypeBoolean, 1, ADefault.ToString());
416 | end;
417 |
418 | procedure TOlfeiTableSchema.UpdateDate(AName, ADefault: string);
419 | begin
420 | Self.UpdateField(AName, TOlfeiFieldTypeDate, 0, ADefault);
421 | end;
422 |
423 | procedure TOlfeiTableSchema.UpdateFloat(AName: string; ASize: integer; ADecimalSize: integer;
424 | ADefault: string);
425 | begin
426 | Self.UpdateDecimalField(AName, TOlfeiFieldTypeFloat, ASize, ADecimalSize, ADefault);
427 | end;
428 |
429 | procedure TOlfeiTableSchema.UpdateInteger(AName: string; ASize: integer;
430 | ADefault: string);
431 | begin
432 | Self.UpdateField(AName, TOlfeiFieldTypeInteger, ASize, ADefault);
433 | end;
434 |
435 | procedure TOlfeiTableSchema.UpdateIntegerUnsigned(AName: string; ASize: integer;
436 | ADefault: string);
437 | begin
438 | Self.UpdateField(AName, TOlfeiFieldTypeIntegerUnsigned, ASize, ADefault);
439 | end;
440 |
441 | procedure TOlfeiTableSchema.UpdateString(AName: string; ASize: integer;
442 | ADefault: string);
443 | begin
444 | Self.UpdateField(AName, TOlfeiFieldTypeString, ASize, ADefault);
445 | end;
446 |
447 | procedure TOlfeiTableSchema.UpdateText(AName: string; ASize: integer;
448 | ADefault: string);
449 | begin
450 | Self.UpdateField(AName, TOlfeiFieldTypeText, ASize, ADefault);
451 | end;
452 |
453 | procedure TOlfeiTableSchema.UpdateDateTime(AName: string; ADefault: string);
454 | begin
455 | Self.UpdateField(AName, TOlfeiFieldTypeDateTime, 0, ADefault);
456 | end;
457 |
458 | initialization
459 |
460 | finalization
461 | ClearMigrations;
462 |
463 | end.
464 |
--------------------------------------------------------------------------------
/Core/OlfeiCollection.pas:
--------------------------------------------------------------------------------
1 | unit OlfeiCollection;
2 |
3 | interface
4 |
5 | uses
6 | OlfeiSQL, System.SysUtils, System.Classes, FireDac.Comp.Client, System.Rtti,
7 | OlfeiORM, System.Generics.Collections, System.JSON;
8 |
9 | type
10 | TOlfeiCollectionEnumerator = class
11 | protected
12 | FList: TOlfeiResultArray;
13 | FIndex: integer;
14 | function GetCurrent: T;
15 | public
16 | constructor Create(AList: TOlfeiResultArray);
17 | function MoveNext: Boolean;
18 | property Current: T read GetCurrent;
19 | end;
20 |
21 | TOlfeiCollectionResult = class
22 | protected
23 | FList: TOlfeiResultArray;
24 | public
25 | constructor Create; overload;
26 | function GetEnumerator: TOlfeiCollectionEnumerator;
27 | procedure Assign(AList: TOlfeiResultArray);
28 | end;
29 |
30 | TOlfeiCollection = class
31 | private
32 | FJSONArray: TJSONArray;
33 | FTable: String;
34 | FDB: TOlfeiDB;
35 | FParentClass: TClass;
36 | IsPreInput: Boolean;
37 | IsPivot: boolean;
38 | QueryString, OrderString, LimitString, DistinctString: String;
39 |
40 | FFilterFields: TOlfeiFilterFields;
41 |
42 | FRemoteKey, FRemoteTable, FLocalKey, FRemoteValue: string;
43 |
44 | procedure Clear;
45 | protected
46 | Elements: TOlfeiResultArray;
47 | Iterator: TOlfeiCollectionResult;
48 |
49 | function GetResultQuery: string;
50 | function RttiMethodInvokeEx(const MethodName:string; RttiType : TRttiType; Instance: TValue; const Args: array of TValue): TValue;
51 | public
52 | property RemoteKey: string read FRemoteKey write FRemoteKey;
53 | property RemoteTable: string read FRemoteTable write FRemoteTable;
54 | property LocalKey: string read FLocalKey write FLocalKey;
55 | property RemoteValue: string read FRemoteValue write FRemoteValue;
56 | property Table: string read FTable;
57 |
58 | function Where(Name, Comparison, Value: String): TOlfeiCollection; overload;
59 | function Where(Name, Value: string): TOlfeiCollection; overload;
60 | function Where(Name: string; Value: boolean): TOlfeiCollection; overload;
61 | function WhereRaw(Expression: string): TOlfeiCollection;
62 |
63 | function StartGroup: TOlfeiCollection;
64 | function StartAndGroup: TOlfeiCollection;
65 | function StartOrGroup: TOlfeiCollection;
66 | function EndGroup: TOlfeiCollection;
67 | function OrWhere(Name, Comparison, Value: String): TOlfeiCollection;
68 | function OrderBy(Field, Direction: String): TOlfeiCollection;
69 | function WhereFor(Table, Name, Comparison, Value: String): TOlfeiCollection;
70 | function OrWhereFor(Table, Name, Comparison, Value: String): TOlfeiCollection;
71 | function OrderByFor(Table, Field, Direction: String): TOlfeiCollection;
72 | function Limit(Offset, Limit: integer): TOlfeiCollection;
73 | function Distinct(Field: string): TOlfeiCollection;
74 |
75 | function Join(Table, FieldJoin, FieldJoinWith: String): TOlfeiCollection;
76 |
77 | function Count: Integer;
78 | function Sum(Field: string): Real;
79 | function Min(Field: string): Real;
80 | function Max(Field: string): Real;
81 | function Avg(Field: string): Real;
82 |
83 | procedure Truncate;
84 | procedure Delete;
85 |
86 | function Select(const AFilterFields: array of string): TOlfeiCollection;
87 |
88 | constructor Create(ADB: TOlfeiDB; AParentClass: TClass; Pivot: boolean = false); overload;
89 | destructor Destroy; override;
90 |
91 | function All(WithCache: Boolean = True): TOlfeiCollectionResult;
92 | function First(LockBeforeUpdate: boolean = false; WithCache: Boolean = True): T;
93 | function Random(LockBeforeUpdate: boolean = false; WithCache: Boolean = True): T;
94 | function ToJSON(WithCache: Boolean = True): TJSONArray;
95 | end;
96 |
97 | implementation
98 |
99 | function TOlfeiCollection.RttiMethodInvokeEx(const MethodName: string; RttiType: TRttiType; Instance: TValue; const Args: array of TValue): TValue;
100 | var
101 | Found : Boolean;
102 | LMethod : TRttiMethod;
103 | LIndex : Integer;
104 | LParams : TArray;
105 | begin
106 | Result := nil;
107 | LMethod := nil;
108 | Found := False;
109 |
110 | for LMethod in RttiType.GetMethods do
111 | if SameText(LMethod.Name, MethodName) then
112 | begin
113 | LParams := LMethod.GetParameters;
114 | if Length(Args) = Length(LParams) then
115 | begin
116 | Found := True;
117 | for LIndex := 0 to Length(LParams) - 1 do
118 | if LParams[LIndex].ParamType.Handle <> Args[LIndex].TypeInfo then
119 | begin
120 | Found := False;
121 | Break;
122 | end;
123 | end;
124 |
125 | if Found then
126 | Break;
127 | end;
128 |
129 | if (LMethod <> nil) and Found then
130 | Result := LMethod.Invoke(Instance, Args)
131 | else
132 | raise Exception.CreateFmt('method %s not found', [MethodName]);
133 | end;
134 |
135 | procedure TOlfeiCollectionResult.Assign(AList: TOlfeiResultArray);
136 | begin
137 | FList := AList;
138 | end;
139 |
140 | constructor TOlfeiCollectionEnumerator.Create(AList: TOlfeiResultArray);
141 | begin
142 | inherited Create;
143 | FList := AList;
144 | FIndex := 0;
145 | end;
146 |
147 | function TOlfeiCollectionEnumerator.MoveNext: Boolean;
148 | begin
149 | Result := FIndex < Length(FList);
150 | if Result then
151 | begin
152 | Inc(FIndex);
153 | end;
154 | end;
155 |
156 | function TOlfeiCollectionEnumerator.GetCurrent: T;
157 | begin
158 | Result := FList[FIndex - 1];
159 | end;
160 |
161 | constructor TOlfeiCollectionResult.Create;
162 | begin
163 | inherited Create;
164 | end;
165 |
166 | function TOlfeiCollectionResult.GetEnumerator: TOlfeiCollectionEnumerator;
167 | begin
168 | Result := TOlfeiCollectionEnumerator.Create(FList);
169 | end;
170 |
171 | constructor TOlfeiCollection.Create(ADB: TOlfeiDB; AParentClass: TClass; Pivot: boolean = false);
172 | var
173 | RttiContext: TRttiContext;
174 | RttiType: TRttiType;
175 | RttiValue: TValue;
176 | RttiParameters: TArray;
177 | begin
178 | FJSONArray := TJSONArray.Create;
179 |
180 | FDB := ADB;
181 | FParentClass := AParentClass;
182 | IsPivot := Pivot;
183 |
184 | RttiContext := TRttiContext.Create;
185 | RttiType := RttiContext.GetType(FParentClass);
186 |
187 | Setlength(RttiParameters, 3);
188 | RttiParameters[0] := TValue.From(ADB);
189 | RttiParameters[1] := TValue.From(0);
190 | RttiParameters[2] := False;
191 |
192 | RttiValue := RttiType.GetMethod('Create').Invoke(RttiType.AsInstance.MetaclassType, RttiParameters);
193 |
194 | FTable := TOlfeiORM(RttiValue.AsObject).Table;
195 |
196 | TOlfeiORM(RttiValue.AsObject).Free;
197 |
198 | RttiContext.Free;
199 |
200 | QueryString := '';
201 | OrderString := '';
202 | LimitString := '';
203 | DistinctString := '';
204 |
205 | IsPreInput := False;
206 |
207 | Iterator := TOlfeiCollectionResult.Create;
208 | end;
209 |
210 | destructor TOlfeiCollection.Destroy;
211 | begin
212 | if Assigned(FJSONArray) then
213 | FJSONArray.Free;
214 |
215 | Self.Clear;
216 | Iterator.Free;
217 |
218 | inherited;
219 | end;
220 |
221 | function TOlfeiCollection.Limit(Offset, Limit: integer): TOlfeiCollection;
222 | begin
223 | LimitString := LimitString + 'LIMIT ' + Offset.ToString() + ',' + Limit.ToString() + ' ';
224 |
225 | Result := Self;
226 | end;
227 |
228 | function TOlfeiCollection.Distinct(Field: string): TOlfeiCollection;
229 | begin
230 | DistinctString := ' DISTINCT ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ', ';
231 |
232 | Result := Self;
233 | end;
234 |
235 | function TOlfeiCollection.Where(Name: String; Comparison: String; Value: String): TOlfeiCollection;
236 | begin
237 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
238 | QueryString := QueryString + 'WHERE ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
239 | else
240 | if IsPreInput then
241 | QueryString := QueryString + 'AND ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
242 | else
243 | QueryString := QueryString + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' ';
244 |
245 | IsPreInput := True;
246 |
247 | Result := Self;
248 | end;
249 |
250 | function TOlfeiCollection.Where(Name: String; Value: String): TOlfeiCollection;
251 | var
252 | Comparison: String;
253 | begin
254 | Comparison := '=';
255 |
256 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
257 | QueryString := QueryString + 'WHERE ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
258 | else
259 | if IsPreInput then
260 | QueryString := QueryString + 'AND ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
261 | else
262 | QueryString := QueryString + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' ';
263 |
264 | IsPreInput := True;
265 |
266 | Result := Self;
267 | end;
268 |
269 | function TOlfeiCollection.Where(Name: String; Value: Boolean): TOlfeiCollection;
270 | begin
271 | if not Value then
272 | begin
273 | Result := Self.
274 | StartGroup.
275 | Where(Name, '<>', '1').
276 | Where(Name, '<>', '-1').
277 | EndGroup;
278 | end
279 | else
280 | begin
281 | Result := Self.
282 | StartGroup.
283 | Where(Name, '=', '1').
284 | OrWhere(Name, '=', '-1').
285 | EndGroup;
286 | end;
287 | end;
288 |
289 | function TOlfeiCollection.WhereRaw(Expression: string): TOlfeiCollection;
290 | begin
291 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
292 | QueryString := QueryString + 'WHERE ' + Expression + ' '
293 | else
294 | if IsPreInput then
295 | QueryString := QueryString + 'AND ' + Expression + ' '
296 | else
297 | QueryString := QueryString + Expression + ' ';
298 |
299 | IsPreInput := True;
300 |
301 | Result := Self;
302 | end;
303 |
304 | function TOlfeiCollection.StartAndGroup: TOlfeiCollection;
305 | begin
306 | IsPreInput := False;
307 |
308 | QueryString := QueryString + 'AND ( ';
309 |
310 | Result := Self;
311 | end;
312 |
313 | function TOlfeiCollection.StartGroup: TOlfeiCollection;
314 | begin
315 | IsPreInput := False;
316 |
317 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
318 | QueryString := QueryString + 'WHERE ( '
319 | else
320 | QueryString := QueryString + 'AND ( ';
321 |
322 | Result := Self;
323 | end;
324 |
325 | function TOlfeiCollection.Select(const AFilterFields: array of string): TOlfeiCollection;
326 | var
327 | i: integer;
328 | begin
329 | SetLength(FFilterFields, 0);
330 | for i := 0 to Length(AFilterFields) - 1 do
331 | begin
332 | SetLength(FFilterFields, Length(FFilterFields) + 1);
333 | FFilterFields[Length(FFilterFields) - 1] := AFilterFields[i];
334 | end;
335 |
336 | Result := Self;
337 | end;
338 |
339 | function TOlfeiCollection.StartOrGroup: TOlfeiCollection;
340 | begin
341 | IsPreInput := False;
342 |
343 | QueryString := QueryString + 'OR ( ';
344 |
345 | Result := Self;
346 | end;
347 |
348 | function TOlfeiCollection.EndGroup: TOlfeiCollection;
349 | begin
350 | IsPreInput := True;
351 |
352 | QueryString := QueryString + ') ';
353 |
354 | Result := Self;
355 | end;
356 |
357 | function TOlfeiCollection.WhereFor(Table, Name, Comparison, Value: String): TOlfeiCollection;
358 | begin
359 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
360 | QueryString := QueryString + 'WHERE ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
361 | else
362 | if IsPreInput then
363 | QueryString := QueryString + 'AND ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
364 | else
365 | QueryString := QueryString + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' ';
366 |
367 | IsPreInput := True;
368 |
369 | Result := Self;
370 | end;
371 |
372 | function TOlfeiCollection.OrWhere(Name: String; Comparison: String; Value: String): TOlfeiCollection;
373 | begin
374 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
375 | QueryString := QueryString + 'WHERE ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
376 | else
377 | if IsPreInput then
378 | QueryString := QueryString + 'OR ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
379 | else
380 | QueryString := QueryString + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' ';
381 |
382 | IsPreInput := True;
383 |
384 | Result := Self;
385 | end;
386 |
387 | function TOlfeiCollection.OrWhereFor(Table, Name, Comparison, Value: String): TOlfeiCollection;
388 | begin
389 | if StrPos(PChar(QueryString), PChar('WHERE')) = nil then
390 | QueryString := QueryString + 'WHERE ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
391 | else
392 | if IsPreInput then
393 | QueryString := QueryString + 'OR ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' '
394 | else
395 | QueryString := QueryString + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + name + FDB.Quote + ' ' + comparison + ' ' + FDB.FullQuoted(value) + ' ';
396 |
397 | IsPreInput := True;
398 |
399 | Result := Self;
400 | end;
401 |
402 | function TOlfeiCollection.OrderBy(field: string; direction: string): TOlfeiCollection;
403 | begin
404 | OrderString := OrderString + ' ORDER BY ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + field + FDB.Quote + ' ' + direction + ' ';
405 |
406 | Result := Self;
407 | end;
408 |
409 | function TOlfeiCollection.OrderByFor(Table, Field: String; Direction: String): TOlfeiCollection;
410 | begin
411 | OrderString := OrderString + ' ORDER BY ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + field + FDB.Quote + ' ' + direction + ' ';
412 |
413 | Result := Self;
414 | end;
415 |
416 | function TolfeiCollection.GetResultQuery: string;
417 | begin
418 | if not Self.IsPivot then
419 | Result := 'SELECT ' + DistinctString + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + 'id' + FDB.Quote + ' FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
420 | else
421 | Result := 'SELECT ' + DistinctString + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + 'id' + FDB.Quote + ' FROM ' + FDB.Quote + FTable + FDB.Quote +
422 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
423 | ' ' + QueryString + OrderString + LimitString;
424 | end;
425 |
426 | function TOlfeiCollection.All(WithCache: boolean = True): TOlfeiCollectionResult;
427 | var
428 | DS: TFDMemTable;
429 |
430 | RttiContext: TRttiContext;
431 | RttiType: TRttiType;
432 | RttiValue: TValue;
433 | RttiParameters: TArray;
434 | begin
435 | DS := FDB.GetSQL(Self.GetResultQuery);
436 |
437 | Self.Clear;
438 |
439 | while not DS.Eof do
440 | begin
441 | RttiContext := TRttiContext.Create;
442 | RttiType := RttiContext.GetType(FParentClass);
443 |
444 | Setlength(RttiParameters, 4);
445 | RttiParameters[0] := TValue.From(FDB);
446 | RttiParameters[1] := TValue.From(FFilterFields);
447 | RttiParameters[2] := TValue.From(DS.FieldByName('id').AsInteger);
448 | RttiParameters[3] := TValue.From(WithCache);
449 |
450 | RttiValue := RttiMethodInvokeEx('Create', RttiType, RttiType.AsInstance.MetaclassType, RttiParameters);
451 |
452 | SetLength(Elements, Length(Elements) + 1);
453 | Elements[Length(Elements) - 1] := T(RttiValue.AsObject);
454 |
455 | RttiContext.Free;
456 |
457 | DS.Next;
458 | end;
459 |
460 | QueryString := '';
461 | OrderString := '';
462 | LimitString := '';
463 |
464 | DS.Free;
465 |
466 | Iterator.Assign(Elements);
467 | Result := Iterator;
468 | end;
469 |
470 | function TOlfeiCollection.ToJSON(WithCache: boolean = true): TJSONArray;
471 | var
472 | DS: TFDMemTable;
473 |
474 | RttiContext: TRttiContext;
475 | RttiType: TRttiType;
476 | RttiValue: TValue;
477 | RttiParameters: TArray;
478 | JSONObject: TJSONObject;
479 | begin
480 | DS := FDB.GetSQL(Self.GetResultQuery);
481 |
482 | while not DS.Eof do
483 | begin
484 | RttiContext := TRttiContext.Create;
485 | RttiType := RttiContext.GetType(FParentClass);
486 |
487 | Setlength(RttiParameters, 4);
488 | RttiParameters[0] := TValue.From(FDB);
489 | RttiParameters[1] := TValue.From(FFilterFields);
490 | RttiParameters[2] := TValue.From(DS.FieldByName('id').AsInteger);
491 | RttiParameters[3] := TValue.From(WithCache);
492 |
493 | RttiValue := RttiMethodInvokeEx('Create', RttiType, RttiType.AsInstance.MetaclassType, RttiParameters);
494 |
495 | SetLength(Elements, Length(Elements) + 1);
496 | Elements[Length(Elements) - 1] := T(RttiValue.AsObject);
497 |
498 | JSONObject := (TJSONObject.ParseJSONValue((Elements[Length(Elements) - 1] as TOlfeiCoreORM).ToJSON.ToString) as TJSONObject);
499 | FJSONArray.Add(JSONObject);
500 |
501 | RttiContext.Free;
502 |
503 | DS.Next;
504 | end;
505 |
506 | QueryString := '';
507 | OrderString := '';
508 | LimitString := '';
509 |
510 | DS.Free;
511 |
512 | Result := FJSONArray;
513 | end;
514 |
515 | procedure TOlfeiCollection.Delete;
516 | var
517 | SQL: string;
518 | begin
519 | if not Self.IsPivot then
520 | SQL := 'DELETE FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString
521 | else
522 | SQL := 'DELETE FROM ' + FDB.Quote + FTable + FDB.Quote +
523 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + 'id' + FDB.Quote +
524 | ' ' + QueryString + OrderString;
525 |
526 | FDB.RunSQL(SQL);
527 |
528 | Self.Clear;
529 |
530 | QueryString := '';
531 | OrderString := '';
532 | LimitString := '';
533 | end;
534 |
535 | function TOlfeiCollection.First(LockBeforeUpdate: Boolean = false; WithCache: boolean = true): T;
536 | var
537 | DS: TFDMemTable;
538 |
539 | RttiContext: TRttiContext;
540 | RttiType: TRttiType;
541 | RttiValue: TValue;
542 | RttiParameters: TArray;
543 | begin
544 | if (LockBeforeUpdate) and (FDB.Driver = 'mysql') then
545 | DS := FDB.GetSQL(Self.GetResultQuery + ' LIMIT 1 FOR UPDATE')
546 | else
547 | DS := FDB.GetSQL(Self.GetResultQuery + ' LIMIT 1');
548 |
549 | Self.Clear;
550 |
551 | RttiContext := TRttiContext.Create;
552 | RttiType := RttiContext.GetType(FParentClass);
553 |
554 | Setlength(RttiParameters, 4);
555 | RttiParameters[0] := TValue.From(FDB);
556 | RttiParameters[1] := TValue.From(FFilterFields);
557 |
558 | if not DS.Eof then
559 | RttiParameters[2] := TValue.From(DS.FieldByName('id').AsInteger)
560 | else
561 | RttiParameters[2] := 0;
562 |
563 | RttiParameters[3] := TValue.From(WithCache);
564 |
565 | RttiValue := RttiMethodInvokeEx('Create', RttiType, RttiType.AsInstance.MetaclassType, RttiParameters);
566 |
567 | SetLength(Elements, Length(Elements) + 1);
568 | Elements[Length(Elements) - 1] := T(RttiValue.AsObject);
569 |
570 | Result := Elements[0];
571 |
572 | RttiContext.Free;
573 |
574 | QueryString := '';
575 | OrderString := '';
576 | LimitString := '';
577 |
578 | DS.Free;
579 | end;
580 |
581 | function TOlfeiCollection.Random(LockBeforeUpdate: Boolean = false; WithCache: boolean = true): T;
582 | var
583 | DS: TFDMemTable;
584 |
585 | RttiContext: TRttiContext;
586 | RttiType: TRttiType;
587 | RttiValue: TValue;
588 | RttiParameters: TArray;
589 | begin
590 | if (LockBeforeUpdate) and (FDB.Driver = 'mysql') then
591 | DS := FDB.GetSQL(Self.GetResultQuery + FDB.RandomOrder + ' LIMIT 1 FOR UPDATE')
592 | else
593 | DS := FDB.GetSQL(Self.GetResultQuery + FDB.RandomOrder + ' LIMIT 1');
594 |
595 | Self.Clear;
596 |
597 | RttiContext := TRttiContext.Create;
598 | RttiType := RttiContext.GetType(FParentClass);
599 |
600 | Setlength(RttiParameters, 4);
601 | RttiParameters[0] := TValue.From(FDB);
602 | RttiParameters[1] := TValue.From(FFilterFields);
603 |
604 | if not DS.Eof then
605 | RttiParameters[2] := TValue.From(DS.FieldByName('id').AsInteger)
606 | else
607 | RttiParameters[2] := 0;
608 |
609 | RttiParameters[3] := TValue.From(WithCache);
610 |
611 | RttiValue := RttiMethodInvokeEx('Create', RttiType, RttiType.AsInstance.MetaclassType, RttiParameters);
612 |
613 | SetLength(Elements, Length(Elements) + 1);
614 | Elements[Length(Elements) - 1] := T(RttiValue.AsObject);
615 |
616 | Result := Elements[0];
617 |
618 | RttiContext.Free;
619 |
620 | QueryString := '';
621 | OrderString := '';
622 | LimitString := '';
623 |
624 | DS.Free;
625 | end;
626 |
627 | function TOlfeiCollection.Count: Integer;
628 | var
629 | SQL: string;
630 | begin
631 | if not Self.IsPivot then
632 | SQL := 'SELECT ' + DistinctString + ' COUNT(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + 'id' + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
633 | else
634 | SQL := 'SELECT ' + DistinctString + ' COUNT(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + 'id' + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote +
635 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
636 | ' ' + QueryString + OrderString + LimitString;
637 |
638 | Result := FDB.GetOnce(SQL, 'integer').ToInteger;
639 |
640 | QueryString := '';
641 | end;
642 |
643 | function TOlfeiCollection.Sum(Field: string): real;
644 | var
645 | SQL: string;
646 | begin
647 | if not Self.IsPivot then
648 | SQL := 'SELECT ' + DistinctString + ' SUM(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
649 | else
650 | SQL := 'SELECT ' + DistinctString + ' SUM(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote +
651 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
652 | ' ' + QueryString + OrderString + LimitString;
653 |
654 | Result := FDB.GetOnce(SQL, 'integer').ToDouble();
655 |
656 | QueryString := '';
657 | end;
658 |
659 | function TOlfeiCollection.Max(Field: string): real;
660 | var
661 | SQL: string;
662 | begin
663 | if not Self.IsPivot then
664 | SQL := 'SELECT ' + DistinctString + ' MAX(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
665 | else
666 | SQL := 'SELECT ' + DistinctString + ' MAX(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote +
667 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
668 | ' ' + QueryString + OrderString + LimitString;
669 |
670 | Result := FDB.GetOnce(SQL, 'integer').ToDouble();
671 |
672 | QueryString := '';
673 | end;
674 |
675 | function TOlfeiCollection.Avg(Field: string): real;
676 | var
677 | SQL: string;
678 | begin
679 | if not Self.IsPivot then
680 | SQL := 'SELECT ' + DistinctString + ' AVG(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
681 | else
682 | SQL := 'SELECT ' + DistinctString + ' AVG(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote +
683 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
684 | ' ' + QueryString + OrderString + LimitString;
685 |
686 | Result := FDB.GetOnce(SQL, 'integer').ToDouble();
687 |
688 | QueryString := '';
689 | end;
690 |
691 | function TOlfeiCollection.Min(Field: string): real;
692 | var
693 | SQL: string;
694 | begin
695 | if not Self.IsPivot then
696 | SQL := 'SELECT ' + DistinctString + ' MIN(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote + ' ' + QueryString + OrderString + LimitString
697 | else
698 | SQL := 'SELECT ' + DistinctString + ' MIN(' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + Field + FDB.Quote + ') FROM ' + FDB.Quote + FTable + FDB.Quote +
699 | ' JOIN ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + ' ON ' + FDB.Quote + Self.FRemoteTable + FDB.Quote + '.' + FDB.Quote + Self.FRemoteKey + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FRemoteValue + FDB.Quote +
700 | ' ' + QueryString + OrderString + LimitString;
701 |
702 | Result := FDB.GetOnce(SQL, 'integer').ToDouble();
703 |
704 | QueryString := '';
705 | end;
706 |
707 | function TOlfeiCollection.Join(Table, FieldJoin, FieldJoinWith: string): TOlfeiCollection;
708 | begin
709 | if QueryString = '' then
710 | QueryString := 'LEFT JOIN ' + FDB.Quote + Table + FDB.Quote + ' ON ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + FieldJoinWith + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FieldJoin + FDB.Quote + ' '
711 | else
712 | QueryString := QueryString + 'LEFT JOIN ' + FDB.Quote + Table + FDB.Quote + ' ON ' + FDB.Quote + Table + FDB.Quote + '.' + FDB.Quote + FieldJoinWith + FDB.Quote + ' = ' + FDB.Quote + FTable + FDB.Quote + '.' + FDB.Quote + FieldJoin + FDB.Quote + ' ';
713 |
714 | Result := Self;
715 | end;
716 |
717 | procedure TOlfeiCollection.Truncate;
718 | begin
719 | FDB.RunSQL('DELETE FROM ' + FDB.Quote + FTable + FDB.Quote);
720 |
721 | if FDB.Driver = 'sqlite' then
722 | FDB.RunSQL('DELETE FROM ' + FDB.Quote + 'sqlite_sequence' + FDB.Quote + ' WHERE name = "' + FTable + '"');
723 |
724 | if FDB.Driver = 'mysql' then
725 | FDB.RunSQL('ALTER TABLE' + FDB.Quote + FTable + FDB.Quote + ' '+ 'AUTO_INCREMENT = 1');
726 | end;
727 |
728 | procedure TOlfeiCollection.Clear;
729 | var
730 | i: integer;
731 | begin
732 | for i := Length(Elements) - 1 downto 0 do
733 | T(Elements[i]).Free;
734 |
735 | SetLength(Elements, 0);
736 | end;
737 |
738 | end.
739 |
--------------------------------------------------------------------------------
/Tools/SchemaGenerator/SchemaGenerator.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {9C4C04CF-B56A-42DB-997A-12D8B4615D50}
4 | 18.6
5 | None
6 | SchemaGenerator.dpr
7 | True
8 | Release
9 | Win32
10 | 1
11 | Console
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Base
34 | true
35 |
36 |
37 | true
38 | Base
39 | true
40 |
41 |
42 | true
43 | Base
44 | true
45 |
46 |
47 | true
48 | Base
49 | true
50 |
51 |
52 | true
53 | Base
54 | true
55 |
56 |
57 | true
58 | Cfg_1
59 | true
60 | true
61 |
62 |
63 | true
64 | Base
65 | true
66 |
67 |
68 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
69 | SchemaGenerator
70 | .\$(Platform)\$(Config)
71 | .\$(Platform)\$(Config)
72 | false
73 | false
74 | false
75 | false
76 | false
77 |
78 |
79 | DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;FrameViewerXE6;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
80 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
81 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
82 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
83 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
84 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
85 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
86 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
87 | android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar
88 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
89 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
90 |
91 |
92 | DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)
93 |
94 |
95 | DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)
96 |
97 |
98 | DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)
99 |
100 |
101 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)
102 | true
103 |
104 |
105 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
106 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
107 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
108 | 1033
109 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
110 | Debug
111 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;frx24;vclib;FireDACDBXDriver;dbexpress;IndyCore;tmsexdXE10;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;CPortLibDXE;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;acntDX10Berlin_R;tmsxlsdXE10;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;TMSCloudPkgDXE10;soaprtl;DbxCommonDriver;ibxpress;Tee;FrameViewerXE6;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;frxTee24;CustomIPTransport;vcldsnap;TMSFMXPackPkgDXE10;bindcomp;appanalytics;DBXInformixDriver;tmswizdXE10;IndyIPClient;EurekaLogCore;bindcompvcl;TeeUI;frxe24;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;frxDB24;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;tmsdXE10;fmxase;$(DCC_UsePackage)
112 | true
113 |
114 |
115 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
116 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
117 | true
118 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;FrameViewerXE6;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)
119 |
120 |
121 | DEBUG;$(DCC_Define)
122 | true
123 | false
124 | true
125 | true
126 | true
127 |
128 |
129 | false
130 |
131 |
132 | false
133 | RELEASE;$(DCC_Define)
134 | 0
135 | 0
136 |
137 |
138 |
139 | MainSource
140 |
141 |
142 | Cfg_2
143 | Base
144 |
145 |
146 | Base
147 |
148 |
149 | Cfg_1
150 | Base
151 |
152 |
153 |
154 | Delphi.Personality.12
155 | Application
156 |
157 |
158 |
159 | SchemaGenerator.dpr
160 |
161 |
162 |
163 |
164 |
165 | true
166 |
167 |
168 |
169 |
170 | SchemaGenerator.exe
171 | true
172 |
173 |
174 |
175 |
176 | true
177 |
178 |
179 |
180 |
181 | true
182 |
183 |
184 |
185 |
186 | true
187 |
188 |
189 |
190 |
191 | true
192 |
193 |
194 |
195 |
196 | true
197 |
198 |
199 |
200 |
201 | 1
202 |
203 |
204 | Contents\MacOS
205 | 1
206 |
207 |
208 | 0
209 |
210 |
211 |
212 |
213 | classes
214 | 1
215 |
216 |
217 |
218 |
219 | res\xml
220 | 1
221 |
222 |
223 |
224 |
225 | library\lib\armeabi-v7a
226 | 1
227 |
228 |
229 |
230 |
231 | library\lib\armeabi
232 | 1
233 |
234 |
235 |
236 |
237 | library\lib\mips
238 | 1
239 |
240 |
241 |
242 |
243 | library\lib\armeabi-v7a
244 | 1
245 |
246 |
247 |
248 |
249 | res\drawable
250 | 1
251 |
252 |
253 |
254 |
255 | res\values
256 | 1
257 |
258 |
259 |
260 |
261 | res\values-v21
262 | 1
263 |
264 |
265 |
266 |
267 | res\drawable
268 | 1
269 |
270 |
271 |
272 |
273 | res\drawable-xxhdpi
274 | 1
275 |
276 |
277 |
278 |
279 | res\drawable-ldpi
280 | 1
281 |
282 |
283 |
284 |
285 | res\drawable-mdpi
286 | 1
287 |
288 |
289 |
290 |
291 | res\drawable-hdpi
292 | 1
293 |
294 |
295 |
296 |
297 | res\drawable-xhdpi
298 | 1
299 |
300 |
301 |
302 |
303 | res\drawable-small
304 | 1
305 |
306 |
307 |
308 |
309 | res\drawable-normal
310 | 1
311 |
312 |
313 |
314 |
315 | res\drawable-large
316 | 1
317 |
318 |
319 |
320 |
321 | res\drawable-xlarge
322 | 1
323 |
324 |
325 |
326 |
327 | 1
328 |
329 |
330 | Contents\MacOS
331 | 1
332 |
333 |
334 | 0
335 |
336 |
337 |
338 |
339 | Contents\MacOS
340 | 1
341 | .framework
342 |
343 |
344 | Contents\MacOS
345 | 1
346 | .framework
347 |
348 |
349 | 0
350 |
351 |
352 |
353 |
354 | 1
355 | .dylib
356 |
357 |
358 | 1
359 | .dylib
360 |
361 |
362 | 1
363 | .dylib
364 |
365 |
366 | Contents\MacOS
367 | 1
368 | .dylib
369 |
370 |
371 | Contents\MacOS
372 | 1
373 | .dylib
374 |
375 |
376 | 0
377 | .dll;.bpl
378 |
379 |
380 |
381 |
382 | 1
383 | .dylib
384 |
385 |
386 | 1
387 | .dylib
388 |
389 |
390 | 1
391 | .dylib
392 |
393 |
394 | Contents\MacOS
395 | 1
396 | .dylib
397 |
398 |
399 | Contents\MacOS
400 | 1
401 | .dylib
402 |
403 |
404 | 0
405 | .bpl
406 |
407 |
408 |
409 |
410 | 0
411 |
412 |
413 | 0
414 |
415 |
416 | 0
417 |
418 |
419 | 0
420 |
421 |
422 | Contents\Resources\StartUp\
423 | 0
424 |
425 |
426 | Contents\Resources\StartUp\
427 | 0
428 |
429 |
430 | 0
431 |
432 |
433 |
434 |
435 | 1
436 |
437 |
438 | 1
439 |
440 |
441 | 1
442 |
443 |
444 |
445 |
446 | 1
447 |
448 |
449 | 1
450 |
451 |
452 | 1
453 |
454 |
455 |
456 |
457 | 1
458 |
459 |
460 | 1
461 |
462 |
463 | 1
464 |
465 |
466 |
467 |
468 | 1
469 |
470 |
471 | 1
472 |
473 |
474 | 1
475 |
476 |
477 |
478 |
479 | 1
480 |
481 |
482 | 1
483 |
484 |
485 | 1
486 |
487 |
488 |
489 |
490 | 1
491 |
492 |
493 | 1
494 |
495 |
496 | 1
497 |
498 |
499 |
500 |
501 | 1
502 |
503 |
504 | 1
505 |
506 |
507 | 1
508 |
509 |
510 |
511 |
512 | 1
513 |
514 |
515 |
516 |
517 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
518 | 1
519 |
520 |
521 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
522 | 1
523 |
524 |
525 |
526 |
527 | 1
528 |
529 |
530 | 1
531 |
532 |
533 |
534 |
535 | ..\
536 | 1
537 |
538 |
539 | ..\
540 | 1
541 |
542 |
543 |
544 |
545 | 1
546 |
547 |
548 | 1
549 |
550 |
551 | 1
552 |
553 |
554 |
555 |
556 | 1
557 |
558 |
559 | 1
560 |
561 |
562 | 1
563 |
564 |
565 |
566 |
567 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
568 | 1
569 |
570 |
571 |
572 |
573 | ..\
574 | 1
575 |
576 |
577 | ..\
578 | 1
579 |
580 |
581 |
582 |
583 | Contents
584 | 1
585 |
586 |
587 | Contents
588 | 1
589 |
590 |
591 |
592 |
593 | Contents\Resources
594 | 1
595 |
596 |
597 | Contents\Resources
598 | 1
599 |
600 |
601 |
602 |
603 | library\lib\armeabi-v7a
604 | 1
605 |
606 |
607 | 1
608 |
609 |
610 | 1
611 |
612 |
613 | 1
614 |
615 |
616 | 1
617 |
618 |
619 | Contents\MacOS
620 | 1
621 |
622 |
623 | Contents\MacOS
624 | 1
625 |
626 |
627 | 0
628 |
629 |
630 |
631 |
632 | 1
633 |
634 |
635 | 1
636 |
637 |
638 |
639 |
640 | Assets
641 | 1
642 |
643 |
644 | Assets
645 | 1
646 |
647 |
648 |
649 |
650 | Assets
651 | 1
652 |
653 |
654 | Assets
655 | 1
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 | False
670 | False
671 | False
672 | False
673 | False
674 | False
675 | True
676 | False
677 |
678 |
679 | 12
680 |
681 |
682 |
683 |
684 |
685 |
--------------------------------------------------------------------------------