unit MongoDBTestCases; {$I Synopse.inc} // define HASINLINE CPU32 CPU64 OWNNORMTOUPPER interface // if defined, will test with 5000 records instead of the default 100 records {.$define ADD5000} // if defined, will create the DB with one "toto" user, to validate authentication {.$define TESTMONGOAUTH} uses SysUtils, Variants, SynCommons, SynTests, SynMongoDB, mORMot, SynSQLite3Static, mORMotSQLite3, mORMotMongoDB; const MONGOSERVER = 'localhost'; //MONGOSERVER = '10.0.2.2'; // from a VirtualBox VM MONGOPORT = 27017; type TTestDirect = class(TSynTestCase) protected fClient: TMongoClient; fDB: TMongoDatabase; fValues: TVariantDynArray; fExpectedCount: integer; procedure CleanUp; override; published procedure ConnectToLocalServer; procedure DropAndPrepareCollection; procedure FillCollection; procedure DropCollection; procedure FillCollectionBulk; procedure GracefulReconnect; procedure ReadCollection; procedure UpdateCollection; procedure DeleteSomeItems; end; TTestDirectWithAcknowledge = class(TTestDirect); TTestDirectWithoutAcknowledge = class(TTestDirect); TSQLORM = class(TSQLRecord) private fAge: integer; fName: RawUTF8; fDate: TDateTime; fValue: variant; fInts: TIntegerDynArray; fCreateTime: TCreateTime; fData: TSQLRawBlob; fFP: double; published property Name: RawUTF8 read fName write fName stored AS_UNIQUE; property Age: integer read fAge write fAge; property Date: TDateTime read fDate write fDate; property Value: variant read fValue write fValue; property Ints: TIntegerDynArray index 1 read fInts write fInts; property Data: TSQLRawBlob read fData write fData; property CreateTime: TCreateTime read fCreateTime write fCreateTime; property FP: double read fFP write fFP; end; TTestORM = class(TSynTestCase) protected fMongoClient: TMongoClient; fDB: TMongoDatabase; fModel: TSQLModel; fClient: TSQLRestClientDB; fStartTimeStamp: TTimeLog; fUpdateOffset: integer; procedure TestOne(R: TSQLORM; aID: integer); procedure CleanUp; override; published procedure ConnectToLocalServer; procedure Insert; procedure InsertInBatchMode; procedure Retrieve; procedure RetrieveAll; procedure RetrieveOneWithWhereClause; procedure RetrieveFromSQL; procedure Update; procedure Blobs; procedure Delete; procedure DeleteInBatchMode; end; TTestORMWithAcknowledge = class(TTestORM); TTestORMWithoutAcknowledge = class(TTestORM); TTestMongoDB = class(TSynTestsLogged) published procedure DirectAccess; procedure ORM; end; implementation { TTestMongoDB } procedure TTestMongoDB.DirectAccess; begin AddCase([TTestDirectWithAcknowledge,TTestDirectWithoutAcknowledge]); end; procedure TTestMongoDB.ORM; begin AddCase([TTestORMWithAcknowledge,TTestORMWithoutAcknowledge]); end; { TTestDirect } const DB_NAME = 'test24'; COLL_NAME = 'direct'; {$ifndef ADD5000} COLL_COUNT = 100; HASH1 = $44D5AC3E; HASH2 = $8A178B3; {$else} COLL_COUNT = 5000; HASH1 = $4EA46962; HASH2 = $2A005528; {$endif} {$ifdef TESTMONGOAUTH} const USER_NAME = 'toto'; USER_PWD = 'pass'; var UserCreated: boolean; {$endif} procedure TTestDirect.CleanUp; begin FreeAndNil(fClient); end; procedure TTestDirect.ConnectToLocalServer; var serverTime: TDateTime; res: variant; errmsg: RawUTF8; begin assert(fClient=nil); {$ifdef TESTMONGOAUTH} if not UserCreated then begin fClient := TMongoClient.Create(MONGOSERVER,MONGOPORT); with fClient.Database[DB_NAME] do begin DropUser(USER_NAME); Check(CreateUserForThisDatabase(USER_NAME,USER_PWD,true)=''); end; fClient.Free; UserCreated := true; end; {$endif} fClient := TMongoClient.Create(MONGOSERVER,MONGOPORT); if ClassType=TTestDirectWithAcknowledge then fClient.WriteConcern := wcAcknowledged else if ClassType=TTestDirectWithoutAcknowledge then fClient.WriteConcern := wcUnacknowledged else assert(false); {$ifdef WITHLOG} fClient.SetLog(SQLite3Log); // define some verbose log {$endif} {$ifdef TESTMONGOAUTH} fDB := fClient.OpenAuth(DB_NAME,USER_NAME,USER_PWD); {$else} fDB := fClient.Database[DB_NAME]; {$endif} Check(fDB<>nil); Check(fDB.Name=DB_NAME); errmsg := fDB.RunCommand('hostInfo',res); if CheckFailed(errmsg='') or CheckFailed(not VarIsNull(res.system)) then exit; serverTime := res.system.currentTime; // direct conversion to TDateTime Check(serverTime<>0); CheckSame(Now,serverTime,0.5); if System.Pos('MongoDB',Owner.CustomVersions)=0 then Owner.CustomVersions := format('%sUsing %s'#13#10'Running on %s'#13#10+ 'Compiled with mORMot '+SYNOPSE_FRAMEWORK_VERSION, [Owner.CustomVersions,fClient.ServerBuildInfoText,OSVersionText]); fExpectedCount := COLL_COUNT; end; procedure TTestDirect.DropAndPrepareCollection; var Coll: TMongoCollection; errmsg: RawUTF8; dat: TDateTime; i: integer; begin assert(fDB<>nil); Coll := fDB.CollectionOrNil[COLL_NAME]; if Coll<>nil then Check(Coll.Drop=''); Coll := fDB.CollectionOrCreate[COLL_NAME]; Check(Coll.Name=COLL_NAME); Check(Coll.FullCollectionName=DB_NAME+'.'+COLL_NAME); Check(Coll.Database=fDB); Check(fDB.Collection[COLL_NAME]=Coll); Check(fDB.CollectionOrCreate[COLL_NAME]=Coll); errmsg := Coll.Drop; CheckUTF8(fClient.ServerBuildInfoNumber>20000,errmsg); fValues := nil; SetLength(fValues,COLL_COUNT); for i := 0 to COLL_COUNT-1 do begin TDocVariant.New(fValues[i]); if i<0 then fValues[i]._id := null else fValues[i]._id := ObjectID; fValues[i].Name := 'Name '+IntToStr(i+1); fValues[i].FirstName := 'FirstName '+IntToStr(i+COLL_COUNT); fValues[i].Number := i; dat := 1.0*(30000+i); fValues[i].Date := dat; end; end; procedure TTestDirect.FillCollection; var Coll: TMongoCollection; oid: TBSONObjectID; i: integer; jsonArray: RawUTF8; bytes: Int64; docs: TVariantDynArray; begin fDB.CollectionOrNil[COLL_NAME].Drop; Coll := fDB.CollectionOrCreate[COLL_NAME]; Coll.EnsureIndex(['Name']); bytes := fClient.BytesTransmitted; for i := 0 to COLL_COUNT-1 do begin Check(Coll.Save(fValues[i],@oid)=(i<0)); Check(BSONVariantType.IsOfKind(fValues[i]._id,betObjectID)); Check(oid.Equal(fValues[i]._id),'EnsureDocumentHasID failure'); end; NotifyTestSpeed('rows inserted',COLL_COUNT,fClient.BytesTransmitted-bytes); Check(Coll.Count=COLL_COUNT); jsonArray := Coll.FindJSON(null,BSONVariant('{_id:0}')); Check(JSONArrayCount(@jsonArray[2])=COLL_COUNT); Check(Hash32(jsonArray)=HASH1,'projection over a collection'); Coll.FindDocs('{Number:{$gt:?}}',[COLL_COUNT shr 1],docs,null); Check(length(docs)=COLL_COUNT-(COLL_COUNT shr 1)-1); for i := 0 to high(docs) do Check(docs[i].number>COLL_COUNT shr 1); end; procedure TTestDirect.DropCollection; begin fDB.CollectionOrNil[COLL_NAME].Drop; end; procedure TTestDirect.FillCollectionBulk; var Coll: TMongoCollection; jsonArray: RawUTF8; bytes: Int64; begin Coll := fDB.CollectionOrCreate[COLL_NAME]; Coll.EnsureIndex(['Name']); bytes := fClient.BytesTransmitted; Coll.Insert(fValues); // insert all values at once NotifyTestSpeed('rows inserted',Coll.Count,fClient.BytesTransmitted-bytes); jsonArray := Coll.FindJSON(null,BSONVariant('{_id:0}')); Check(JSONArrayCount(@jsonArray[2])=COLL_COUNT); Check(Hash32(jsonArray)=HASH1,'projection over a collection'); end; procedure TTestDirect.GracefulReconnect; var Coll: TMongoCollection; jsonArray: RawUTF8; begin fClient.Connections[0].Close; // simulate server connection close Coll := fDB.Collection[COLL_NAME]; Check(Coll.Count=COLL_COUNT); jsonArray := Coll.FindJSON(null,BSONVariant('{_id:0}')); Check(JSONArrayCount(@jsonArray[2])=COLL_COUNT); Check(Hash32(jsonArray)=HASH1,'projection over a collection'); end; procedure TTestDirect.ReadCollection; var i: integer; Coll: TMongoCollection; docs: variant; jsonOne,jsonArray: RawUTF8; bytes: Int64; begin Coll := fDB.Collection[COLL_NAME]; Check(Coll.Count=COLL_COUNT); bytes := fClient.BytesTransmitted; jsonArray := Coll.FindJSON(null,BSONVariant('{_id:0}')); Check(JSONArrayCount(@jsonArray[2])=COLL_COUNT); Check(Hash32(jsonArray)=HASH1,'projection over a collection'); NotifyTestSpeed('rows read at once',Coll.Count,fClient.BytesTransmitted-bytes); for i := 0 to COLL_COUNT-1 do begin jsonOne := VariantSaveMongoJSON(fValues[i],modMongoStrict); jsonArray := '['+jsonOne+']'; Check(Coll.FindJSON('{Name:?}',[fValues[i].Name])=jsonArray); Check(Coll.FindJSON(BSONVariant(['Name','Name '+IntToStr(i+1)]),null)=jsonarray); Check(Coll.FindJSON(BSONVariant(['Name','Name '+IntToStr(i+1)]),null,1)=jsonone); docs := Coll.FindDoc('{Name:?}',[fValues[i].Name]); Check(VariantSaveMongoJSON(docs,modMongoStrict)=jsonArray); docs := Coll.FindDoc('{_id:?}',[fValues[i]._id]); Check(VariantSaveMongoJSON(docs,modMongoStrict)=jsonArray); docs := Coll.FindDoc('{_id:?}',[fValues[i]._id],1); Check(VariantSaveMongoJSON(docs,modMongoStrict)=jsonOne); end; end; procedure TTestDirect.UpdateCollection; var i: integer; Coll: TMongoCollection; jsonOne,jsonArray,expected: RawUTF8; bytes: Int64; begin Coll := fDB.Collection[COLL_NAME]; Check(Coll.Count=COLL_COUNT); bytes := fClient.BytesTransmitted; for i := 0 to COLL_COUNT-1 do begin fValues[i].Name := 'Name "'+IntToStr(i+1); if inil); Check(fDB.Name=DB_NAME); Check(fMongoClient.ServerBuildInfoNumber<>0); fModel := TSQLModel.Create([TSQLORM]); fClient := TSQLRestClientDB.Create(fModel,nil,':memory:',TSQLRestServerDB); Check(StaticMongoDBRegister(TSQLORM,fClient.Server,fDB,'mORMot')<>nil); fClient.Server.CreateMissingTables; (fClient.Server.StaticDataServer[TSQLORM] as TSQLRestStorageMongoDB).Drop; Check(fClient.TableRowCount(TSQLORM)=0); fStartTimeStamp := fClient.ServerTimeStamp; Check(fStartTimeStamp>10000); fClient.Server.NoAJAXJSON := true; end; procedure TTestORM.CleanUp; begin FreeAndNil(fClient); FreeAndNil(fModel); FreeAndNil(fMongoClient); end; procedure TTestORM.Insert; var R: TSQLORM; i: integer; bytes: Int64; begin Check(fClient.TableRowCount(TSQLORM)=0); bytes := fMongoClient.BytesTransmitted; R := TSQLORM.Create; try for i := 1 to COLL_COUNT do begin R.Name := 'Name '+Int32ToUTF8(i); R.Age := i and 63; R.Date := 1.0*(30000+i); R.Value := _ObjFast(['num',i]); R.Ints := nil; R.DynArray(1).Add(i); Check(fClient.Add(R,True)=i); end; finally R.Free; end; NotifyTestSpeed('rows inserted',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); Check(fClient.TableRowCount(TSQLORM)=COLL_COUNT); (fClient.Server.StaticDataServer[TSQLORM] as TSQLRestStorageMongoDB).Drop; end; procedure TTestORM.InsertInBatchMode; var R: TSQLORM; i: integer; bytes: Int64; IDs: TIDDynArray; begin Check(fClient.TableRowCount(TSQLORM)=0); bytes := fMongoClient.BytesTransmitted; fClient.BatchStart(TSQLORM); R := TSQLORM.Create; try for i := 1 to COLL_COUNT do begin R.Name := 'Name '+Int32ToUTF8(i); R.Age := i and 63; R.Date := 1.0*(30000+i); R.Value := _ObjFast(['num',i]); R.Ints := nil; R.DynArray(1).Add(i); R.FP := i*7.3445; Check(fClient.BatchAdd(R,True)>=0); end; finally R.Free; end; Check(fClient.BatchSend(IDs)=HTTP_SUCCESS); Check(length(IDs)=COLL_COUNT); NotifyTestSpeed('rows inserted',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); Check(fClient.TableRowCount(TSQLORM)=COLL_COUNT); end; procedure TTestORM.TestOne(R: TSQLORM; aID: integer); begin Check(R.ID=aID); Check(R.Name='Name '+Int32ToUTF8(aID)); Check(R.Age=aID and 63+fUpdateOffset); CheckSame(R.Date,1.0*(30000+aID),1E-5); Check(R.Value.num=aID+fUpdateOffset); Check(Length(R.Ints)=1); Check(R.Ints[0]=aID); Check(R.CreateTime>=fStartTimeStamp); CheckSame(R.FP,aID*7.3445); end; procedure TTestORM.Retrieve; var R: TSQLORM; i: integer; bytes: Int64; begin Check(fClient.TableRowCount(TSQLORM)=COLL_COUNT); bytes := fMongoClient.BytesTransmitted; R := TSQLORM.Create; try for i := 1 to COLL_COUNT do begin Check(fClient.Retrieve(i,R)); TestOne(R,i); end; finally R.Free; end; NotifyTestSpeed('rows retrieved',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); end; procedure TTestORM.RetrieveAll; var n: integer; R: TSQLORM; bytes: Int64; begin bytes := fMongoClient.BytesTransmitted; R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; while R.FillOne do begin inc(n); TestOne(R,n); end; Check(n=COLL_COUNT); finally R.Free; end; NotifyTestSpeed('rows retrieved',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); end; procedure TTestORM.RetrieveOneWithWhereClause; var R: TSQLORM; i,n: integer; bytes: Int64; begin bytes := fMongoClient.BytesTransmitted; for i := 1 to COLL_COUNT do begin R := TSQLORM.CreateAndFillPrepare(fClient,'ID=?',[i]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,i); end; Check(n=1); finally R.Free; end; end; NotifyTestSpeed('rows retrieved',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); end; procedure TTestORM.RetrieveFromSQL; var R: TSQLORM; n,tot,tot2,total,stat: integer; i64: Int64; ages: TIntegerDynArray; prev: RawUTF8; doc: variant; T: TSQLTable; bytes: Int64; begin bytes := fMongoClient.BytesTransmitted; R := TSQLORM.CreateAndFillPrepare(fClient,'Name=?',['Name 43']); try n := 0; while R.FillOne do begin inc(n); TestOne(R,43); end; Check(n=1); finally R.Free; end; stat := n; R := TSQLORM.CreateAndFillPrepare(fClient,'Age50); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'not RowID=?',[50]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,R.ID); Check(R.ID<>50); end; Check(n=COLL_COUNT-1); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'not Age51); end; Check(n>10); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age'' then Check(StrIComp(pointer(prev),pointer(R.Name))<0); prev := R.Name; end; Check(n=COLL_COUNT,'client side sort of a text field'); Check(total>=2682); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age in (1,10,20)',[]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,R.ID); Check(R.Age in [1,10,20]); end; Check(n>=3); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age in (1,10,20) and ID=?',[10]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,10); end; Check(n=1); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age in (10,20) or ID=?',[30]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,R.ID); Check((R.Age in [10,20]) or (R.ID=30)); end; Check(n>=3,'{$or:[{Age:{$in:[10,20]}},{_id:30}]}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age in (10,20) or ID=? order by ID desc',[40]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,R.ID); Check((R.Age in [10,20]) or (R.ID=40)); end; Check(n>=3,'{$query:{$or:[{Age:{$in:[10,20]}},{_id:40}]},$orderby:{_id:-1}}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Name like ?',['name 1%']); try n := 0; while R.FillOne do begin inc(n); Check(IdemPChar(pointer(R.Name),'NAME 1')); TestOne(R,R.ID); end; Check(n>10,'{Name:/^name 1/i}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Name like ?',['name 1']); try n := 0; while R.FillOne do begin inc(n); Check(IdemPChar(pointer(R.Name),'NAME 1')); TestOne(R,R.ID); end; Check(n=1,'{Name:/^name 1$/i}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Name like ?',['%ame 1%']); try n := 0; while R.FillOne do begin inc(n); Check(IdemPChar(pointer(R.Name),'NAME 1')); TestOne(R,R.ID); end; Check(n>10,'{Name:/ame 1/i}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'not Name like ?',['%ame 1%']); try tot := 0; while R.FillOne do begin inc(n); Check(not IdemPChar(pointer(R.Name),'NAME 1')); TestOne(R,R.ID); end; Check(n+tot=COLL_COUNT,'{Name:/ame 1/i}'); finally R.Free; end; inc(stat,n); R := TSQLORM.CreateAndFillPrepare(fClient,'Age in (1,10,20) and '+ 'IntegerDynArrayContains(Ints,?)',[10]); try n := 0; while R.FillOne do begin inc(n); TestOne(R,10); end; Check(n=1,'{Age:{$in:[1,10,20]},Ints:{$in:[10]}}'); finally R.Free; end; inc(stat,n); check(fClient.OneFieldValue(TSQLORM,'count(*)','Data is null',[],[],i64)); check(i64=COLL_COUNT,'{Data:null}'); check(fClient.OneFieldValue(TSQLORM,'count(*)','Data is not null',[],[],i64)); check(i64=0,'{Data:{$ne:null}}'); Check(fClient.RetrieveListJSON(TSQLORM,'',[],'min(RowID),max(RowID),Count(RowID)')= FormatUTF8('[{"min(RowID)":1,"max(RowID)":%,"Count(RowID)":%}]',[COLL_COUNT,COLL_COUNT])); doc := fClient.RetrieveDocVariant(TSQLORM,'',[], 'min(RowID) as a,max(RowID) as b,Count(RowID) as c'); if checkfailed(not VarIsEmptyOrNull(doc),'abc docvariant') then exit; check(doc.a=1); check(doc.b=COLL_COUNT); check(doc.c=COLL_COUNT); doc := fClient.RetrieveDocVariant(TSQLORM,'',[], 'min(RowID) as a,max(RowID)+1 as b,Count(RowID) as c,sum(Age) as d'); check(doc.a=1); check(doc.b=COLL_COUNT+1); check(doc.c=COLL_COUNT); check(doc.d=total); doc := fClient.RetrieveDocVariant(TSQLORM,'RowID=?',[50],'max(RowID) as a'); Check(doc.a=50); doc := fClient.RetrieveDocVariant(TSQLORM,'RowID=?',[50],'max(RowID) as a'); Check(doc.a=49); doc := fClient.RetrieveDocVariant(TSQLORM,'not RowID=?',[50],'count(RowID) as a'); Check(doc.a=COLL_COUNT-1); inc(stat,9); T := fClient.MultiFieldValues(TSQLORM,'Distinct(Age),max(RowID) as first,'+ 'count(Age) as count,sum(Age) as total','order by age group by age'); if not CheckFailed(T<>nil) then try n := 0; tot := 0; tot2 := 0; Check(T.FieldIndex('Age')=0); Check(T.FieldIndex('first')=1); Check(T.FieldIndex('count')=2); Check(T.FieldIndex('total')=3); while T.Step(false,@doc) do begin Check(AddInteger(ages,doc.Age,true)); if n>0 then Check(ages[n]>ages[n-1]); Check(integer(doc.first) and 63=doc.Age); inc(n); tot := tot+doc.Count; tot2 := tot2+doc.total; end; Check(n=64); Check(tot=COLL_COUNT); Check(tot2=total); finally T.Free; end; inc(stat,n); NotifyTestSpeed('rows retrieved',stat,fMongoClient.BytesTransmitted-bytes); end; procedure TTestORM.Update; var R: TSQLORM; bytes: Int64; n: integer; begin inc(fUpdateOffset); R := TSQLORM.CreateAndFillPrepare(fClient,''); try bytes := fMongoClient.BytesTransmitted; n := 0; while R.FillOne do begin R.Age := R.Age+fUpdateOffset; R.Value.num := R.Value.num+fUpdateOffset; fClient.Update(R); inc(n); end; Check(n=COLL_COUNT); finally R.Free; end; NotifyTestSpeed('rows updated',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; while R.FillOne do begin inc(n); TestOne(R,n); end; Check(n=COLL_COUNT); finally R.Free; end; end; procedure TTestORM.Blobs; var R: TSQLORM; i, n: integer; blob,blobRead: TSQLRawBlob; bytes,i64: Int64; begin SetLength(blob,8); bytes := fMongoClient.BytesTransmitted; for i := 1 to COLL_COUNT do begin PIntegerArray(blob)[0] := i; PIntegerArray(blob)[1] := i*$01020304; Check(fClient.UpdateBlob(TSQLORM,i,'Data',blob)); end; NotifyTestSpeed('rows updated',COLL_COUNT,fMongoClient.BytesTransmitted-bytes); R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; while R.FillOne do begin inc(n); TestOne(R,n); Check(R.Data=''); fClient.RetrieveBlob(TSQLORM,n,'Data',blobRead); PIntegerArray(blob)[0] := n; PIntegerArray(blob)[1] := n*$01020304; Check(blobRead=blob); end; Check(n=COLL_COUNT); finally R.Free; end; R := TSQLORM.CreateAndFillPrepare(fClient,'','ID,Data'); try n := 0; while R.FillOne do begin inc(n); Check(R.ID=n); Check(R.Age=0); PIntegerArray(blob)[0] := n; PIntegerArray(blob)[1] := n*$01020304; Check(R.Data=blob); PIntegerArray(blob)[0] := n*2; PIntegerArray(blob)[1] := n*$02030405; R.Data := blob; fClient.Server.UpdateBlobFields(R); end; Check(n=COLL_COUNT); finally R.Free; end; R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; while R.FillOne do begin inc(n); TestOne(R,n); Check(R.Data=''); Check(fClient.Server.RetrieveBlobFields(R)); PIntegerArray(blob)[0] := n*2; PIntegerArray(blob)[1] := n*$02030405; Check(R.Data=blob); R.Data := ''; end; Check(n=COLL_COUNT); finally R.Free; end; check(fClient.OneFieldValue(TSQLORM,'count(*)','Data is null',[],[],i64)); check(i64=0,'{Data:null}'); check(fClient.OneFieldValue(TSQLORM,'count(*)','Data is not null',[],[],i64)); check(i64=COLL_COUNT,'{Data:{$ne:null}}'); end; procedure TTestORM.Delete; var i,n: integer; ExpectedCount: integer; bytes: Int64; temp: string; R: TSQLORM; begin Check(fClient.Delete(TSQLORM,'ID in (5,10,15)'),'deletion with IN clause'); bytes := fMongoClient.BytesTransmitted; ExpectedCount := COLL_COUNT-3; for i := 20 to COLL_COUNT do if i mod 5=0 then begin Check(fClient.Delete(TSQLORM,i)); dec(ExpectedCount); end; NotifyTestSpeed('rows deleted',COLL_COUNT-ExpectedCount, fMongoClient.BytesTransmitted-bytes); R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; i := 0; while R.FillOne do begin inc(i); if i mod 5=0 then inc(i); inc(n); TestOne(R,i); end; Check(n=ExpectedCount); finally R.Free; end; temp := fRunConsole; (fClient.Server.StaticDataServer[TSQLORM] as TSQLRestStorageMongoDB).Drop; fUpdateOffset := 0; InsertInBatchMode; fRunConsole := temp; end; procedure TTestORM.DeleteInBatchMode; var i,n: integer; ExpectedCount: integer; bytes: Int64; IDs: TIDDynArray; R: TSQLORM; begin bytes := fMongoClient.BytesTransmitted; ExpectedCount := COLL_COUNT; fClient.BatchStart(TSQLORM); for i := 5 to COLL_COUNT do if i mod 5=0 then begin Check(fClient.BatchDelete(i)>=0); dec(ExpectedCount); end; Check(fClient.BatchSend(IDs)=HTTP_SUCCESS); Check(length(IDs)=COLL_COUNT-ExpectedCount); NotifyTestSpeed('rows deleted',length(IDs),fMongoClient.BytesTransmitted-bytes); R := TSQLORM.CreateAndFillPrepare(fClient,''); try n := 0; i := 0; while R.FillOne do begin inc(i); if i mod 5=0 then inc(i); inc(n); TestOne(R,i); end; Check(n=ExpectedCount); finally R.Free; end; end; end.