├── .gitignore ├── Core ├── Bin │ ├── MySQL │ │ ├── libmysql.dll │ │ └── libmysql.lib │ └── SQLite │ │ ├── sqlite3.def │ │ └── sqlite3.dll ├── OlfeiCollection.pas ├── OlfeiORM.pas ├── OlfeiPool.pas ├── OlfeiSQL.pas └── OlfeiSchema.pas ├── Demo ├── Collections │ ├── OlfeiImages.pas │ └── OlfeiUsers.pas ├── Migrations │ ├── migration_001_create_users_table.pas │ ├── migration_002_create_test_table.pas │ ├── migration_003_add_seeds_to_test_table.pas │ ├── migration_004_update_price_in_users_table.pas │ ├── migration_005_delete_birthday_from_users_table.pas │ ├── migration_006_create_images_table.pas │ ├── migration_007_drop_index_on_users_table.pas │ ├── migration_008_drop_foreign_on_test_table.pas │ ├── migration_009_add_avatar_to_users_table.pas │ └── migration_010_create_pivot_user_friend_table.pas ├── Models │ ├── OlfeiImage.pas │ ├── OlfeiTest.pas │ └── OlfeiUser.pas ├── ORMDemo.deployproj ├── ORMDemo.dpr ├── ORMDemo.dproj ├── ORMDemo.dproj.local ├── ORMDemo.eof ├── ORMDemo.identcache ├── ORMDemo.res ├── ORMDemo.stat ├── ORMDemoMain.fmx ├── ORMDemoMain.pas ├── ORMDemo_project.tvsconfig ├── SchemaGenerator.exe └── schema.inc ├── Drivers ├── OlfeiDriverMySQL.pas ├── OlfeiDriverSQLite.pas └── OlfeiSQLDriver.pas ├── README.md └── Tools └── SchemaGenerator ├── .gitignore ├── SchemaGenerator.dpr ├── SchemaGenerator.dproj ├── SchemaGenerator.dproj.local ├── SchemaGenerator.identcache ├── SchemaGenerator.res └── SchemaGenerator.stat /.gitignore: -------------------------------------------------------------------------------- 1 | /demo/win32 2 | /demo/android 3 | /bin 4 | AndroidManifest.template.xml 5 | __history 6 | __recovery 7 | *.dcu 8 | *.o -------------------------------------------------------------------------------- /Core/Bin/MySQL/libmysql.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Core/Bin/MySQL/libmysql.dll -------------------------------------------------------------------------------- /Core/Bin/MySQL/libmysql.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Core/Bin/MySQL/libmysql.lib -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Core/Bin/SQLite/sqlite3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Core/Bin/SQLite/sqlite3.dll -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/Migrations/migration_003_add_seeds_to_test_table.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Demo/Migrations/migration_003_add_seeds_to_test_table.pas -------------------------------------------------------------------------------- /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/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_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/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_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_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_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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Demo/ORMDemo.eof: -------------------------------------------------------------------------------- 1 |  2 | [Exception Log] 3 | EurekaLog Version=7007 4 | Activate=0 5 | DeleteMapAfterCompile=0 6 | Encrypt Password="" 7 | 8 | -------------------------------------------------------------------------------- /Demo/ORMDemo.identcache: -------------------------------------------------------------------------------- 1 | JE:\Projects\delphi-orm\Demo\Migrations\migration_002_create_test_table.pasPE:\Projects\delphi-orm\Demo\Migrations\migration_003_add_seeds_to_test_table.pasLE:\Projects\delphi-orm\Demo\Migrations\migration_006_create_images_table.pasRE:\Projects\delphi-orm\Demo\Migrations\migration_007_drop_index_on_users_table.pas7E:\Projects\delphi-orm\Demo\Collections\OlfeiImages.pasSE:\Projects\delphi-orm\Demo\Migrations\migration_008_drop_foreign_on_test_table.pas6E:\Projects\delphi-orm\Demo\Collections\OlfeiUsers.pasKE:\Projects\delphi-orm\Demo\Migrations\migration_001_create_users_table.pas0E:\Projects\delphi-orm\Demo\Models\OlfeiUser.pas0E:\Projects\delphi-orm\Demo\Models\OlfeiTest.pasYE:\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.dpr1E:\Projects\delphi-orm\Demo\Models\OlfeiImage.pasRE:\Projects\delphi-orm\Demo\Migrations\migration_009_add_avatar_to_users_table.pasWE:\Projects\delphi-orm\Demo\Migrations\migration_010_create_pivot_user_friend_table.pasTE:\Projects\delphi-orm\Demo\Migrations\migration_004_update_price_in_users_table.pas -------------------------------------------------------------------------------- /Demo/ORMDemo.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Demo/ORMDemo.res -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Demo/ORMDemo_project.tvsconfig: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Demo/SchemaGenerator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Demo/SchemaGenerator.exe -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Tools/SchemaGenerator/.gitignore: -------------------------------------------------------------------------------- 1 | /win32 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Tools/SchemaGenerator/SchemaGenerator.identcache: -------------------------------------------------------------------------------- 1 | :F:\My\delphi-orm\Tools\SchemaGenerator\SchemaGenerator.dpr -------------------------------------------------------------------------------- /Tools/SchemaGenerator/SchemaGenerator.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlfeiTeam/delphi-orm/1058a4d988060fecd6540beae2080a06c5388336/Tools/SchemaGenerator/SchemaGenerator.res -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------