-
Notifications
You must be signed in to change notification settings - Fork 26
/
MongoBson.pas
1121 lines (1022 loc) · 39.1 KB
/
MongoBson.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
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
361
362
363
364
365
366
367
368
369
370
371
372
373
374
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
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
Copyright 2009-2011 10gen Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
}
{ This unit implements BSON, a binary JSON-like document format.
It is used to represent documents in MongoDB and also for network traffic.
See http://www.mongodb.org/display/DOCS/BSON }
unit MongoBson;
interface
type TBson = class;
TIntegerArray = array of Integer;
TDoubleArray = array of Double;
TBooleanArray = array of Boolean;
TStringArray = array of string;
{ A value of TBsonType indicates the type of the data associated
with a field within a BSON document. }
TBsonType = (
bsonEOO = 0,
bsonDOUBLE = 1,
bsonSTRING = 2,
bsonOBJECT = 3,
bsonARRAY = 4,
bsonBINDATA = 5,
bsonUNDEFINED = 6,
bsonOID = 7,
bsonBOOL = 8,
bsonDATE = 9,
bsonNULL = 10,
bsonREGEX = 11,
bsonDBREF = 12, (* Deprecated. *)
bsonCODE = 13,
bsonSYMBOL = 14,
bsonCODEWSCOPE = 15,
bsonINT = 16,
bsonTIMESTAMP = 17,
bsonLONG = 18);
TBsonIterator = class;
{ A TBsonOID is used to store BSON Object IDs.
See http://www.mongodb.org/display/DOCS/Object+IDs }
TBsonOID = class(TObject)
var
{ the oid data }
value : array[0..11] of Byte;
{ Generate an Object ID }
constructor Create(); overload;
{ Create an ObjectID from a 24-digit hex string }
constructor Create(s : string); overload;
{ Create an Object ID from a TBsonIterator pointing to an oid field }
constructor Create(i : TBsonIterator); overload;
{ Convert this Object ID to a 24-digit hex string }
function AsString() : string;
end;
{ A TBsonCodeWScope is used to hold javascript code and its associated scope.
See TBsonIterator.getCodeWScope() }
TBsonCodeWScope = class(TObject)
var
code : string;
scope : TBson;
{ Create a TBsonCodeWScope from a javascript string and a TBson scope }
constructor Create(code_ : string; scope_ : TBson); overload;
{ Create a TBsonCodeWScope from a TBSonIterator pointing to a
CODEWSCOPE field. }
constructor Create(i : TBsonIterator); overload;
end;
{ A TBsonRegex is used to hold a regular expression string and its options.
See TBsonIterator.getRegex(). }
TBsonRegex = class(TObject)
var
pattern : string;
options : string;
{ Create a TBsonRegex from reqular expression and options strings }
constructor Create(pattern_ : string; options_ : string); overload;
{ Create a TBsonRegex from a TBsonIterator pointing to a REGEX field }
constructor Create(i : TBsonIterator); overload;
end;
{ A TBsonTimestamp is used to hold a TDateTime and an increment value.
See http://www.mongodb.org/display/DOCS/Timestamp+data+type and
TBsonIterator.getTimestamp() }
TBsonTimestamp = class(TObject)
var
time : TDateTime;
increment : Integer;
{ Create a TBsonTimestamp from a TDateTime and an increment }
constructor Create(time_ : TDateTime; increment_ : Integer); overload;
{ Create a TBSonTimestamp from a TBsonIterator pointing to a TIMESTAMP
field. }
constructor Create(i : TBsonIterator); overload;
end;
{ A TBsonBinary is used to hold the contents of BINDATA fields.
See TBsonIterator.getBinary() }
TBsonBinary = class(TObject)
var
{ Pointer to data allocated on the heap with GetMem }
data : Pointer;
{ The length of the data in bytes }
len : Integer;
{ The subtype of the BINDATA (usually 0) }
kind : Integer;
{ Create a TBsonBinary from a pointer and a length. The data
is copied to the heap. kind is initialized to 0 }
constructor Create(p : Pointer; length : Integer); overload;
{ Create a TBsonBinary from a TBsonIterator pointing to a BINDATA
field. }
constructor Create(i : TBsonIterator); overload;
{ Destroys the TBsonBinary and releases its memory with FreeMem() }
destructor Destroy(); override;
end;
{ A TBsonBuffer is used to build a BSON document by appending the
names and values of fields. Call finish() when done to convert
the buffer to a TBson which can be used in database operations.
Example: @longcode(#
var
bb : TBsonBuffer;
b : TBson;
begin
bb := TBsonBuffer.Create();
bb.append('name', 'Joe');
bb.append('age', 33);
bb.append('city', 'Boston');
b := bb.finish();
end;
#) }
TBsonBuffer = class(TObject)
private
var handle : Pointer;
public
{ Create an empty TBsonBuffer ready to have fields appended. }
constructor Create();
{ Append a string (PAnsiChar) to the buffer }
function append(name : string; value : PAnsiChar) : Boolean; overload;
{ Append an Integer to the buffer }
function append(name : string; value : Integer) : Boolean; overload;
{ Append an Int64 to the buffer }
function append(name : string; value : Int64) : Boolean; overload;
{ Append a Double to the buffer }
function append(name : string; value : Double) : Boolean; overload;
{ Append a TDateTime to the buffer; converted to 64-bit POSIX time }
function append(name : string; value : TDateTime) : Boolean; overload;
{ Append a Boolean to the buffer }
function append(name : string; value : Boolean) : Boolean; overload;
{ Append an Object ID to the buffer }
function append(name : string; value : TBsonOID) : Boolean; overload;
{ Append a CODEWSCOPE to the buffer }
function append(name : string; value : TBsonCodeWScope) : Boolean; overload;
{ Append a REGEX to the buffer }
function append(name : string; value : TBsonRegex) : Boolean; overload;
{ Append a TIMESTAMP to the buffer }
function append(name : string; value : TBsonTimestamp) : Boolean; overload;
{ Append BINDATA to the buffer }
function append(name : string; value : TBsonBinary) : Boolean; overload;
{ Append a TBson document as a subobject }
function append(name : string; value : TBson) : Boolean; overload;
{ Generic version of append. Calls one of the other append functions
if the type contained in the variant is supported. }
function append(name : string; value : OleVariant) : Boolean; overload;
{ Append an array of Integers }
function appendArray(name : string; value : array of Integer) : Boolean; overload;
{ Append an array of Doubles }
function appendArray(name : string; value : array of Double) : Boolean; overload;
{ Append an array of Booleans }
function appendArray(name : string; value : array of Boolean) : Boolean; overload;
{ Append an array of strings }
function appendArray(name : string; value : array of string) : Boolean; overload;
{ Append a NULL field to the buffer }
function appendNull(name : string) : Boolean;
{ Append an UNDEFINED field to the buffer }
function appendUndefined(name : string) : Boolean;
{ Append javascript code to the buffer }
function appendCode(name : string; value : PAnsiChar) : Boolean;
{ Append a SYMBOL to the buffer }
function appendSymbol(name : string; value : PAnsiChar) : Boolean;
{ Alternate way to append BINDATA directly without first creating a
TBsonBinary value }
function appendBinary(name : string; kind : Integer; data : Pointer; length : Integer) : Boolean;
{ Indicate that you will be appending more fields as a subobject }
function startObject(name : string) : Boolean;
{ Indicate that you will be appending more fields as an array }
function startArray(name : string) : Boolean;
{ Indicate that a subobject or array is done. }
function finishObject() : Boolean;
{ Return the current size of the BSON document you are building }
function size() : Integer;
{ Call this when finished appending fields to the buffer to turn it into
a TBson for network transport. }
function finish() : TBson;
{ Destroy this TBsonBuffer. Releases external resources. }
destructor Destroy(); override;
end;
{ A TBson holds a BSON document. BSON is a binary, JSON-like document format.
It is used to represent documents in MongoDB and also for network traffic.
See http://www.mongodb.org/display/DOCS/BSON }
TBson = class(TObject)
{ Pointer to externally managed data. User code should not modify this.
It is public only because the MongoDB and GridFS units must access it. }
var handle : Pointer;
{ Return the size of this BSON document in bytes }
function size() : Integer;
{ Get a TBsonIterator that points to the first field of this BSON }
function iterator() : TBsonIterator;
{ Get a TBsonIterator that points to the field with the given name.
If name is not found, nil is returned. }
function find(name : string) : TBsonIterator;
{ Get the value of a field given its name. This function does not support
all BSON field types. Use find() and one of the 'get' functions of
TBsonIterator to retrieve special values. }
function value(name : string) : Variant;
{ Display this BSON document on the console. subobjects and arrays are
appropriately indented. }
procedure display();
{ Create a TBson given a pointer to externally managed data describing
the document. User code should not instantiate TBson directly. Use
TBsonBuffer and finish() to create BSON documents. }
constructor Create(h : Pointer);
{ Destroy this TBson. Releases the externally managed data. }
destructor Destroy; override;
end;
{ TBsonIterators are used to step through the fields of a TBson document. }
TBsonIterator = class(TObject)
private
{ Pointer to externally managed data. }
var handle : Pointer;
public
{ Return the TBsonType of the field pointed to by this iterator. }
function kind() : TBsonType;
{ Return the key (or name) of the field pointed to by this iterator. }
function key() : string;
{ Step to the first or next field of a TBson document. Returns True
if there is a next field; otherwise, returns false at the end of the
document (or subobject).
Example: @longcode(#
iter := b.iterator;
while i.next() do
if i.kind = bsonNULL then
WriteLn(i.key, ' is a NULL field.');
#) }
function next() : Boolean;
{ Get the value of the field pointed to by this iterator. This function
does not support all BSON field types and will throw an exception for
those it does not. Use one of the 'get' functions to extract one of these
special types. }
function value() : Variant;
{ Get an TBsonIterator pointing to the first field of a subobject or array.
kind() must be bsonOBJECT or bsonARRAY. }
function subiterator() : TBsonIterator;
{ Get an Object ID from the field pointed to by this iterator. }
function getOID() : TBsonOID;
{ Get a TBsonCodeWScope object for a CODEWSCOPE field pointed to by this
iterator. }
function getCodeWScope() : TBsonCodeWScope;
{ Get a TBsonRegex for a REGEX field }
function getRegex() : TBsonRegex;
{ Get a TBsonTimestamp object for a TIMESTAMP field pointed to by this
iterator. }
function getTimestamp() : TBsonTimestamp;
{ Get a TBsonBinary object for the BINDATA field pointed to by this
iterator. }
function getBinary() : TBsonBinary;
{ Get an array of Integers. This iterator must point to ARRAY field
which has each component type as Integer }
function getIntegerArray() : TIntegerArray;
{ Get an array of Doubles. This iterator must point to ARRAY field
which has each component type as Double }
function getDoubleArray() : TDoubleArray;
{ Get an array of strings. This iterator must point to ARRAY field
which has each component type as string }
function getStringArray() : TStringArray;
{ Get an array of Booleans. This iterator must point to ARRAY field
which has each component type as Boolean }
function getBooleanArray() : TBooleanArray;
{ Internal usage only. Create an uninitialized TBsonIterator }
constructor Create(); overload;
{ Create a TBsonIterator that points to the first field of the given
TBson }
constructor Create(b : TBson); overload;
{ Destroy this TBsonIterator. Releases external resources. }
destructor Destroy; override;
end;
var
{ An empty BSON document }
bsonEmpty : TBson;
(* The idea for this shorthand way to build a BSON
document from an array of variants came from Stijn Sanders
and his TMongoWire, located here:
https://github.com/stijnsanders/TMongoWire
Subobjects are started with '{' and ended with '}'
Example: @longcode(#
var b : TBson;
begin
b := BSON(['name', 'Albert', 'age', 64,
'address', '{',
'street', '109 Vine Street',
'city', 'New Haven',
'}' ]);
#) *)
function BSON(x : array of OleVariant) : TBson;
{ Convert a byte to a 2-digit hex string }
function ByteToHex(InByte : Byte) : string;
{ Convert an Int64 to a Double. Some loss of precision may occur. }
function Int64toDouble(i64 : int64) : double;
cdecl; external 'mongoc.dll' name 'bson_int64_to_double';
implementation
uses SysUtils, Variants;
procedure set_bson_err_handler(err_handler : Pointer); cdecl; external 'mongoc.dll';
function bson_create() : Pointer; cdecl; external 'mongoc.dll';
procedure bson_init(b : Pointer); cdecl; external 'mongoc.dll';
procedure bson_destroy(b : Pointer); cdecl; external 'mongoc.dll';
procedure bson_dispose(b : Pointer); cdecl; external 'mongoc.dll';
procedure bson_copy(dest : Pointer; src : Pointer); cdecl; external 'mongoc.dll';
function bson_finish(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
procedure bson_oid_gen(oid : Pointer); cdecl; external 'mongoc.dll';
procedure bson_oid_to_string(oid : Pointer; s : PAnsiChar); cdecl; external 'mongoc.dll';
procedure bson_oid_from_string(oid : Pointer; s : PAnsiChar); cdecl; external 'mongoc.dll';
function bson_append_string(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_code(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_symbol(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_int(b : Pointer; name : PAnsiChar; value : Integer) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_long(b : Pointer; name : PAnsiChar; value : Int64) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_double(b : Pointer; name : PAnsiChar; value : Double) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_date(b : Pointer; name : PAnsiChar; value : Int64) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_bool(b : Pointer; name : PAnsiChar; value : Boolean) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_null(b : Pointer; name : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_undefined(b : Pointer; name : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_start_object(b : Pointer; name : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_start_array(b : Pointer; name : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_finish_object(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_append_oid(b : Pointer; name : PAnsiChar; oid : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_append_code_w_scope(b : Pointer; name : PAnsiChar; code : PAnsiChar; scope : Pointer) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_regex(b : Pointer; name : PAnsiChar; pattern : PAnsiChar; options : PAnsiChar) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_timestamp2(b : Pointer; name : PAnsiChar; time : Integer; increment : Integer) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_binary(b : Pointer; name : PAnsiChar; kind : Byte; data : Pointer; len : Integer) : Integer;
cdecl; external 'mongoc.dll';
function bson_append_bson(b : Pointer; name : PAnsiChar; value : Pointer) : Integer;
cdecl; external 'mongoc.dll';
function bson_buffer_size(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_size(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_iterator_create() : Pointer; cdecl; external 'mongoc.dll';
procedure bson_iterator_dispose(i : Pointer); cdecl; external 'mongoc.dll';
procedure bson_iterator_init(i : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
function bson_find(i : Pointer; b : Pointer; name : PAnsiChar) : TBsonType;
cdecl; external 'mongoc.dll';
function bson_iterator_type(i : Pointer) : TBsonType; cdecl; external 'mongoc.dll';
function bson_iterator_next(i : Pointer) : TBsonType; cdecl; external 'mongoc.dll';
function bson_iterator_key(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
function bson_iterator_double(i : Pointer) : Double; cdecl; external 'mongoc.dll';
function bson_iterator_long(i : Pointer) : Int64; cdecl; external 'mongoc.dll';
function bson_iterator_int(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_iterator_bool(i : Pointer) : Boolean; cdecl; external 'mongoc.dll';
function bson_iterator_string(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
function bson_iterator_date(i : Pointer) : Int64; cdecl; external 'mongoc.dll';
procedure bson_iterator_subiterator(i : Pointer; sub : Pointer);
cdecl; external 'mongoc.dll';
function bson_iterator_oid(i : Pointer) : Pointer; cdecl; external 'mongoc.dll';
function bson_iterator_code(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
procedure bson_iterator_code_scope(i : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
function bson_iterator_regex(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
function bson_iterator_regex_opts(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
function bson_iterator_timestamp_time(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_iterator_timestamp_increment(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_iterator_bin_len(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
function bson_iterator_bin_type(i : Pointer) : Byte; cdecl; external 'mongoc.dll';
function bson_iterator_bin_data(i : Pointer) : Pointer; cdecl; external 'mongoc.dll';
constructor TBsonOID.Create();
begin
bson_oid_gen(@value);
end;
constructor TBsonOID.Create(s : string);
begin
if length(s) <> 24 then
Raise Exception.Create('Expected a 24 digit hex string');
bson_oid_from_string(@value, PAnsiChar(AnsiString(s)));
end;
constructor TBsonOID.Create(i : TBsonIterator);
var
p : PByte;
begin
p := bson_iterator_oid(i.handle);
Move(p^, value, 12);
end;
function TBsonOID.AsString() : string;
var
buf : array[0..24] of AnsiChar;
begin
bson_oid_to_string(@value, @buf);
Result := string(buf);
end;
constructor TBsonIterator.Create();
begin
inherited Create();
handle := bson_iterator_create();
end;
constructor TBsonIterator.Create(b : TBson);
begin
inherited Create();
handle := bson_iterator_create();
bson_iterator_init(handle, b.handle);
end;
destructor TBsonIterator.Destroy;
begin
bson_iterator_dispose(handle);
end;
function TBsonIterator.kind() : TBsonType;
begin
Result := bson_iterator_type(handle);
end;
function TBsonIterator.next() : Boolean;
begin
Result := bson_iterator_next(handle) <> bsonEOO;
end;
function TBsonIterator.key() : string;
begin
Result := string(System.UTF8ToWideString(bson_iterator_key(handle)));
end;
function TBsonIterator.value() : Variant;
var
k : TBsonType;
d : TDateTime;
begin
k := kind();
case k of
bsonEOO, bsonNULL : Result := Null;
bsonDOUBLE: Result := bson_iterator_double(handle);
bsonSTRING, bsonCODE, bsonSYMBOL:
Result := string(System.UTF8ToWideString(bson_iterator_string(handle)));
bsonINT: Result := bson_iterator_int(handle);
bsonBOOL: Result := bson_iterator_bool(handle);
bsonDATE: begin
d := Int64toDouble(bson_iterator_date(handle)) / (1000 * 24 * 60 * 60) + 25569;
Result := d;
end;
bsonLONG: Result := bson_iterator_long(handle);
else
Raise Exception.Create('BsonType (' + IntToStr(Ord(k)) + ') not supported by TBsonIterator.value');
end;
end;
function TBsonIterator.getOID() : TBsonOID;
begin
Result := TBsonOID.Create(Self);
end;
function TBsonIterator.getCodeWScope() : TBsonCodeWScope;
begin
Result := TBsonCodeWScope.Create(Self);
end;
function TBsonIterator.getRegex() : TBsonRegex;
begin
Result := TBsonRegex.Create(Self);
end;
function TBsonIterator.getTimestamp() : TBsonTimestamp;
begin
Result := TBsonTimestamp.Create(Self);
end;
function TBsonIterator.getBinary() : TBsonBinary;
begin
Result := TBsonBinary.Create(Self);
end;
function TBsonIterator.subiterator() : TBsonIterator;
var
i : TBsonIterator;
begin
i := TBsonIterator.Create();
bson_iterator_subiterator(handle, i.handle);
Result := i;
end;
function TBsonIterator.getIntegerArray() : TIntegerArray;
var
i : TBsonIterator;
j, count : Integer;
begin
if kind() <> bsonArray then
raise Exception.Create('Iterator does not point to an array');
i := subiterator();
count := 0;
while i.next() do begin
if i.kind() <> bsonINT then
raise Exception.Create('Array component is not an Integer');
inc(count);
end;
i := subiterator;
j := 0;
SetLength(Result, count);
while i.next() do begin
Result[j] := i.value();
inc(j);
end;
end;
function TBsonIterator.getDoubleArray() : TDoubleArray;
var
i : TBsonIterator;
j, count : Integer;
begin
if kind() <> bsonArray then
raise Exception.Create('Iterator does not point to an array');
i := subiterator();
count := 0;
while i.next() do begin
if i.kind() <> bsonDOUBLE then
raise Exception.Create('Array component is not a Double');
inc(count);
end;
i := subiterator;
j := 0;
SetLength(Result, count);
while i.next() do begin
Result[j] := i.value();
inc(j);
end;
end;
function TBsonIterator.getStringArray() : TStringArray;
var
i : TBsonIterator;
j, count : Integer;
begin
if kind() <> bsonArray then
raise Exception.Create('Iterator does not point to an array');
i := subiterator();
count := 0;
while i.next() do begin
if i.kind() <> bsonSTRING then
raise Exception.Create('Array component is not a string');
inc(count);
end;
i := subiterator;
j := 0;
SetLength(Result, count);
while i.next() do begin
Result[j] := System.UTF8ToWideString(i.value());
inc(j);
end;
end;
function TBsonIterator.getBooleanArray() : TBooleanArray;
var
i : TBsonIterator;
j, count : Integer;
begin
if kind() <> bsonArray then
raise Exception.Create('Iterator does not point to an array');
i := subiterator();
count := 0;
while i.next() do begin
if i.kind() <> bsonBOOL then
raise Exception.Create('Array component is not a Boolean');
inc(count);
end;
i := subiterator;
j := 0;
SetLength(Result, count);
while i.next() do begin
Result[j] := i.value();
inc(j);
end;
end;
function TBson.value(name : string) : Variant;
var
i : TBsonIterator;
begin
i := find(name);
if i = nil then
Result := Null
else
Result := i.value;
i.Free; { Thanks to SamJokO }
end;
function TBson.iterator() : TBsonIterator;
begin
Result := TBsonIterator.Create(Self);
end;
constructor TBsonBuffer.Create();
begin
inherited Create();
handle := bson_create();
bson_init(handle);
end;
destructor TBsonBuffer.Destroy();
begin
bson_destroy(handle);
bson_dispose(handle);
inherited Destroy();
end;
function TBsonBuffer.append(name : string; value: PAnsiChar) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_string(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.appendCode(name : string; value: PAnsiChar) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_code(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.appendSymbol(name : string; value: PAnsiChar) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_symbol(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.append(name : string; value: Integer) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_int(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.append(name : string; value: Int64) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_long(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.append(name : string; value: Double) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_double(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.append(name : string; value: TDateTime) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_date(handle, PAnsiChar(System.UTF8Encode(name)), Trunc((value - 25569) * 1000 * 60 * 60 * 24)) = 0);
end;
function TBsonBuffer.append(name : string; value: Boolean) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_bool(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
end;
function TBsonBuffer.append(name : string; value: TBsonOID) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_oid(handle, PAnsiChar(System.UTF8Encode(name)), @value.value) = 0);
end;
function TBsonBuffer.append(name : string; value: TBsonCodeWScope) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_code_w_scope(handle, PAnsiChar(System.UTF8Encode(name)), PAnsiChar(System.UTF8Encode(value.code)), value.scope.handle) = 0);
end;
function TBsonBuffer.append(name : string; value: TBsonRegex) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_regex(handle, PAnsiChar(System.UTF8Encode(name)), PAnsiChar(System.UTF8Encode(value.pattern)), PAnsiChar(System.UTF8Encode(value.options))) = 0);
end;
function TBsonBuffer.append(name : string; value: TBsonTimestamp) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_timestamp2(handle, PAnsiChar(System.UTF8Encode(name)), Trunc((value.time - 25569) * 60 * 60 * 24), value.increment) = 0);
end;
function TBsonBuffer.append(name : string; value: TBsonBinary) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_binary(handle, PAnsiChar(System.UTF8Encode(name)), value.kind, value.data, value.len) = 0);
end;
function TBsonBuffer.append(name : string; value : OleVariant) : Boolean;
var
d : double;
begin
case VarType(value) of
varNull: Result := appendNull(name);
varInteger: Result := append(name, Integer(value));
varSingle, varDouble, varCurrency: begin
d := value;
Result := append(name, d);
end;
varDate: Result := append(name, TDateTime(value));
varInt64: Result := append(name, Int64(value));
varBoolean: Result := append(name, Boolean(value));
varOleStr: Result := append(name, PAnsiChar(System.UTF8Encode(value)));
else
raise Exception.Create('TBson.append(variant): type not supported (' + IntToStr(VarType(value)) + ')');
end;
end;
function TBsonBuffer.appendNull(name : string) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_null(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
end;
function TBsonBuffer.appendUndefined(name : string) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_undefined(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
end;
function TBsonBuffer.appendBinary(name : string; kind : Integer; data : Pointer; length : Integer) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_binary(handle, PAnsiChar(System.UTF8Encode(name)), kind, data, length) = 0);
end;
function TBsonBuffer.append(name : string; value : TBson) : Boolean;
begin
Result := (bson_append_bson(handle, PAnsiChar(System.UTF8Encode(name)), value.handle) = 0);
end;
function TBsonBuffer.appendArray(name : string; value : array of Integer) : Boolean;
var
success : Boolean;
i, len : Integer;
begin
success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
len := Length(value);
i := 0;
while success and (i < len) do begin
success := (bson_append_int(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
inc(i);
end;
if success then
success := (bson_append_finish_object(handle) = 0);
Result := success;
end;
function TBsonBuffer.appendArray(name : string; value : array of Double) : Boolean;
var
success : Boolean;
i, len : Integer;
begin
success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
len := Length(value);
i := 0;
while success and (i < len) do begin
success := (bson_append_double(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
inc(i);
end;
if success then
success := (bson_append_finish_object(handle) = 0);
Result := success;
end;
function TBsonBuffer.appendArray(name : string; value : array of Boolean) : Boolean;
var
success : Boolean;
i, len : Integer;
begin
success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
len := Length(value);
i := 0;
while success and (i < len) do begin
success := (bson_append_bool(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
inc(i);
end;
if success then
success := (bson_append_finish_object(handle) = 0);
Result := success;
end;
function TBsonBuffer.appendArray(name : string; value : array of string) : Boolean;
var
success : Boolean;
i, len : Integer;
begin
success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
len := Length(value);
i := 0;
while success and (i < len) do begin
success := (bson_append_string(handle, PAnsiChar(AnsiString(IntToStr(i))), PAnsiChar(System.UTF8Encode(value[i]))) = 0);
inc(i);
end;
if success then
success := (bson_append_finish_object(handle) = 0);
Result := success;
end;
function TBsonBuffer.startObject(name : string) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_start_object(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
end;
function TBsonBuffer.startArray(name : string) : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
end;
function TBsonBuffer.finishObject() : Boolean;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := (bson_append_finish_object(handle) = 0);
end;
function TBsonBuffer.size() : Integer;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
Result := bson_buffer_size(handle);
end;
function TBsonBuffer.finish() : TBson;
begin
if handle = nil then
raise Exception.Create('BsonBuffer already finished');
if bson_finish(handle) = 0 Then begin
Result := TBson.Create(handle);
handle := nil;
end
else
Result := nil;
end;
constructor TBson.Create(h : Pointer);
begin
handle := h;
end;
destructor TBson.Destroy();
begin
bson_destroy(handle);
bson_dispose(handle);
inherited Destroy();
end;
function TBson.size() : Integer;
begin
Result := bson_size(handle);
end;
function TBson.find(name : string) : TBsonIterator;
var
i : TBsonIterator;
begin
i := TBsonIterator.Create();
if bson_find(i.handle, handle, PAnsiChar(System.UTF8Encode(name))) = bsonEOO Then
i := nil;
Result := i;
end;
procedure _display(i : TBsonIterator; depth : Integer);
var
t : TBsonType;
j,k : Integer;
cws : TBsonCodeWScope;
regex : TBsonRegex;
ts : TBsonTimestamp;
bin : TBsonBinary;
p : PByte;
begin
while i.next() do begin
t := i.kind();
if t = bsonEOO then
break;
for j:= 1 To depth do
Write(' ');
Write(i.key, ' (', Ord(t), ') : ');
case t of
bsonDOUBLE,
bsonSTRING, bsonSYMBOL, bsonCODE,
bsonBOOL, bsonDATE, bsonINT, bsonLONG :
Write(i.value);
bsonUNDEFINED :
Write('UNDEFINED');
bsonNULL :
Write('NULL');
bsonOBJECT, bsonARRAY : begin
Writeln;
_display(i.subiterator, depth+1);
end;
bsonOID : write(i.getOID().AsString());
bsonCODEWSCOPE : begin
Write('CODEWSCOPE ');
cws := i.getCodeWScope();
WriteLn(cws.code);
_display(cws.scope.iterator, depth+1);
end;
bsonREGEX: begin
regex := i.getRegex();
write(regex.pattern, ', ', regex.options);
end;
bsonTIMESTAMP: begin
ts := i.getTimestamp();
write(DateTimeToStr(ts.time), ' (', ts.increment, ')');
end;
bsonBINDATA: begin
bin := i.getBinary();
Write('BINARY (', bin.kind, ')');
p := bin.data;
for j := 0 to bin.len-1 do begin
if j and 15 = 0 then begin
WriteLn;
for k := 1 To depth+1 do
Write(' ');
end;
write(ByteToHex(p^), ' ');
Inc(p);
end;
end;
else
Write('UNKNOWN');
end;
Writeln;
end;
end;
procedure TBson.display();
begin
if Self = nil then
WriteLn('nil BSON')
else
_display(iterator, 0);
end;
constructor TBsonCodeWScope.Create(code_ : string; scope_ : TBson);
begin
code := code_;