mORMot and Open Source friends
Check-in [5bf8ef64b3]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
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: 5bf8ef64b3d99a51b07a3945ae87706d866de366
User & Date: ab 2015-05-17 12:02:35
Context
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

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'