Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | {1366} ensure MongoDB external ODM storage would create all needed indexes, and also populate the collection with the expected default data |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5bf8ef64b3d99a51b07a3945ae87706d |
User & Date: | ab 2015-05-17 12:02:35 |
2015-05-17
| ||
12:19 | {1367} enhanced MongoDBTests sample to support latest MongoDB 3.0 engine behavior and also added speed statistics about SQL translated queries check-in: 9eaedf3229 user: ab tags: trunk | |
12:02 | {1366} ensure MongoDB external ODM storage would create all needed indexes, and also populate the collection with the expected default data check-in: 5bf8ef64b3 user: ab tags: trunk | |
11:02 | {1365} fixed regression about an unexpected Access Violation error when running /mvc-info URI check-in: 3f2cf172c4 user: ab tags: trunk | |
Changes to SQLite3/Samples/30 - MVC Server/MVCModel.pas.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
{ TSQLAuthor } class procedure TSQLAuthor.InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8; Options: TSQLInitializeTableOptions); var Auth: TSQLAuthor; begin inherited; if FieldName='' then begin // new table -> create default Author Auth := TSQLAuthor.Create; try Auth.LogonName := 'synopse'; Auth.SetPlainPassword('synopse'); Auth.FamilyName := 'Synopse'; Auth.Verified := true; |
| |
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
{ TSQLAuthor }
class procedure TSQLAuthor.InitializeTable(Server: TSQLRestServer;
const FieldName: RawUTF8; Options: TSQLInitializeTableOptions);
var Auth: TSQLAuthor;
begin
inherited InitializeTable(Server,FieldName,Options);
if FieldName='' then begin // new table -> create default Author
Auth := TSQLAuthor.Create;
try
Auth.LogonName := 'synopse';
Auth.SetPlainPassword('synopse');
Auth.FamilyName := 'Synopse';
Auth.Verified := true;
|
Changes to SQLite3/mORMot.pas.
16394 16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 ..... 25594 25595 25596 25597 25598 25599 25600 25601 25602 25603 25604 25605 25606 25607 25608 25609 25610 25611 25612 25613 ..... 32455 32456 32457 32458 32459 32460 32461 32462 32463 32464 32465 32466 32467 32468 32469 32470 32471 32472 32473 32474 32475 32476 32477 |
Select: 'SELECT='; Where: 'WHERE='; SendTotalRowsCountFmt: ''); /// options to specify no index createon for TSQLRestServer.CreateMissingTables // and TSQLRecord.InitializeTable methods INITIALIZETABLE_NOINDEX: TSQLInitializeTableOptions = [itoNoIndex4ID..itoNoIndex4RecordReference]; /// default value of TSQLRestServer.StatLevels property // - i.e. gather all statistics, but mlSessions SERVERDEFAULTMONITORLEVELS: TSQLRestServerMonitorLevels = [mlTables,mlMethods,mlInterfaces,mlSQLite3]; /// wrapper to search for a given TSQLRecord by ID in an array of TSQLRecord ................................................................................ aClient.Retrieve(FormatUTF8(FormatSQLWhere,ParamsSQLWhere,BoundsSQLWhere),self); end; class procedure TSQLRecord.InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8; Options: TSQLInitializeTableOptions); var f: integer; begin // is not part of TSQLRecordProperties because has been declared as virtual if (self<>nil) and (Server<>nil) then begin if not (itoNoIndex4ID in Options) then if (FieldName='') or IsRowID(pointer(FieldName)) then Server.CreateSQLIndex(self,'ID',true); // for external tables with RecordProps do // automatic column indexation of fields which are commonly searched by value for f := 0 to Fields.Count-1 do with Fields.List[f] do if (FieldName='') or IdemPropNameU(FieldName,Name) then if ((aIsUnique in Attributes) and not (itoNoIndex4UniqueField in Options)) or ((SQLFieldType=sftRecord) and not (itoNoIndex4RecordReference in Options)) or ((SQLFieldType=sftRecordVersion) and not (itoNoIndex4RecordVersion in Options)) or ((SQLFieldType=sftID) and not (itoNoIndex4NestedRecord in Options)) or ................................................................................ Props: TSQLRecordProperties; Rest: TSQLRest; begin result := false; if high(FieldNames)<0 then exit; // avoid endless loop for TSQLRestStorage with no overridden method TableIndex := Model.GetTableIndexExisting(Table); if fStaticVirtualTable<>nil then begin Rest := fStaticVirtualTable[TableIndex]; if Rest<>nil then begin if Rest.InheritsFrom(TSQLRestStorage) then // will try to create an index on the static table (e.g. for external DB) result := TSQLRestStorage(Rest). CreateSQLMultiIndex(Table,FieldNames,Unique,IndexName); exit; end; end; if (high(FieldNames)=0) and IsRowID(pointer(FieldNames[0])) then begin result := true; // SQLite3 has always its ID/RowID primary key indexed exit; end; Props := Model.TableProps[TableIndex].Props; for i := 0 to high(FieldNames) do |
| | > > < > | < | | | | | | < |
16394 16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 ..... 25594 25595 25596 25597 25598 25599 25600 25601 25602 25603 25604 25605 25606 25607 25608 25609 25610 25611 25612 25613 25614 25615 ..... 32457 32458 32459 32460 32461 32462 32463 32464 32465 32466 32467 32468 32469 32470 32471 32472 32473 32474 32475 32476 32477 |
Select: 'SELECT='; Where: 'WHERE='; SendTotalRowsCountFmt: ''); /// options to specify no index createon for TSQLRestServer.CreateMissingTables // and TSQLRecord.InitializeTable methods INITIALIZETABLE_NOINDEX: TSQLInitializeTableOptions = [itoNoIndex4ID..itoNoIndex4RecordVersion]; /// default value of TSQLRestServer.StatLevels property // - i.e. gather all statistics, but mlSessions SERVERDEFAULTMONITORLEVELS: TSQLRestServerMonitorLevels = [mlTables,mlMethods,mlInterfaces,mlSQLite3]; /// wrapper to search for a given TSQLRecord by ID in an array of TSQLRecord ................................................................................ aClient.Retrieve(FormatUTF8(FormatSQLWhere,ParamsSQLWhere,BoundsSQLWhere),self); end; class procedure TSQLRecord.InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8; Options: TSQLInitializeTableOptions); var f: integer; begin // is not part of TSQLRecordProperties because has been declared as virtual if (self<>nil) and (Server<>nil) and (Options*INITIALIZETABLE_NOINDEX<>INITIALIZETABLE_NOINDEX) then begin // ensure ID/RowID column is indexed if not (itoNoIndex4ID in Options) then if (FieldName='') or IsRowID(pointer(FieldName)) then Server.CreateSQLIndex(self,'ID',true); // for external tables // automatic column indexation of fields which are commonly searched by value with RecordProps do for f := 0 to Fields.Count-1 do with Fields.List[f] do if (FieldName='') or IdemPropNameU(FieldName,Name) then if ((aIsUnique in Attributes) and not (itoNoIndex4UniqueField in Options)) or ((SQLFieldType=sftRecord) and not (itoNoIndex4RecordReference in Options)) or ((SQLFieldType=sftRecordVersion) and not (itoNoIndex4RecordVersion in Options)) or ((SQLFieldType=sftID) and not (itoNoIndex4NestedRecord in Options)) or ................................................................................ Props: TSQLRecordProperties; Rest: TSQLRest; begin result := false; if high(FieldNames)<0 then exit; // avoid endless loop for TSQLRestStorage with no overridden method TableIndex := Model.GetTableIndexExisting(Table); Rest := GetStaticDataServerOrVirtualTable(TableIndex); if Rest<>nil then begin if Rest.InheritsFrom(TSQLRestStorage) then // will try to create an index on the static table (e.g. for external DB) result := TSQLRestStorage(Rest). CreateSQLMultiIndex(Table,FieldNames,Unique,IndexName); exit; end; if (high(FieldNames)=0) and IsRowID(pointer(FieldNames[0])) then begin result := true; // SQLite3 has always its ID/RowID primary key indexed exit; end; Props := Model.TableProps[TableIndex].Props; for i := 0 to high(FieldNames) do |
Changes to SQLite3/mORMotMongoDB.pas.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 ... 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ... 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 ... 229 230 231 232 233 234 235 236 237 238 239 240 241 242 ... 290 291 292 293 294 295 296 297 298 299 300 301 302 303 ... 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 ... 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 ... 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
fBSONProjectionBlobFields: variant; fBSONProjectionBlobFieldsNames: TRawUTF8DynArray; // multi-thread BATCH process is secured via Lock/UnLock critical section fBatchMethod: TSQLURIMethod; fBatchWriter: TBSONWriter; fBatchIDs: TIDDynArray; fBatchIDsCount: integer; fIndexesCreated: Boolean; function EngineNextID: TID; procedure CreateIndexes; function DocFromJSON(const JSON: RawUTF8; Occasion: TSQLOccasion; var Doc: TDocVariantData): TID; procedure JSONFromDoc(var doc: TDocVariantData; var result: RawUTF8); function BSONProjectionSet(var Projection: variant; WithID: boolean; const Fields: TSQLFieldBits; ExtFieldNames: PRawUTF8DynArray): integer; function GetJSONValues(const Res: TBSONDocument; const extFieldNames: TRawUTF8DynArray; W: TJSONSerializer): integer; ................................................................................ function InternalBatchStart(Method: TSQLURIMethod; BatchOptions: TSQLRestBatchOptions): boolean; override; // internal method called by TSQLRestServer.RunBatch() to process fast // BULK sending to remote MongoDB database procedure InternalBatchStop; override; public /// initialize the direct access to the MongoDB collection // - you should not use this, but rather call StaticMongoDBRegister() // - in practice, just call the other reintroduced constructor, supplying // a TMongoDatabase instance // - will create the indexes // - to initilialize void tables, you can call, after the main database is // launched: // ! aServer.InitializeTables(INITIALIZETABLE_NOINDEX); constructor Create(aClass: TSQLRecordClass; aServer: TSQLRestServer); override; /// release used memory destructor Destroy; override; /// overridden method for one single update call to the MongoDB server function UpdateBlobFields(Value: TSQLRecord): boolean; override; /// overridden method for one single read call to the MongoDB server ................................................................................ // - will associate the supplied class with a MongoDB collection for a // specified MongoDB database // - to be called before Server.CreateMissingTables // - by default, the collection name will match TSQLRecord.SQLTableName, but // you can customize it with the corresponding parameter // - the TSQLRecord.ID (RowID) field is always mapped to MongoDB's _id field // - will call create needed indexes // - you can later call aServer.InitializeTables(INITIALIZETABLE_NOINDEX) to // initialize the void tables (e.g. default TSQLAuthGroup and TSQLAuthUser records) // - after registration, you can tune the field-name mapping by calling // ! aModel.Props[aClass].ExternalDB.MapField(..) // (just a regular external DB as defined in mORMotDB.pas unit) - it may be // a good idea to use short field names on MongoDB side, to reduce the space // used for storage (since they will be embedded within the document data) // - it will return the corresponding TSQLRestStorageMongoDB instance - ................................................................................ mrMapAutoFieldsIntoSmallerLength ); /// set of options for StaticMongoDBRegisterAll/TSQLRestMongoDBCreate functions TStaticMongoDBRegisterOptions = set of TStaticMongoDBRegisterOption; /// create and register ALL classes of a given model to access a MongoDB server // - the collection names will follow the class names function StaticMongoDBRegisterAll(aServer: TSQLRestServer; aMongoDatabase: TMongoDatabase; aOptions: TStaticMongoDBRegisterOptions=[]): boolean; /// create a new TSQLRest instance, possibly using MongoDB for its ORM process // - if aDefinition.Kind matches a TSQLRest registered class, one new instance // of this kind will be created and returned // - if aDefinition.Kind is 'MongoDB', it will instantiate an in-memory ................................................................................ for i := 0 to high(Tables) do if (mrDoNotRegisterUserGroupTables in aOptions) and (Tables[i].InheritsFrom(TSQLAuthGroup) or Tables[i].InheritsFrom(TSQLAuthUser)) then continue else if StaticMongoDBRegister(Tables[i],aServer,aMongoDatabase,'')=nil then result := false; end; function TSQLRestMongoDBCreate(aModel: TSQLModel; aDefinition: TSynConnectionDefinition; aHandleAuthentication: boolean; aOptions: TStaticMongoDBRegisterOptions): TSQLRest; var client: TMongoClient; database: TMongoDatabase; ................................................................................ {$ifdef WITHLOG} fOwner.LogFamily.SynLog.Log(sllInfo,'will store % using %',[aClass,Collection],self); {$endif} BSONProjectionSet(fBSONProjectionSimpleFields,true, fStoredClassRecordProps.SimpleFieldsBits[soSelect],nil); BSONProjectionSet(fBSONProjectionBlobFields,false, fStoredClassRecordProps.FieldBits[sftBlob],@fBSONProjectionBlobFieldsNames); CreateIndexes; end; procedure TSQLRestStorageMongoDB.CreateIndexes; var F: integer; begin fIndexesCreated := true; if IsZero(fIsUnique) then exit; for F := 0 to fStoredClassRecordProps.Fields.Count-1 do if F in fIsUnique then fCollection.EnsureIndex( [fStoredClassProps.ExternalDB.FieldNames[f]],true,true); end; function TSQLRestStorageMongoDB.BSONProjectionSet(var Projection: variant; WithID: boolean; const Fields: TSQLFieldBits; ExtFieldNames: PRawUTF8DynArray): integer; var i,n: integer; W: TBSONWriter; begin ................................................................................ end; end; function TSQLRestStorageMongoDB.CreateSQLMultiIndex( Table: TSQLRecordClass; const FieldNames: array of RawUTF8; Unique: boolean; IndexName: RawUTF8): boolean; begin result := false; if (self=nil) or (fCollection=nil) or (Table<>fStoredClass) then exit; fCollection.EnsureIndex(FieldNames,true,Unique); end; procedure TSQLRestStorageMongoDB.Drop; var DB: TMongoDatabase; CollName: RawUTF8; begin DB := Collection.Database; CollName := Collection.Name; Collection.Drop; fCollection := DB.CollectionOrCreate[CollName]; fEngineLastID := 0; fIndexesCreated := false; end; destructor TSQLRestStorageMongoDB.Destroy; begin inherited; FreeAndNil(fBatchWriter); {$ifdef WITHLOG} ................................................................................ result := fCollection.Count; end; function TSQLRestStorageMongoDB.EngineNextID: TID; procedure ComputeMax_ID; var res: variant; begin if not fIndexesCreated then CreateIndexes; res := fCollection.AggregateDocFromJson('{$group:{_id:null,max:{$max:"$_id"}}}'); if DocVariantType.IsOfType(res) then fEngineLastID := VariantToInt64Def(res.max,0); {$ifdef WITHLOG} fOwner.LogFamily.SynLog.Log(sllInfo,'Computed EngineNextID=%',[fEngineLastID],self); {$endif} end; |
< < | < | < < < < | > > > > < < < < < < < < < < < < < > | < > > > > > | > > > < < < |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 ... 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 ... 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 ... 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 ... 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 ... 331 332 333 334 335 336 337 338 339 340 341 342 343 344 ... 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 ... 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
fBSONProjectionBlobFields: variant; fBSONProjectionBlobFieldsNames: TRawUTF8DynArray; // multi-thread BATCH process is secured via Lock/UnLock critical section fBatchMethod: TSQLURIMethod; fBatchWriter: TBSONWriter; fBatchIDs: TIDDynArray; fBatchIDsCount: integer; function EngineNextID: TID; function DocFromJSON(const JSON: RawUTF8; Occasion: TSQLOccasion; var Doc: TDocVariantData): TID; procedure JSONFromDoc(var doc: TDocVariantData; var result: RawUTF8); function BSONProjectionSet(var Projection: variant; WithID: boolean; const Fields: TSQLFieldBits; ExtFieldNames: PRawUTF8DynArray): integer; function GetJSONValues(const Res: TBSONDocument; const extFieldNames: TRawUTF8DynArray; W: TJSONSerializer): integer; ................................................................................ function InternalBatchStart(Method: TSQLURIMethod; BatchOptions: TSQLRestBatchOptions): boolean; override; // internal method called by TSQLRestServer.RunBatch() to process fast // BULK sending to remote MongoDB database procedure InternalBatchStop; override; public /// initialize the direct access to the MongoDB collection // - in practice, you should not have to call this constructor, but rather // StaticMongoDBRegister() with a TMongoDatabase instance constructor Create(aClass: TSQLRecordClass; aServer: TSQLRestServer); override; /// release used memory destructor Destroy; override; /// overridden method for one single update call to the MongoDB server function UpdateBlobFields(Value: TSQLRecord): boolean; override; /// overridden method for one single read call to the MongoDB server ................................................................................ // - will associate the supplied class with a MongoDB collection for a // specified MongoDB database // - to be called before Server.CreateMissingTables // - by default, the collection name will match TSQLRecord.SQLTableName, but // you can customize it with the corresponding parameter // - the TSQLRecord.ID (RowID) field is always mapped to MongoDB's _id field // - will call create needed indexes // - you can later call aServer.InitializeTables to create any missing index and // initialize the void tables (e.g. default TSQLAuthGroup and TSQLAuthUser records) // - after registration, you can tune the field-name mapping by calling // ! aModel.Props[aClass].ExternalDB.MapField(..) // (just a regular external DB as defined in mORMotDB.pas unit) - it may be // a good idea to use short field names on MongoDB side, to reduce the space // used for storage (since they will be embedded within the document data) // - it will return the corresponding TSQLRestStorageMongoDB instance - ................................................................................ mrMapAutoFieldsIntoSmallerLength ); /// set of options for StaticMongoDBRegisterAll/TSQLRestMongoDBCreate functions TStaticMongoDBRegisterOptions = set of TStaticMongoDBRegisterOption; /// create and register ALL classes of a given model to access a MongoDB server // - the collection names will follow the class names // - this function will call aServer.InitializeTables to create any missing // index or populate default collection content function StaticMongoDBRegisterAll(aServer: TSQLRestServer; aMongoDatabase: TMongoDatabase; aOptions: TStaticMongoDBRegisterOptions=[]): boolean; /// create a new TSQLRest instance, possibly using MongoDB for its ORM process // - if aDefinition.Kind matches a TSQLRest registered class, one new instance // of this kind will be created and returned // - if aDefinition.Kind is 'MongoDB', it will instantiate an in-memory ................................................................................ for i := 0 to high(Tables) do if (mrDoNotRegisterUserGroupTables in aOptions) and (Tables[i].InheritsFrom(TSQLAuthGroup) or Tables[i].InheritsFrom(TSQLAuthUser)) then continue else if StaticMongoDBRegister(Tables[i],aServer,aMongoDatabase,'')=nil then result := false; if result then // ensure TSQLRecord.InitializeTable() is called aServer.InitializeTables([]); // will create indexes and default data end; function TSQLRestMongoDBCreate(aModel: TSQLModel; aDefinition: TSynConnectionDefinition; aHandleAuthentication: boolean; aOptions: TStaticMongoDBRegisterOptions): TSQLRest; var client: TMongoClient; database: TMongoDatabase; ................................................................................ {$ifdef WITHLOG} fOwner.LogFamily.SynLog.Log(sllInfo,'will store % using %',[aClass,Collection],self); {$endif} BSONProjectionSet(fBSONProjectionSimpleFields,true, fStoredClassRecordProps.SimpleFieldsBits[soSelect],nil); BSONProjectionSet(fBSONProjectionBlobFields,false, fStoredClassRecordProps.FieldBits[sftBlob],@fBSONProjectionBlobFieldsNames); end; function TSQLRestStorageMongoDB.BSONProjectionSet(var Projection: variant; WithID: boolean; const Fields: TSQLFieldBits; ExtFieldNames: PRawUTF8DynArray): integer; var i,n: integer; W: TBSONWriter; begin ................................................................................ end; end; function TSQLRestStorageMongoDB.CreateSQLMultiIndex( Table: TSQLRecordClass; const FieldNames: array of RawUTF8; Unique: boolean; IndexName: RawUTF8): boolean; begin if (self=nil) or (fCollection=nil) or (Table<>fStoredClass) then begin result := false; exit; end; result := true; if (high(FieldNames)=0) and IsRowID(pointer(FieldNames[0])) then exit; // ID primary key is always indexed by MongoDB try fCollection.EnsureIndex(FieldNames,true,Unique); except result := false; end; end; procedure TSQLRestStorageMongoDB.Drop; var DB: TMongoDatabase; CollName: RawUTF8; begin DB := Collection.Database; CollName := Collection.Name; Collection.Drop; fCollection := DB.CollectionOrCreate[CollName]; fEngineLastID := 0; end; destructor TSQLRestStorageMongoDB.Destroy; begin inherited; FreeAndNil(fBatchWriter); {$ifdef WITHLOG} ................................................................................ result := fCollection.Count; end; function TSQLRestStorageMongoDB.EngineNextID: TID; procedure ComputeMax_ID; var res: variant; begin res := fCollection.AggregateDocFromJson('{$group:{_id:null,max:{$max:"$_id"}}}'); if DocVariantType.IsOfType(res) then fEngineLastID := VariantToInt64Def(res.max,0); {$ifdef WITHLOG} fOwner.LogFamily.SynLog.Log(sllInfo,'Computed EngineNextID=%',[fEngineLastID],self); {$endif} end; |
Changes to SynMongoDB.pas.
5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 |
procedure TMongoCollection.EnsureIndex(const Keys: array of RawUTF8; Ascending, Unique: boolean); const Order: array[boolean] of Integer = (-1,1); var k,opt: variant; A: integer; begin TDocVariant.New(k); for A := 0 to high(Keys) do TDocVariantData(k).AddValue(Keys[A],Order[Ascending]); if Unique then opt := _ObjFast(['unique',true]); EnsureIndex(k,opt); end; |
> > |
5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 |
procedure TMongoCollection.EnsureIndex(const Keys: array of RawUTF8; Ascending, Unique: boolean); const Order: array[boolean] of Integer = (-1,1); var k,opt: variant; A: integer; begin if high(Keys)<0 then exit; // no column name TDocVariant.New(k); for A := 0 to high(Keys) do TDocVariantData(k).AddValue(Keys[A],Order[Ascending]); if Unique then opt := _ObjFast(['unique',true]); EnsureIndex(k,opt); end; |
Changes to SynopseCommit.inc.
1 |
'1.18.1365'
|
| |
1 |
'1.18.1366'
|