1 | unit DbEngine;
|
---|
2 |
|
---|
3 | interface
|
---|
4 |
|
---|
5 | uses
|
---|
6 | Classes, SysUtils, ExtCtrls, Dialogs, USqlDatabase, RegistryEx, Generics,
|
---|
7 | Generics.Collections;
|
---|
8 |
|
---|
9 | type
|
---|
10 | TTable = class;
|
---|
11 | TDbClientType = class;
|
---|
12 | TDbClient = class;
|
---|
13 | TDataType = class;
|
---|
14 | TDbManager = class;
|
---|
15 |
|
---|
16 | TFieldType = (ftString, ftInteger, ftDateTime, ftBoolean, ftFloat, ftImage,
|
---|
17 | ftDate, ftTime, ftMapPosition, ftReference);
|
---|
18 |
|
---|
19 | { TValue }
|
---|
20 |
|
---|
21 | TValue = class
|
---|
22 | procedure Assign(Source: TValue); virtual;
|
---|
23 | function GetString: string; virtual;
|
---|
24 | procedure SetString(Value: string); virtual;
|
---|
25 | function GetStringSQL: string; virtual;
|
---|
26 | procedure SetStringSQL(Value: string); virtual;
|
---|
27 | end;
|
---|
28 |
|
---|
29 | TValueClass = class of TValue;
|
---|
30 |
|
---|
31 | { TValues }
|
---|
32 |
|
---|
33 | TValues = class(TObjectList<TValue>)
|
---|
34 | procedure Assign(Source: TValues);
|
---|
35 | end;
|
---|
36 |
|
---|
37 | { TFieldTypeSpecific }
|
---|
38 |
|
---|
39 | TFieldTypeSpecific = class
|
---|
40 | procedure Assign(Source: TFieldTypeSpecific); virtual;
|
---|
41 | function GetValueClass: TValueClass; virtual;
|
---|
42 | end;
|
---|
43 |
|
---|
44 | TFieldTypeSpecificClass = class of TFieldTypeSpecific;
|
---|
45 |
|
---|
46 | { TField }
|
---|
47 |
|
---|
48 | TField = class
|
---|
49 | private
|
---|
50 | FDataType: TDataType;
|
---|
51 | procedure SetDataType(AValue: TDataType);
|
---|
52 | public
|
---|
53 | Name: string;
|
---|
54 | TypeRelated: TFieldTypeSpecific;
|
---|
55 | Required: Boolean;
|
---|
56 | ReadOnly: Boolean;
|
---|
57 | TextBefore: string;
|
---|
58 | TextAfter: string;
|
---|
59 | Description: string;
|
---|
60 | AllowNull: string;
|
---|
61 | Pos: TPoint;
|
---|
62 | Size: TPoint;
|
---|
63 | Table: TTable;
|
---|
64 | procedure Assign(Source: TField);
|
---|
65 | function GetValueClass: TValueClass;
|
---|
66 | property DataType: TDataType read FDataType write SetDataType;
|
---|
67 | constructor Create;
|
---|
68 | destructor Destroy; override;
|
---|
69 | end;
|
---|
70 |
|
---|
71 | { TFields }
|
---|
72 |
|
---|
73 | TFields = class(TObjectList<TField>)
|
---|
74 | Table: TTable;
|
---|
75 | function SearchByName(Name: string): TField;
|
---|
76 | procedure Assign(Source: TFields);
|
---|
77 | function AddNew(Name: string; DataType: TDataType): TField;
|
---|
78 | procedure Load;
|
---|
79 | end;
|
---|
80 |
|
---|
81 | { TRecord }
|
---|
82 |
|
---|
83 | TRecord = class
|
---|
84 | Table: TTable;
|
---|
85 | Values: TValues;
|
---|
86 | function Match(AValues: TStrings): Boolean;
|
---|
87 | procedure InitValues;
|
---|
88 | procedure Assign(Source: TRecord);
|
---|
89 | constructor Create;
|
---|
90 | destructor Destroy; override;
|
---|
91 | end;
|
---|
92 |
|
---|
93 | { TRecords }
|
---|
94 |
|
---|
95 | TRecords = class(TObjectList<TRecord>)
|
---|
96 | Table: TTable;
|
---|
97 | procedure Assign(Source: TRecords);
|
---|
98 | function SearchByValue(Name, Value: string): TRecord;
|
---|
99 | function SearchByValues(Values: TStrings): TRecord;
|
---|
100 | function AddNew: TRecord;
|
---|
101 | procedure Load;
|
---|
102 | end;
|
---|
103 |
|
---|
104 | { TTable }
|
---|
105 |
|
---|
106 | TTable = class
|
---|
107 | Id: Integer;
|
---|
108 | Name: string;
|
---|
109 | Caption: string;
|
---|
110 | Records: TRecords;
|
---|
111 | Fields: TFields;
|
---|
112 | DbClient: TDbClient;
|
---|
113 | RecordsCount: Integer;
|
---|
114 | procedure LoadRecordsCount;
|
---|
115 | procedure Assign(Source: TTable);
|
---|
116 | constructor Create;
|
---|
117 | destructor Destroy; override;
|
---|
118 | end;
|
---|
119 |
|
---|
120 | { TTables }
|
---|
121 |
|
---|
122 | TTables = class(TObjectList<TTable>)
|
---|
123 | DbClient: TDbClient;
|
---|
124 | function SearchByName(Name: string): TTable;
|
---|
125 | function AddNew(Name: string): TTable;
|
---|
126 | end;
|
---|
127 |
|
---|
128 | { TDbConnectParams }
|
---|
129 |
|
---|
130 | TDbConnectParams = class
|
---|
131 | protected
|
---|
132 | FConnectionString: string;
|
---|
133 | function GetConnectionString: string; virtual;
|
---|
134 | procedure SetConnectionString(AValue: string); virtual;
|
---|
135 | public
|
---|
136 | property ConnectionString: string read GetConnectionString
|
---|
137 | write SetConnectionString;
|
---|
138 | end;
|
---|
139 |
|
---|
140 | TDbConnectParamsClass = class of TDbConnectParams;
|
---|
141 |
|
---|
142 | { TDbConnectProfile }
|
---|
143 |
|
---|
144 | TDbConnectProfile = class
|
---|
145 | private
|
---|
146 | FClientType: TDbClientType;
|
---|
147 | procedure SetClientType(AValue: TDbClientType);
|
---|
148 | public
|
---|
149 | Name: string;
|
---|
150 | Params: TDbConnectParams;
|
---|
151 | DbManager: TDbManager;
|
---|
152 | destructor Destroy; override;
|
---|
153 | function GetClient: TDbClient;
|
---|
154 | property ClientType: TDbClientType read FClientType write SetClientType;
|
---|
155 | end;
|
---|
156 |
|
---|
157 | { TDbConnectProfiles }
|
---|
158 |
|
---|
159 | TDbConnectProfiles = class(TObjectList<TDbConnectProfile>)
|
---|
160 | DbManager: TDbManager;
|
---|
161 | procedure LoadFromRegistry(Context: TRegistryContext);
|
---|
162 | procedure SaveToRegistry(Context: TRegistryContext);
|
---|
163 | function SearchByName(Name: string): TDbConnectProfile;
|
---|
164 | end;
|
---|
165 |
|
---|
166 | { TDataType }
|
---|
167 |
|
---|
168 | TDataType = class
|
---|
169 | Id: Integer;
|
---|
170 | Name: string;
|
---|
171 | Title: string;
|
---|
172 | FieldType: TFieldType;
|
---|
173 | FieldTypeClass: TFieldTypeSpecificClass;
|
---|
174 | end;
|
---|
175 |
|
---|
176 | { TDataTypes }
|
---|
177 |
|
---|
178 | TDataTypes = class(TObjectList<TDataType>)
|
---|
179 | function RegisterType(Id: Integer; Name, Title: string;
|
---|
180 | FieldType: TFieldType; FieldTypeClass: TFieldTypeSpecificClass): TDataType;
|
---|
181 | function SearchByType(FieldType: TFieldType): TDataType;
|
---|
182 | function SearchByName(Name: string): TDataType;
|
---|
183 | end;
|
---|
184 |
|
---|
185 | TDbRows = USqlDatabase.TDbRows;
|
---|
186 |
|
---|
187 | { TDbClient }
|
---|
188 |
|
---|
189 | TDbClient = class
|
---|
190 | private
|
---|
191 | function GetClientType: TDbClientType;
|
---|
192 | protected
|
---|
193 | FConnectProfile: TDbConnectProfile;
|
---|
194 | procedure SetConnectProfile(AValue: TDbConnectProfile); virtual;
|
---|
195 | public
|
---|
196 | DbManager: TDbManager;
|
---|
197 | procedure Query(Text: string; DbRows: TDbRows = nil); virtual;
|
---|
198 | constructor Create; virtual;
|
---|
199 | procedure Load; virtual;
|
---|
200 | procedure Save; virtual;
|
---|
201 | property ClientType: TDbClientType read GetClientType;
|
---|
202 | property ConnectProfile: TDbConnectProfile read FConnectProfile
|
---|
203 | write SetConnectProfile;
|
---|
204 | end;
|
---|
205 |
|
---|
206 | TDbClientClass = class of TDbClient;
|
---|
207 |
|
---|
208 | TFieldTypeSet = set of TFieldType;
|
---|
209 |
|
---|
210 | { TDbClientType }
|
---|
211 |
|
---|
212 | TDbClientType = class
|
---|
213 | Name: string;
|
---|
214 | DataTypes: TDataTypes;
|
---|
215 | DatabaseClientClass: TDbClientClass;
|
---|
216 | ConnectParmasClass: TDbConnectParamsClass;
|
---|
217 | procedure UseTypes(ADataTypes: TDataTypes; Types: TFieldTypeSet);
|
---|
218 | constructor Create;
|
---|
219 | destructor Destroy; override;
|
---|
220 | end;
|
---|
221 |
|
---|
222 | { TDbClientTypes }
|
---|
223 |
|
---|
224 | TDbClientTypes = class(TObjectList<TDbClientType>)
|
---|
225 | function RegisterClientType(Name: string; DatabaseClass: TDbClientClass;
|
---|
226 | ConnectParamsClass: TDbConnectParamsClass): TDbClientType;
|
---|
227 | function FindByName(Name: string): TDbClientType;
|
---|
228 | end;
|
---|
229 |
|
---|
230 | TPreferences = class
|
---|
231 | RememberDatabase: Boolean;
|
---|
232 | LastDatabaseName: string;
|
---|
233 | end;
|
---|
234 |
|
---|
235 | { TDbManager }
|
---|
236 |
|
---|
237 | TDbManager = class
|
---|
238 | private
|
---|
239 | procedure InitClientTypes;
|
---|
240 | procedure InitDataTypes;
|
---|
241 | public
|
---|
242 | ConnectProfiles: TDbConnectProfiles;
|
---|
243 | ClientTypes: TDbClientTypes;
|
---|
244 | DataTypes: TDataTypes;
|
---|
245 | constructor Create;
|
---|
246 | destructor Destroy; override;
|
---|
247 | end;
|
---|
248 |
|
---|
249 | resourcestring
|
---|
250 | STypeString = 'String';
|
---|
251 | STypeInteger = 'Integer';
|
---|
252 | STypeFloat = 'Float';
|
---|
253 | STypeBoolean = 'Boolean';
|
---|
254 | STypeMapPosition = 'Map position';
|
---|
255 | STypeImage = 'Image';
|
---|
256 | STypeDate = 'Date';
|
---|
257 | STypeTime = 'Time';
|
---|
258 | STypeDateTime = 'Date and time';
|
---|
259 | STypeReference = 'Reference';
|
---|
260 | SFieldNotFound = 'Field %s not found';
|
---|
261 |
|
---|
262 |
|
---|
263 | implementation
|
---|
264 |
|
---|
265 | uses
|
---|
266 | DataTypes, EngineXML, EngineMySQL, EngineSQLite, EngineRegistry;
|
---|
267 |
|
---|
268 | { TDbManager }
|
---|
269 |
|
---|
270 | procedure TDbManager.InitClientTypes;
|
---|
271 | var
|
---|
272 | ClientType: TDbClientType;
|
---|
273 | begin
|
---|
274 | ClientTypes.Clear;
|
---|
275 |
|
---|
276 | ClientType := ClientTypes.RegisterClientType('XML file', TDatabaseXML, TDbConnectParamsXml);
|
---|
277 | ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat]);
|
---|
278 |
|
---|
279 | ClientType := ClientTypes.RegisterClientType('MySQL', TDatabaseMySQL, TDbConnectParamsMySql);
|
---|
280 | ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat,
|
---|
281 | ftReference]);
|
---|
282 |
|
---|
283 | ClientType := ClientTypes.RegisterClientType('SQLite', TDatabaseSQLite, TDbConnectParamsSqlite);
|
---|
284 | ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat]);
|
---|
285 |
|
---|
286 | ClientType := ClientTypes.RegisterClientType('Registry', TDbClientRegistry, TDbConnectParamsRegistry);
|
---|
287 | ClientType.UseTypes(DataTypes, [ftString, ftInteger]);
|
---|
288 | end;
|
---|
289 |
|
---|
290 | procedure TDbManager.InitDataTypes;
|
---|
291 | begin
|
---|
292 | DataTypes.Clear;
|
---|
293 | with DataTypes do begin
|
---|
294 | RegisterType(1, 'String', STypeString, ftString, TFieldString);
|
---|
295 | RegisterType(2, 'Integer', STypeInteger, ftInteger, TFieldInteger);
|
---|
296 | RegisterType(3, 'DateTime', STypeDateTime, ftDateTime, TFieldDateTime);
|
---|
297 | RegisterType(4, 'Boolean', STypeBoolean, ftBoolean, TFieldBoolean);
|
---|
298 | RegisterType(5, 'Float', STypeFloat, ftFloat, TFieldFloat);
|
---|
299 | RegisterType(6, 'MapPosition', STypeMapPosition, ftMapPosition, TFieldMapPosition);
|
---|
300 | RegisterType(7, 'Date', STypeDate, ftDate, TFieldDate);
|
---|
301 | RegisterType(8, 'Time', STypeTime, ftTime, TFieldTime);
|
---|
302 | RegisterType(9, 'Image', STypeImage, ftImage, TFieldImage);
|
---|
303 | RegisterType(10, 'Reference', STypeReference, ftReference, TFieldReference);
|
---|
304 | end;
|
---|
305 | end;
|
---|
306 |
|
---|
307 | constructor TDbManager.Create;
|
---|
308 | begin
|
---|
309 | ConnectProfiles := TDbConnectProfiles.Create;
|
---|
310 | ConnectProfiles.DbManager := Self;
|
---|
311 | ClientTypes := TDbClientTypes.Create;
|
---|
312 | DataTypes := TDataTypes.Create;
|
---|
313 | InitDataTypes;
|
---|
314 | InitClientTypes;
|
---|
315 | end;
|
---|
316 |
|
---|
317 | destructor TDbManager.Destroy;
|
---|
318 | begin
|
---|
319 | FreeAndNil(DataTypes);
|
---|
320 | FreeAndNil(ClientTypes);
|
---|
321 | FreeAndNil(ConnectProfiles);
|
---|
322 | inherited;
|
---|
323 | end;
|
---|
324 |
|
---|
325 | { TDbConnectParams }
|
---|
326 |
|
---|
327 | procedure TDbConnectParams.SetConnectionString(AValue: string);
|
---|
328 | begin
|
---|
329 | if FConnectionString = AValue then Exit;
|
---|
330 | FConnectionString := AValue;
|
---|
331 | end;
|
---|
332 |
|
---|
333 | function TDbConnectParams.GetConnectionString: string;
|
---|
334 | begin
|
---|
335 | Result := FConnectionString;
|
---|
336 | end;
|
---|
337 |
|
---|
338 | { TDbConnectProfiles }
|
---|
339 |
|
---|
340 | procedure TDbConnectProfiles.LoadFromRegistry(Context: TRegistryContext);
|
---|
341 | var
|
---|
342 | I: Integer;
|
---|
343 | ConnectProfile: TDbConnectProfile;
|
---|
344 | ClientType: TDbClientType;
|
---|
345 | begin
|
---|
346 | with TRegistryEx.Create do
|
---|
347 | try
|
---|
348 | CurrentContext := Context;
|
---|
349 | Count := ReadIntegerWithDefault('Count', 0);
|
---|
350 | for I := 0 to Count - 1 do begin
|
---|
351 | OpenKey(Context.Key + '\Item' + IntToStr(I), True);
|
---|
352 | ClientType := DbManager.ClientTypes.FindByName(ReadStringWithDefault('ClientType', ''));
|
---|
353 | if not Assigned(ClientType) and (DbManager.ClientTypes.Count > 0) then
|
---|
354 | ClientType := TDbClientType(DbManager.ClientTypes[0]);
|
---|
355 |
|
---|
356 | ConnectProfile := TDbConnectProfile.Create;
|
---|
357 | ConnectProfile.DbManager := DbManager;
|
---|
358 | ConnectProfile.ClientType := ClientType;
|
---|
359 | ConnectProfile.Name := ReadStringWithDefault('Name', '');
|
---|
360 | ConnectProfile.Params.ConnectionString := ReadStringWithDefault('ConnectionString', '');
|
---|
361 | Items[I] := ConnectProfile;
|
---|
362 | end;
|
---|
363 | finally
|
---|
364 | Free;
|
---|
365 | end;
|
---|
366 | end;
|
---|
367 |
|
---|
368 | procedure TDbConnectProfiles.SaveToRegistry(Context: TRegistryContext);
|
---|
369 | var
|
---|
370 | I: Integer;
|
---|
371 | begin
|
---|
372 | with TRegistryEx.Create do
|
---|
373 | try
|
---|
374 | CurrentContext := Context;
|
---|
375 | ReadIntegerWithDefault('Count', Count);
|
---|
376 | for I := 0 to Count - 1 do begin
|
---|
377 | OpenKey(Context.Key + '\Item' + IntToStr(I), True);
|
---|
378 | WriteString('Name', Items[I].Name);
|
---|
379 | WriteString('ConnectionString', Items[I].Params.ConnectionString);
|
---|
380 | WriteString('ClientType', Items[I].ClientType.Name);
|
---|
381 | end;
|
---|
382 | finally
|
---|
383 | Free;
|
---|
384 | end;
|
---|
385 | end;
|
---|
386 |
|
---|
387 | function TDbConnectProfiles.SearchByName(Name: string): TDbConnectProfile;
|
---|
388 | var
|
---|
389 | I: Integer;
|
---|
390 | begin
|
---|
391 | I := 0;
|
---|
392 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
---|
393 | if (I < Count) then Result := Items[I]
|
---|
394 | else Result := nil;
|
---|
395 | end;
|
---|
396 |
|
---|
397 | { TDbConnectProfile }
|
---|
398 |
|
---|
399 | procedure TDbConnectProfile.SetClientType(AValue: TDbClientType);
|
---|
400 | begin
|
---|
401 | if FClientType = AValue then Exit;
|
---|
402 | if Assigned(FClientType) then begin
|
---|
403 | FreeAndNil(Params);
|
---|
404 | end;
|
---|
405 | FClientType := AValue;
|
---|
406 | if Assigned(FClientType) then begin
|
---|
407 | Params := FClientType.ConnectParmasClass.Create;
|
---|
408 | end;
|
---|
409 | end;
|
---|
410 |
|
---|
411 | destructor TDbConnectProfile.Destroy;
|
---|
412 | begin
|
---|
413 | ClientType := nil;
|
---|
414 | if Assigned(Params) then Params.Free;
|
---|
415 | inherited;
|
---|
416 | end;
|
---|
417 |
|
---|
418 | function TDbConnectProfile.GetClient: TDbClient;
|
---|
419 | begin
|
---|
420 | Result := ClientType.DatabaseClientClass.Create;
|
---|
421 | Result.ConnectProfile := Self;
|
---|
422 | Result.DbManager := DbManager;
|
---|
423 | end;
|
---|
424 |
|
---|
425 | { TTables }
|
---|
426 |
|
---|
427 | function TTables.SearchByName(Name: string): TTable;
|
---|
428 | var
|
---|
429 | I: Integer;
|
---|
430 | begin
|
---|
431 | I := 0;
|
---|
432 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
---|
433 | if I < Count then Result := Items[I]
|
---|
434 | else Result := nil;
|
---|
435 | end;
|
---|
436 |
|
---|
437 | function TTables.AddNew(Name: string): TTable;
|
---|
438 | begin
|
---|
439 | Result := TTable.Create;
|
---|
440 | Result.DbClient := DbClient;
|
---|
441 | Result.Name := Name;
|
---|
442 | Add(Result);
|
---|
443 | end;
|
---|
444 |
|
---|
445 | { TDbClient }
|
---|
446 |
|
---|
447 | function TDbClient.GetClientType: TDbClientType;
|
---|
448 | begin
|
---|
449 | Result := FConnectProfile.ClientType;
|
---|
450 | end;
|
---|
451 |
|
---|
452 | procedure TDbClient.SetConnectProfile(AValue: TDbConnectProfile);
|
---|
453 | begin
|
---|
454 | if FConnectProfile = AValue then Exit;
|
---|
455 | FConnectProfile := AValue;
|
---|
456 | end;
|
---|
457 |
|
---|
458 | procedure TDbClient.Query(Text: string; DbRows: TDbRows = nil);
|
---|
459 | begin
|
---|
460 | end;
|
---|
461 |
|
---|
462 | constructor TDbClient.Create;
|
---|
463 | begin
|
---|
464 | inherited;
|
---|
465 | end;
|
---|
466 |
|
---|
467 | procedure TDbClient.Load;
|
---|
468 | begin
|
---|
469 | end;
|
---|
470 |
|
---|
471 | procedure TDbClient.Save;
|
---|
472 | begin
|
---|
473 | end;
|
---|
474 |
|
---|
475 | { TDbClientTypes }
|
---|
476 |
|
---|
477 | function TDbClientTypes.RegisterClientType(Name: string;
|
---|
478 | DatabaseClass: TDbClientClass; ConnectParamsClass: TDbConnectParamsClass): TDbClientType;
|
---|
479 | begin
|
---|
480 | Result := TDbClientType.Create;
|
---|
481 | Result.Name := Name;
|
---|
482 | Result.DatabaseClientClass := DatabaseClass;
|
---|
483 | Result.ConnectParmasClass := ConnectParamsClass;
|
---|
484 | Add(Result);
|
---|
485 | end;
|
---|
486 |
|
---|
487 | function TDbClientTypes.FindByName(Name: string): TDbClientType;
|
---|
488 | var
|
---|
489 | I: Integer;
|
---|
490 | begin
|
---|
491 | I := 0;
|
---|
492 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
---|
493 | if I < Count then Result := Items[I]
|
---|
494 | else Result := nil;
|
---|
495 | end;
|
---|
496 |
|
---|
497 | { TDataTypes }
|
---|
498 |
|
---|
499 | function TDataTypes.RegisterType(Id: Integer; Name, Title: string;
|
---|
500 | FieldType: TFieldType; FieldTypeClass: TFieldTypeSpecificClass): TDataType;
|
---|
501 | begin
|
---|
502 | Result := TDataType.Create;
|
---|
503 | Result.Id := Id;
|
---|
504 | Result.Name := Name;
|
---|
505 | Result.Title := Title;
|
---|
506 | Result.FieldType := FieldType;
|
---|
507 | Result.FieldTypeClass := FieldTypeClass;
|
---|
508 | Add(Result);
|
---|
509 | end;
|
---|
510 |
|
---|
511 | function TDataTypes.SearchByType(FieldType: TFieldType): TDataType;
|
---|
512 | var
|
---|
513 | I: Integer;
|
---|
514 | begin
|
---|
515 | I := 0;
|
---|
516 | while (I < Count) and (Items[I].FieldType <> FieldType) do Inc(I);
|
---|
517 | if I < Count then Result := Items[I]
|
---|
518 | else Result := nil;
|
---|
519 | end;
|
---|
520 |
|
---|
521 | function TDataTypes.SearchByName(Name: string): TDataType;
|
---|
522 | var
|
---|
523 | I: Integer;
|
---|
524 | begin
|
---|
525 | I := 0;
|
---|
526 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
---|
527 | if I < Count then Result := Items[I]
|
---|
528 | else Result := nil;
|
---|
529 | end;
|
---|
530 |
|
---|
531 | { TDbClientType }
|
---|
532 |
|
---|
533 | procedure TDbClientType.UseTypes(ADataTypes: TDataTypes; Types: TFieldTypeSet);
|
---|
534 | var
|
---|
535 | I: TFieldType;
|
---|
536 | begin
|
---|
537 | DataTypes.Clear;
|
---|
538 | for I := Low(TFieldType) to High(TFieldType) do
|
---|
539 | if I in Types then DataTypes.Add(ADataTypes.SearchByType(I));
|
---|
540 | end;
|
---|
541 |
|
---|
542 | constructor TDbClientType.Create;
|
---|
543 | begin
|
---|
544 | DataTypes := TDataTypes.Create;
|
---|
545 | DataTypes.OwnsObjects := False;
|
---|
546 | end;
|
---|
547 |
|
---|
548 | destructor TDbClientType.Destroy;
|
---|
549 | begin
|
---|
550 | FreeAndNil(DataTypes);
|
---|
551 | inherited;
|
---|
552 | end;
|
---|
553 |
|
---|
554 | { TValues }
|
---|
555 |
|
---|
556 | procedure TValues.Assign(Source: TValues);
|
---|
557 | var
|
---|
558 | I: Integer;
|
---|
559 | OldCount: Integer;
|
---|
560 | begin
|
---|
561 | OldCount := Count;
|
---|
562 | Count := Source.Count;
|
---|
563 | for I := OldCount to Count - 1 do
|
---|
564 | Items[I] := TValueClass(Source.Items[I].ClassType).Create;
|
---|
565 | for I := 0 to Count - 1 do
|
---|
566 | if TValue(Items[I]).ClassType <> Source.Items[I].ClassType then begin
|
---|
567 | Items[I] := TValueClass(Source.Items[I].ClassType).Create;
|
---|
568 | end;
|
---|
569 | for I := 0 to Source.Count - 1 do begin
|
---|
570 | Items[I].Assign(Source.Items[I]);
|
---|
571 | end;
|
---|
572 | end;
|
---|
573 |
|
---|
574 | { TRecords }
|
---|
575 |
|
---|
576 | procedure TRecords.Assign(Source: TRecords);
|
---|
577 | var
|
---|
578 | I: Integer;
|
---|
579 | OldCount: Integer;
|
---|
580 | begin
|
---|
581 | OldCount := Count;
|
---|
582 | Count := Source.Count;
|
---|
583 | for I := OldCount to Count - 1 do
|
---|
584 | Items[I] := TRecord.Create;
|
---|
585 | for I := 0 to Source.Count - 1 do begin
|
---|
586 | Items[I].Assign(Source.Items[I]);
|
---|
587 | end;
|
---|
588 | end;
|
---|
589 |
|
---|
590 | function TRecords.SearchByValue(Name, Value: string): TRecord;
|
---|
591 | var
|
---|
592 | I: Integer;
|
---|
593 | FieldIndex: Integer;
|
---|
594 | Field: TField;
|
---|
595 | begin
|
---|
596 | Result := nil;
|
---|
597 | Field := Table.Fields.SearchByName(Name);
|
---|
598 | if Assigned(Field) then begin
|
---|
599 | FieldIndex := Table.Fields.IndexOf(Field);
|
---|
600 | I := 0;
|
---|
601 | while (I < Count) and (Items[I].Values[FieldIndex].GetString <> Value) do Inc(I);
|
---|
602 | if I < Count then Result := Items[I]
|
---|
603 | else Result := nil;
|
---|
604 | end;
|
---|
605 | end;
|
---|
606 |
|
---|
607 | function TRecords.SearchByValues(Values: TStrings): TRecord;
|
---|
608 | var
|
---|
609 | I: Integer;
|
---|
610 | begin
|
---|
611 | Result := nil;
|
---|
612 | I := 0;
|
---|
613 | while (I < Count) and (Items[I].Match(Values)) do Inc(I);
|
---|
614 | if I < Count then Result := Items[I]
|
---|
615 | else Result := nil;
|
---|
616 | end;
|
---|
617 |
|
---|
618 | function TRecords.AddNew: TRecord;
|
---|
619 | begin
|
---|
620 | Result := TRecord.Create;
|
---|
621 | Result.Table := Table;
|
---|
622 | Result.InitValues;
|
---|
623 | Add(Result);
|
---|
624 | end;
|
---|
625 |
|
---|
626 | procedure TRecords.Load;
|
---|
627 | var
|
---|
628 | DbRows: TDbRows;
|
---|
629 | I: Integer;
|
---|
630 | F: Integer;
|
---|
631 | NewRecord: TRecord;
|
---|
632 | NewValue: TValue;
|
---|
633 | Value: string;
|
---|
634 | begin
|
---|
635 | Clear;
|
---|
636 | DbRows := TDbRows.Create;
|
---|
637 | try
|
---|
638 | Table.DbClient.Query('SELECT * FROM ' + Table.Name, DbRows);
|
---|
639 | for I := 0 to DbRows.Count - 1 do begin
|
---|
640 | NewRecord := TRecord.Create;
|
---|
641 | for F := 0 to Table.Fields.Count - 1 do begin
|
---|
642 | NewValue := Table.Fields[F].GetValueClass.Create;
|
---|
643 | if DbRows[I].TryGetValue(Table.Fields[F].Name, Value) then begin
|
---|
644 | NewValue.SetString(Value);
|
---|
645 | NewRecord.Values.Add(NewValue);
|
---|
646 | end else begin
|
---|
647 | //NewValue.SetString('');
|
---|
648 | NewRecord.Values.Add(NewValue);
|
---|
649 | end;
|
---|
650 | end;
|
---|
651 | Add(NewRecord);
|
---|
652 | end;
|
---|
653 | finally
|
---|
654 | DbRows.Free;
|
---|
655 | end;
|
---|
656 | end;
|
---|
657 |
|
---|
658 | { TFields }
|
---|
659 |
|
---|
660 | function TFields.SearchByName(Name: string): TField;
|
---|
661 | var
|
---|
662 | I: Integer;
|
---|
663 | begin
|
---|
664 | I := 0;
|
---|
665 | while (I < Count) and (Items[I].Name <> Name) do Inc(I);
|
---|
666 | if I < Count then Result := Items[I]
|
---|
667 | else Result := nil;
|
---|
668 | end;
|
---|
669 |
|
---|
670 | procedure TFields.Assign(Source: TFields);
|
---|
671 | var
|
---|
672 | I: Integer;
|
---|
673 | OldCount: Integer;
|
---|
674 | begin
|
---|
675 | OldCount := Count;
|
---|
676 | Count := Source.Count;
|
---|
677 | for I := OldCount to Count - 1 do
|
---|
678 | Items[I] := TField.Create;
|
---|
679 | for I := 0 to Source.Count - 1 do begin
|
---|
680 | Items[I].Assign(Source.Items[I]);
|
---|
681 | end;
|
---|
682 | end;
|
---|
683 |
|
---|
684 | function TFields.AddNew(Name: string; DataType: TDataType): TField;
|
---|
685 | begin
|
---|
686 | Result := TField.Create;
|
---|
687 | Result.Table := Table;
|
---|
688 | Result.Name := Name;
|
---|
689 | Result.DataType := DataType;
|
---|
690 | Add(Result);
|
---|
691 | end;
|
---|
692 |
|
---|
693 | procedure TFields.Load;
|
---|
694 | var
|
---|
695 | DbRows: TDbRows;
|
---|
696 | NewField: TField;
|
---|
697 | I: Integer;
|
---|
698 | begin
|
---|
699 | Clear;
|
---|
700 | DbRows := TDbRows.Create;
|
---|
701 | try
|
---|
702 | Table.DbClient.Query('SELECT * FROM ModelField WHERE Model = ' + Table.Name, DbRows);
|
---|
703 | for I := 0 to DbRows.Count - 1 do begin
|
---|
704 | NewField := AddNew(DbRows[I].Items['Name'],
|
---|
705 | Table.DbClient.DbManager.DataTypes.SearchByName(DbRows[I].Items['DataType']));
|
---|
706 | NewField.TextBefore := DbRows[I].Items['Caption'];
|
---|
707 | end;
|
---|
708 | finally
|
---|
709 | DbRows.Free;
|
---|
710 | end;
|
---|
711 | end;
|
---|
712 |
|
---|
713 | { TRecord }
|
---|
714 |
|
---|
715 | function TRecord.Match(AValues: TStrings): Boolean;
|
---|
716 | var
|
---|
717 | I: Integer;
|
---|
718 | Field: TField;
|
---|
719 | FieldIndex: Integer;
|
---|
720 | begin
|
---|
721 | Result := True;
|
---|
722 | for I := 0 to aValues.Count - 1 do begin
|
---|
723 | Field := Table.Fields.SearchByName(AValues.Names[I]);
|
---|
724 | FieldIndex := Table.Fields.IndexOf(Field);
|
---|
725 | if Assigned(Field) then begin
|
---|
726 | if Values[FieldIndex].GetString <> AValues.ValueFromIndex[I] then begin
|
---|
727 | Result := False;
|
---|
728 | Break;
|
---|
729 | end;
|
---|
730 | end else raise Exception.Create(Format(SFieldNotFound, [AValues.Names[I]]));
|
---|
731 | end;
|
---|
732 | end;
|
---|
733 |
|
---|
734 | procedure TRecord.InitValues;
|
---|
735 | var
|
---|
736 | I: Integer;
|
---|
737 | begin
|
---|
738 | Values.Clear;
|
---|
739 | for I := 0 to Table.Fields.Count - 1 do
|
---|
740 | Values.Add(Table.Fields[I].GetValueClass.Create);
|
---|
741 | end;
|
---|
742 |
|
---|
743 | procedure TRecord.Assign(Source: TRecord);
|
---|
744 | begin
|
---|
745 | Values.Assign(Source.Values);
|
---|
746 | end;
|
---|
747 |
|
---|
748 | constructor TRecord.Create;
|
---|
749 | begin
|
---|
750 | Values := TValues.Create;
|
---|
751 | end;
|
---|
752 |
|
---|
753 | destructor TRecord.Destroy;
|
---|
754 | begin
|
---|
755 | FreeAndNil(Values);
|
---|
756 | inherited;
|
---|
757 | end;
|
---|
758 |
|
---|
759 | { TValue }
|
---|
760 |
|
---|
761 | procedure TValue.Assign(Source: TValue);
|
---|
762 | begin
|
---|
763 | end;
|
---|
764 |
|
---|
765 | function TValue.GetString: string;
|
---|
766 | begin
|
---|
767 | Result := '';
|
---|
768 | end;
|
---|
769 |
|
---|
770 | procedure TValue.SetString(Value: string);
|
---|
771 | begin
|
---|
772 | end;
|
---|
773 |
|
---|
774 | function TValue.GetStringSQL: string;
|
---|
775 | begin
|
---|
776 | Result := '';
|
---|
777 | end;
|
---|
778 |
|
---|
779 | procedure TValue.SetStringSQL(Value: string);
|
---|
780 | begin
|
---|
781 | end;
|
---|
782 |
|
---|
783 | { TFieldTypeSpecific }
|
---|
784 |
|
---|
785 | procedure TFieldTypeSpecific.Assign(Source: TFieldTypeSpecific);
|
---|
786 | begin
|
---|
787 | end;
|
---|
788 |
|
---|
789 | function TFieldTypeSpecific.GetValueClass: TValueClass;
|
---|
790 | begin
|
---|
791 | Result := TValue;
|
---|
792 | end;
|
---|
793 |
|
---|
794 | { TField }
|
---|
795 |
|
---|
796 | procedure TField.SetDataType(AValue: TDataType);
|
---|
797 | begin
|
---|
798 | if FDataType = AValue then Exit;
|
---|
799 | if Assigned(TypeRelated) then TypeRelated.Free;
|
---|
800 | FDataType := AValue;
|
---|
801 | if Assigned(AValue) then
|
---|
802 | TypeRelated := AValue.FieldTypeClass.Create
|
---|
803 | else TypeRelated := nil;
|
---|
804 | end;
|
---|
805 |
|
---|
806 | procedure TField.Assign(Source: TField);
|
---|
807 | begin
|
---|
808 | Name := Source.Name;
|
---|
809 | DataType := Source.DataType;
|
---|
810 | TextAfter := Source.TextAfter;
|
---|
811 | TextBefore := Source.TextBefore;
|
---|
812 | Required := Source.Required;
|
---|
813 | ReadOnly := Source.ReadOnly;
|
---|
814 | Description := Source.Description;
|
---|
815 | AllowNull := Source.AllowNull;
|
---|
816 | TypeRelated.Assign(Source.TypeRelated);
|
---|
817 | end;
|
---|
818 |
|
---|
819 | function TField.GetValueClass: TValueClass;
|
---|
820 | begin
|
---|
821 | if Assigned(TypeRelated) then Result := TypeRelated.GetValueClass
|
---|
822 | else Result := TValue;
|
---|
823 | end;
|
---|
824 |
|
---|
825 | constructor TField.Create;
|
---|
826 | begin
|
---|
827 | TypeRelated := TFieldString.Create;
|
---|
828 | end;
|
---|
829 |
|
---|
830 | destructor TField.Destroy;
|
---|
831 | begin
|
---|
832 | DataType := nil;
|
---|
833 | inherited;
|
---|
834 | end;
|
---|
835 |
|
---|
836 | procedure TTable.LoadRecordsCount;
|
---|
837 | var
|
---|
838 | DbRows: TDbRows;
|
---|
839 | begin
|
---|
840 | Records.Clear;
|
---|
841 | DbRows := TDbRows.Create;
|
---|
842 | try
|
---|
843 | DbClient.Query('SELECT COUNT(*) FROM ' + Name, DbRows);
|
---|
844 | if DbRows.Count = 1 then begin
|
---|
845 | RecordsCount := StrToInt(DbRows[0].Items['COUNT(*)']);
|
---|
846 | end else RecordsCount := 0;
|
---|
847 | finally
|
---|
848 | DbRows.Free;
|
---|
849 | end;
|
---|
850 | end;
|
---|
851 |
|
---|
852 | procedure TTable.Assign(Source: TTable);
|
---|
853 | begin
|
---|
854 | Name := Source.Name;
|
---|
855 | Caption := Source.Caption;
|
---|
856 | Fields.Assign(Source.Fields);
|
---|
857 | Records.Assign(Source.Records);
|
---|
858 | end;
|
---|
859 |
|
---|
860 | constructor TTable.Create;
|
---|
861 | begin
|
---|
862 | Records := TRecords.Create;
|
---|
863 | Records.Table := Self;
|
---|
864 | Fields := TFields.Create;
|
---|
865 | Fields.Table := Self;
|
---|
866 | end;
|
---|
867 |
|
---|
868 | destructor TTable.Destroy;
|
---|
869 | begin
|
---|
870 | FreeAndNil(Fields);
|
---|
871 | FreeAndNil(Records);
|
---|
872 | inherited;
|
---|
873 | end;
|
---|
874 |
|
---|
875 | end.
|
---|
876 |
|
---|