├── .gitignore
├── AddressBook.dpr
├── AddressBook.dproj
├── AddressBook.res
├── AddressBookForm.dfm
├── AddressBookForm.pas
├── COPYRIGHT.txt
├── GridFS.pas
├── LICENSE.txt
├── MongoBson.pas
├── MongoDB.pas
├── MongoDelphiDriver.dpk
├── MongoDelphiDriver.dproj
├── MongoDelphiDriver.groupproj
├── MongoDelphiDriver.groupproj.local
├── MongoDelphiDriver.res
├── README.md
├── Test.dpr
├── Test.dproj
├── Test.res
└── mongo-c-driver.zip
/.gitignore:
--------------------------------------------------------------------------------
1 | Win32/
2 | Win64/
3 | __history
4 | MongoDelphiDriver.dproj.local
5 | MongoDelphiDriver.identcache
6 | Test.dproj.local
7 | Test.identcache
8 | MongoDelphiDriver_prjgroup.tvsconfig
9 | AddressBook.dproj.local
10 | AddressBook.identcache
11 |
--------------------------------------------------------------------------------
/AddressBook.dpr:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | program AddressBook;
17 |
18 | uses
19 | Vcl.Forms,
20 | AddressBookForm in 'AddressBookForm.pas' {Form1};
21 |
22 | {$R *.res}
23 |
24 | begin
25 | Application.Initialize;
26 | Application.MainFormOnTaskbar := True;
27 | Application.CreateForm(TForm1, Form1);
28 | Application.Run;
29 | end.
30 |
--------------------------------------------------------------------------------
/AddressBook.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {EE370486-5233-498B-B225-FE8AEB2310C3}
4 | 13.4
5 | VCL
6 | AddressBook.dpr
7 | True
8 | Debug
9 | Win32
10 | 1
11 | Application
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Base
40 | true
41 |
42 |
43 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;ibxpress;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;FMXTee;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;CloudService;FmxTeeUI;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)
44 | $(BDS)\bin\delphi_PROJECTICON.ico
45 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
46 | .\$(Platform)\$(Config)
47 | .\$(Platform)\$(Config)
48 | false
49 | false
50 | false
51 | false
52 | false
53 |
54 |
55 | TeeDB;vclib;Tee;DBXOdbcDriver;DBXSybaseASEDriver;vclimg;TeeUI;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;vclribbon;VclSmp;vcl;DataSnapConnectors;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;adortl;$(DCC_UsePackage)
56 |
57 |
58 | vcldbx;frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;VclSmp;fsDB16;vcl;DataSnapConnectors;DBXMSSQLDriver;CodeSiteExpressPkg;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage)
59 | true
60 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
61 | 1033
62 | $(BDS)\bin\default_app.manifest
63 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
64 |
65 |
66 | DEBUG;$(DCC_Define)
67 | false
68 | true
69 | true
70 | true
71 |
72 |
73 | false
74 |
75 |
76 | false
77 | RELEASE;$(DCC_Define)
78 | 0
79 | false
80 |
81 |
82 |
83 | MainSource
84 |
85 |
86 |
87 | dfm
88 |
89 |
90 | Cfg_2
91 | Base
92 |
93 |
94 | Base
95 |
96 |
97 | Cfg_1
98 | Base
99 |
100 |
101 |
102 | Delphi.Personality.12
103 |
104 |
105 |
106 |
107 | False
108 | False
109 | 1
110 | 0
111 | 0
112 | 0
113 | False
114 | False
115 | False
116 | False
117 | False
118 | 1033
119 | 1252
120 |
121 |
122 |
123 |
124 | 1.0.0.0
125 |
126 |
127 |
128 |
129 |
130 | 1.0.0.0
131 |
132 |
133 |
134 | AddressBook.dpr
135 |
136 |
137 |
138 |
139 | False
140 | True
141 |
142 |
143 | 12
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/AddressBook.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gerald-lindsly/mongo-delphi-driver/6f4e145bab99ad3d737c484a8d0c3f284828a6f6/AddressBook.res
--------------------------------------------------------------------------------
/AddressBookForm.dfm:
--------------------------------------------------------------------------------
1 | object Form1: TForm1
2 | Left = 0
3 | Top = 0
4 | Caption = 'MonogDelphiDriver Address Book'
5 | ClientHeight = 158
6 | ClientWidth = 363
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OldCreateOrder = False
14 | PixelsPerInch = 96
15 | TextHeight = 13
16 | object lblName: TLabel
17 | Left = 8
18 | Top = 8
19 | Width = 27
20 | Height = 13
21 | Caption = 'Name'
22 | end
23 | object lblAddress: TLabel
24 | Left = 8
25 | Top = 35
26 | Width = 39
27 | Height = 13
28 | Caption = 'Address'
29 | end
30 | object lblCity: TLabel
31 | Left = 8
32 | Top = 62
33 | Width = 19
34 | Height = 13
35 | Caption = 'City'
36 | end
37 | object lblState: TLabel
38 | Left = 175
39 | Top = 62
40 | Width = 26
41 | Height = 13
42 | Caption = 'State'
43 | end
44 | object lblZip: TLabel
45 | Left = 263
46 | Top = 62
47 | Width = 14
48 | Height = 13
49 | Caption = 'Zip'
50 | end
51 | object lblPhone: TLabel
52 | Left = 8
53 | Top = 88
54 | Width = 30
55 | Height = 13
56 | Caption = 'Phone'
57 | end
58 | object txtName: TEdit
59 | Left = 57
60 | Top = 5
61 | Width = 296
62 | Height = 21
63 | TabOrder = 0
64 | end
65 | object txtAddress: TEdit
66 | Left = 57
67 | Top = 32
68 | Width = 296
69 | Height = 21
70 | TabOrder = 1
71 | end
72 | object txtCity: TEdit
73 | Left = 57
74 | Top = 59
75 | Width = 112
76 | Height = 21
77 | TabOrder = 2
78 | end
79 | object txtState: TEdit
80 | Left = 207
81 | Top = 59
82 | Width = 50
83 | Height = 21
84 | TabOrder = 3
85 | end
86 | object txtZip: TEdit
87 | Left = 283
88 | Top = 59
89 | Width = 70
90 | Height = 21
91 | TabOrder = 4
92 | end
93 | object txtPhone: TEdit
94 | Left = 57
95 | Top = 86
96 | Width = 112
97 | Height = 21
98 | TabOrder = 5
99 | end
100 | object btnClear: TButton
101 | Left = 8
102 | Top = 125
103 | Width = 75
104 | Height = 25
105 | Caption = 'Clear'
106 | TabOrder = 6
107 | OnClick = btnClearClick
108 | end
109 | object btnSave: TButton
110 | Left = 94
111 | Top = 125
112 | Width = 75
113 | Height = 25
114 | Caption = 'Save'
115 | TabOrder = 7
116 | OnClick = btnSaveClick
117 | end
118 | object btnSearch: TButton
119 | Left = 280
120 | Top = 125
121 | Width = 75
122 | Height = 25
123 | Caption = 'Search'
124 | TabOrder = 8
125 | OnClick = btnSearchClick
126 | end
127 | object btnDelete: TButton
128 | Left = 182
129 | Top = 125
130 | Width = 75
131 | Height = 25
132 | Caption = 'Delete'
133 | TabOrder = 9
134 | OnClick = btnDeleteClick
135 | end
136 | object btnPrev: TButton
137 | Left = 175
138 | Top = 86
139 | Width = 18
140 | Height = 21
141 | Caption = '<'
142 | TabOrder = 10
143 | OnClick = btnPrevClick
144 | end
145 | object btnNext: TButton
146 | Left = 199
147 | Top = 86
148 | Width = 18
149 | Height = 21
150 | Caption = '>'
151 | TabOrder = 11
152 | OnClick = btnNextClick
153 | end
154 | end
155 |
--------------------------------------------------------------------------------
/AddressBookForm.pas:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | unit AddressBookForm;
17 |
18 | interface
19 |
20 | uses
21 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
22 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
23 | MongoDB, MongoBson;
24 |
25 | type
26 | TForm1 = class(TForm)
27 | lblName: TLabel;
28 | txtName: TEdit;
29 | lblAddress: TLabel;
30 | txtAddress: TEdit;
31 | lblCity: TLabel;
32 | txtCity: TEdit;
33 | lblState: TLabel;
34 | txtState: TEdit;
35 | lblZip: TLabel;
36 | txtZip: TEdit;
37 | lblPhone: TLabel;
38 | txtPhone: TEdit;
39 | btnClear: TButton;
40 | btnSave: TButton;
41 | btnSearch: TButton;
42 | btnDelete: TButton;
43 | btnPrev: TButton;
44 | btnNext: TButton;
45 | procedure btnClearClick(Sender: TObject);
46 | procedure btnSaveClick(Sender: TObject);
47 | procedure btnDeleteClick(Sender: TObject);
48 | procedure btnSearchClick(Sender: TObject);
49 | procedure btnPrevClick(Sender: TObject);
50 | procedure ShowRecord(b : TBson);
51 | procedure btnNextClick(Sender: TObject);
52 | end;
53 |
54 | var
55 | Form1: TForm1;
56 | mongo: TMongo;
57 |
58 | implementation
59 |
60 | {$R *.dfm}
61 |
62 | const
63 | db = 'test';
64 | ns = db + '.addresses';
65 |
66 | procedure TForm1.btnClearClick(Sender: TObject);
67 | begin
68 | txtName.Text := '';
69 | txtAddress.Text := '';
70 | txtCity.Text := '';
71 | txtState.Text := '';
72 | txtZip.Text := '';
73 | txtPhone.Text := '';
74 | end;
75 |
76 | procedure TForm1.btnDeleteClick(Sender: TObject);
77 | var
78 | query : TBson;
79 | begin
80 | query := BSON(['phone', txtPhone.Text]);
81 | if mongo.findOne(ns, query) = nil Then
82 | ShowMessage('A record with that phone number does not exist.')
83 | else if MessageDlg('Delete record for phone number ' + txtPhone.Text + '?',
84 | mtWarning, [mbYes, MbNo], 0) = mrYes then begin
85 | mongo.remove(ns, query);
86 | btnClearClick(Sender);
87 | ShowMessage('Record deleted.');
88 | end;
89 | end;
90 |
91 | procedure TForm1.ShowRecord(b : TBson);
92 | begin
93 | txtName.Text := b.value('name');
94 | txtAddress.Text := b.value('address');
95 | txtCity.Text := b.value('city');
96 | txtState.Text := b.value('state');
97 | txtZip.Text := b.value('zip');
98 | txtPhone.Text := b.value('phone');
99 | end;
100 |
101 | procedure TForm1.btnNextClick(Sender: TObject);
102 | var
103 | query, b : TBson;
104 | begin
105 | query := BSON(['phone', '{', '$gt', txtPhone.Text, '}']);
106 | b := mongo.findOne(ns, query);
107 | if b = nil then
108 | ShowMessage('No next record.')
109 | else
110 | ShowRecord(b);
111 | end;
112 |
113 | procedure TForm1.btnPrevClick(Sender: TObject);
114 | var
115 | query, b : TBson;
116 | begin
117 | query := BSON(['phone', '{', '$lt', txtPhone.Text, '}']);
118 | b := mongo.findOne(ns, query);
119 | if b = nil then
120 | ShowMessage('No previous record.')
121 | else
122 | ShowRecord(b);
123 | end;
124 |
125 |
126 | procedure TForm1.btnSaveClick(Sender: TObject);
127 | var
128 | bb : TBsonBuffer;
129 | b : TBson;
130 | query : TBson;
131 | begin
132 | query := BSON(['phone', txtPhone.Text]);
133 | if (mongo.findOne(ns, query) = nil) Or
134 | (MessageDlg('A record already exists with that phone number. Replace?', mtWarning, [mbYes, MbNo], 0) = mrYes) then begin
135 | bb := TbsonBuffer.Create();
136 | bb.append('name', txtName.Text);
137 | bb.append('address', txtAddress.Text);
138 | bb.append('city', txtCity.Text);
139 | bb.append('state', txtState.Text);
140 | bb.append('zip', txtZip.Text);
141 | bb.append('phone', txtPhone.Text);
142 | b := bb.finish();
143 | mongo.update(ns, query, b, updateUpsert);
144 | ShowMessage('Record saved.');
145 | end;
146 | end;
147 |
148 | procedure TForm1.btnSearchClick(Sender: TObject);
149 | var
150 | bb : TBsonBuffer;
151 | query, b : TBson;
152 | begin
153 | bb := TbsonBuffer.Create();
154 | if txtName.Text <> '' then begin
155 | bb.startObject('name');
156 | bb.append('$regex', txtName.Text);
157 | bb.append('$options', 'i');
158 | bb.finishObject();
159 | end;
160 | if txtAddress.Text <> '' then begin
161 | bb.startObject('address');
162 | bb.append('$regex', txtAddress.Text);
163 | bb.append('$options', 'i');
164 | bb.finishObject();
165 | end;
166 | if txtCity.Text <> '' then begin
167 | bb.startObject('city');
168 | bb.append('$regex', txtCity.Text);
169 | bb.append('$options', 'i');
170 | bb.finishObject();
171 | end;
172 | if txtState.Text <> '' then begin
173 | bb.startObject('state');
174 | bb.append('$regex', txtState.Text);
175 | bb.append('$options', 'i');
176 | bb.finishObject();
177 | end;
178 | if txtZip.Text <> '' then begin
179 | bb.startObject('zip');
180 | bb.append('$regex', txtZip.Text);
181 | bb.append('$options', 'i');
182 | bb.finishObject();
183 | end;
184 | if txtPhone.Text <> '' then begin
185 | bb.startObject('phone');
186 | bb.append('$regex', txtPhone.Text);
187 | bb.append('$options', 'i');
188 | bb.finishObject();
189 | end;
190 | query := bb.finish();
191 | b := mongo.findOne(ns, query);
192 | if b = nil then
193 | ShowMessage('No match')
194 | else
195 | ShowRecord(b);
196 | end;
197 |
198 |
199 | const
200 | NoConnectMsg = 'Unable to connect to a MongoDB server running on localhost';
201 |
202 | initialization
203 | mongo := TMongo.Create();
204 | if not mongo.isConnected() then begin
205 | ShowMessage(NoConnectMsg);
206 | Halt(1);
207 | end;
208 | mongo.indexCreate(ns, 'phone');
209 |
210 |
211 | end.
212 |
--------------------------------------------------------------------------------
/COPYRIGHT.txt:
--------------------------------------------------------------------------------
1 | Copyright 2011 10gen Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/GridFS.pas:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | { GridFS Unit - The classes in this unit are used to store and/or
17 | access a "Grid File System" (GridFS) on a MongoDB server.
18 | While primarily intended to store large documents that
19 | won't fit on the server as a single BSON object,
20 | GridFS may also be used to store large numbers of smaller files.
21 |
22 | See http://www.mongodb.org/display/DOCS/GridFS and
23 | http://www.mongodb.org/display/DOCS/When+to+use+GridFS.
24 |
25 | Objects of class TGridFS represent the interface to the GridFS.
26 | Objects of class TGridfile are used to access gridfiles and read from them.
27 | Objects of class TGridfileWriter are used to write buffered data to the GridFS.
28 | }
29 | unit GridFS;
30 |
31 | interface
32 | Uses
33 | MongoDB, MongoBson;
34 |
35 | type
36 | TGridfile = class;
37 | TGridfileWriter = class;
38 |
39 | TGridFS = class(TObject)
40 | private
41 | var
42 | { Pointer to externally managed data representing the GridFS }
43 | handle : Pointer;
44 | { Holds a reference to the TMongo object used in construction.
45 | Prevents release until the TGridFS is destroyed. }
46 | conn : TMongo;
47 | public
48 | { Create a TGridFS object for accessing the GridFS on the MongoDB server.
49 | Parameter mongo is an already established connection object to the
50 | server; db is the name of the database in which to construct the GridFS.
51 | The prefix defaults to 'fs'.}
52 | constructor Create(mongo : TMongo; db : string); overload;
53 | { Create a TGridFS object for accessing the GridFS on the MongoDB server.
54 | Parameter mongo is an already established connection object to the
55 | server; db is the name of the database in which to construct the GridFS.
56 | prefix is appended to the database name for the collections that represent
57 | the GridFS: 'db.prefix.files' & 'db.prefix.chunks'. }
58 | constructor Create(mongo : TMongo; db : string; prefix : string); overload;
59 | { Store a file on the GridFS. filename is the path to the file.
60 | Returns True if successful; otherwise, False. }
61 | function storeFile(filename : string) : Boolean; overload;
62 | { Store a file on the GridFS. filename is the path to the file.
63 | remoteName is the name that the file will be known as within the GridFS.
64 | Returns True if successful; otherwise, False. }
65 | function storeFile(filename : string; remoteName : string) : Boolean; overload;
66 | { Store a file on the GridFS. filename is the path to the file.
67 | remoteName is the name that the file will be known as within the GridFS.
68 | contentType is the MIME-type content type of the file.
69 | Returns True if successful; otherwise, False. }
70 | function storeFile(filename : string; remoteName : string; contentType : string) : Boolean; overload;
71 | { Remove a file from the GridFS. }
72 | procedure removeFile(remoteName : string);
73 | { Store data as a GridFS file. Pointer is the address of the data and length
74 | is its size. remoteName is the name that the file will be known as within the GridFS.
75 | Returns True if successful; otherwise, False. }
76 | function store(p : Pointer; length : Int64; remoteName : string) : Boolean; overload;
77 | { Store data as a GridFS file. Pointer is the address of the data and length
78 | is its size. remoteName is the name that the file will be known as within the GridFS.
79 | contentType is the MIME-type content type of the file.
80 | Returns True if successful; otherwise, False. }
81 | function store(p : Pointer; length : Int64; remoteName : string; contentType : string) : Boolean; overload;
82 | { Create a TGridfileWriter object for writing buffered data to a GridFS file.
83 | remoteName is the name that the file will be known as within the GridFS. }
84 | function writerCreate(remoteName : string) : TGridfileWriter; overload;
85 | { Create a TGridfileWriter object for writing buffered data to a GridFS file.
86 | remoteName is the name that the file will be known as within the GridFS.
87 | contentType is the MIME-type content type of the file. }
88 | function writerCreate(remoteName : string; contentType : string) : TGridfileWriter; overload;
89 | { Locate a GridFS file by its remoteName and return a TGridfile object for
90 | accessing it. }
91 | function find(remoteName : string) : TGridfile; overload;
92 | { Locate a GridFS file by an TBson query document on the GridFS file descriptors.
93 | Returns a TGridfile object for accessing it. }
94 | function find(query : TBson) : TGridfile; overload;
95 | { Destroy this GridFS object. Releases external resources. }
96 | destructor Destroy(); override;
97 | end;
98 |
99 | { Objects of class TGridfile are used to access gridfiles and read from them. }
100 | TGridfile = class(TObject)
101 | private
102 | var
103 | { Pointer to externally managed data representing the gridfile }
104 | handle : Pointer;
105 | { Hold a reference to the TGridFS object used in construction of this
106 | TGridfile. Prevents release until this TGridfile is destroyed. }
107 | gfs : TGridFS;
108 | { Create a TGridfile object. Internal use only by TGridFS.find(). }
109 | constructor Create(gridfs : TGridFS);
110 | public
111 | { Get the filename (remoteName) of this gridfile. }
112 | function getFilename() : string;
113 | { Get the size of the chunks into which the file is divided. }
114 | function getChunkSize() : Integer;
115 | { Get the length of this gridfile. }
116 | function getLength() : Int64;
117 | { Get the content type of this gridfile. }
118 | function getContentType() : string;
119 | { Get the upload date of this gridfile. }
120 | function getUploadDate() : TDateTime;
121 | { Get the MD5 hash of this gridfile. This is a 16-digit hex string. }
122 | function getMD5() : string;
123 | { Get any metadata associated with this gridfile as a TBson document.
124 | Returns nil if there is none. }
125 | function getMetadata() : TBson;
126 | { Get the number of chunks into which the file is divided. }
127 | function getChunkCount() : Integer;
128 | { Get the descriptor of this gridfile as a TBson document. }
129 | function getDescriptor() : TBson;
130 | { Get the Ith chunk of this gridfile. The content of the chunk is
131 | in the 'data' field of the returned TBson document. Returns nil
132 | if i is not in the range 0 to getChunkCount() - 1. }
133 | function getChunk(i : Integer) : TBson;
134 | { Get a cursor for stepping through a range of chunks of this gridfile.
135 | i is the index of the first chunk to be returned. count is the number
136 | of chunks to return. Returns nil if there are no chunks in the
137 | specified range. }
138 | function getChunks(i : Integer; count : Integer) : TMongoCursor;
139 | { Read data from this gridfile. The gridfile maintains a current position
140 | so that successive reads will return consecutive data. The data is
141 | read to the address indicated by p and length bytes are read. The size
142 | of the data read is returned and can be less than length if there was
143 | not enough data remaining to be read. }
144 | function read(p : Pointer; length : Int64) : Int64;
145 | { Seek to a specified offset within the gridfile. read() will then
146 | return data starting at that location. Returns the position that
147 | was set. This can be at the end of the gridfile if offset is greater
148 | the length of this gridfile. }
149 | function seek(offset : Int64) : Int64;
150 | { Destroy this TGridfile object. Releases external resources. }
151 | destructor Destroy(); override;
152 | end;
153 |
154 | { Objects of class TGridfileWriter are used to write buffered data to the GridFS. }
155 | TGridfileWriter = class(TObject)
156 | private
157 | var
158 | { Holds a pointer to externally managed data representing the TGridfileWriter. }
159 | handle : Pointer;
160 | { Holds a reference to the TGridFS object used in construction.
161 | Prevents release of the TGridFS until this TGridfileWriter is destroyed. }
162 | gfs : TGridFS;
163 | public
164 | { Create a TGridfile writer on the given TGridFS that will write data to
165 | the given remoteName. }
166 | constructor Create(gridfs : TGridFS; remoteName : string); overload;
167 | { Create a TGridfile writer on the given TGridFS that will write data to
168 | the given remoteName. contentType is the MIME-type content type of the gridfile
169 | to be written. }
170 | constructor Create(gridfs : TGridFS; remoteName : string; contentType : string); overload;
171 | { Write data to this TGridfileWriter. p is the address of the data and length
172 | is its size. Multiple calls to write() may be made to append successive
173 | data. }
174 | procedure write(p : Pointer; length : Int64);
175 | { Finish with this TGridfileWriter. Flushes any data remaining to be written
176 | to a chunk and posts the 'directory' information of the gridfile to the
177 | GridFS. Returns True if successful; otherwise, False. }
178 | function finish() : Boolean;
179 | { Destroy this TGridfileWriter. Calls finish() if necessary and releases
180 | external resources. }
181 | destructor Destroy(); override;
182 | end;
183 |
184 | implementation
185 | uses
186 | SysUtils;
187 |
188 | function gridfs_create() : Pointer; cdecl; external 'mongoc.dll';
189 | procedure gridfs_dispose(g : Pointer); cdecl; external 'mongoc.dll';
190 | function gridfs_init(c : Pointer; db : PAnsiChar; prefix : PAnsiChar; g : Pointer) : Integer;
191 | cdecl; external 'mongoc.dll';
192 | procedure gridfs_destroy(g : Pointer); cdecl; external 'mongoc.dll';
193 | function gridfs_store_file(g : Pointer; filename : PAnsiChar; remoteName : PAnsiChar; contentType : PAnsiChar) : Integer;
194 | cdecl; external 'mongoc.dll';
195 | procedure gridfs_remove_filename(g : Pointer; remoteName : PAnsiChar); cdecl; external 'mongoc.dll';
196 | function gridfs_store_buffer(g : Pointer; p : Pointer; size : Int64; remoteName : PAnsiChar; contentType : PAnsiChar) : Integer;
197 | cdecl; external 'mongoc.dll';
198 | function gridfile_create() : Pointer; cdecl; external 'mongoc.dll';
199 | procedure gridfile_dispose(gf : Pointer); cdecl; external 'mongoc.dll';
200 | procedure gridfile_writer_init(gf : Pointer; gfs : Pointer; remoteName : PAnsiChar; contentType : PAnsiChar);
201 | cdecl; external 'mongoc.dll';
202 | procedure gridfile_write_buffer(gf : Pointer; data : Pointer; length : Int64);
203 | cdecl; external 'mongoc.dll';
204 | function gridfile_writer_done(gf : Pointer) : Integer; cdecl; external 'mongoc.dll';
205 | function gridfs_find_query(g : Pointer; query : Pointer; gf : Pointer) : Integer;
206 | cdecl; external 'mongoc.dll';
207 | procedure gridfile_destroy(gf : Pointer); cdecl; external 'mongoc.dll';
208 | function gridfile_get_filename(gf : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
209 | function gridfile_get_chunksize(gf : Pointer) : Integer; cdecl; external 'mongoc.dll';
210 | function gridfile_get_contentlength(gf : Pointer) : Int64; cdecl; external 'mongoc.dll';
211 | function gridfile_get_contenttype(gf : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
212 | function gridfile_get_uploaddate(gf : Pointer) : Int64; cdecl; external 'mongoc.dll';
213 | function gridfile_get_md5(gf : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
214 | procedure gridfile_get_metadata(gf : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
215 | function bson_create() : Pointer; cdecl; external 'mongoc.dll';
216 | procedure bson_dispose(b : Pointer); cdecl; external 'mongoc.dll';
217 | function bson_size(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
218 | procedure bson_copy(dest : Pointer; src : Pointer); cdecl; external 'mongoc.dll';
219 | function gridfile_get_numchunks(gf : Pointer) : Integer; cdecl; external 'mongoc.dll';
220 | procedure gridfile_get_descriptor(gf : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
221 | procedure gridfile_get_chunk(gf : Pointer; i : Integer; b : Pointer); cdecl; external 'mongoc.dll';
222 | function gridfile_get_chunks(gf : Pointer; i : Integer; count : Integer) : Pointer;
223 | cdecl; external 'mongoc.dll';
224 | function gridfile_read(gf : Pointer; size : Int64; buf : Pointer) : Int64;
225 | cdecl; external 'mongoc.dll';
226 | function gridfile_seek(gf : Pointer; offset : Int64) : Int64;
227 | cdecl; external 'mongoc.dll';
228 |
229 |
230 | constructor TGridFS.Create(mongo: TMongo; db: string; prefix : string);
231 | begin
232 | conn := mongo;
233 | handle := gridfs_create();
234 | if gridfs_init(mongo.handle, PAnsiChar(System.UTF8Encode(db)),
235 | PAnsiChar(System.UTF8Encode(prefix)), handle) <> 0 then begin
236 | gridfs_dispose(handle);
237 | Raise Exception.Create('Unable to create GridFS');
238 | end;
239 | end;
240 |
241 | constructor TGridFS.Create(mongo: TMongo; db: string);
242 | begin
243 | Create(mongo, db, 'fs');
244 | end;
245 |
246 | destructor TGridFS.Destroy();
247 | begin
248 | gridfs_destroy(handle);
249 | gridfs_dispose(handle);
250 | end;
251 |
252 | function TGridFS.storeFile(filename : string; remoteName : string; contentType : string) : Boolean;
253 | begin
254 | Result := (gridfs_store_file(handle, PAnsiChar(System.UTF8Encode(filename)),
255 | PAnsiChar(System.UTF8Encode(remoteName)),
256 | PAnsiChar(System.UTF8Encode(contentType))) = 0);
257 | end;
258 |
259 | function TGridFS.storeFile(filename : string; remoteName : string) : Boolean;
260 | begin
261 | Result := storeFile(filename, remoteName, '');
262 | end;
263 |
264 | function TGridFS.storeFile(filename : string) : Boolean;
265 | begin
266 | Result := storeFile(filename, filename, '');
267 | end;
268 |
269 | procedure TGridFS.removeFile(remoteName : string);
270 | begin
271 | gridfs_remove_filename(handle, PAnsiChar(System.UTF8Encode(remoteName)));
272 | end;
273 |
274 | function TGridFS.store(p : Pointer; length : Int64; remoteName : string; contentType : string) : Boolean;
275 | begin
276 | Result := (gridfs_store_buffer(handle, p, length, PAnsiChar(System.UTF8Encode(remoteName)),
277 | PAnsiChar(System.UTF8Encode(contentType))) = 0);
278 | end;
279 |
280 | function TGridFS.store(p : Pointer; length : Int64; remoteName : string) : Boolean;
281 | begin
282 | Result := store(p, length, remoteName, '');
283 | end;
284 |
285 | function TGridFS.writerCreate(remoteName : string; contentType : string) : TGridfileWriter;
286 | begin
287 | Result := TGridfileWriter.Create(Self, remoteName, contentType);
288 | end;
289 |
290 | function TGridFS.writerCreate(remoteName : string) : TGridfileWriter;
291 | begin
292 | Result := writerCreate(remoteName, '');
293 | end;
294 |
295 | constructor TGridfileWriter.Create(gridfs : TGridFS; remoteName : string; contentType : string);
296 | begin
297 | gfs := gridfs;
298 | handle := gridfile_create();
299 | gridfile_writer_init(handle, gridfs.handle, PAnsiChar(System.UTF8Encode(remoteName)), PAnsiChar(System.UTF8Encode(contentType)));
300 | end;
301 |
302 | constructor TGridfileWriter.Create(gridfs : TGridFS; remoteName : string);
303 | begin
304 | Create(gridfs, remoteName, '');
305 | end;
306 |
307 | procedure TGridfileWriter.write(p: Pointer; length: Int64);
308 | begin
309 | gridfile_write_buffer(handle, p, length);
310 | end;
311 |
312 | function TGridfileWriter.finish() : Boolean;
313 | begin
314 | if handle = nil then
315 | Result := True
316 | else begin
317 | Result := (gridfile_writer_done(handle) = 0);
318 | gridfile_dispose(handle);
319 | handle := nil;
320 | end;
321 | end;
322 |
323 | destructor TGridfileWriter.Destroy();
324 | begin
325 | finish();
326 | end;
327 |
328 | function TGridFS.find(query : TBson) : TGridfile;
329 | var
330 | gf : TGridfile;
331 | begin
332 | gf := TGridfile.Create(Self);
333 | if gridfs_find_query(handle, query.handle, gf.handle) = 0 then
334 | Result := gf
335 | else begin
336 | gf.Free;
337 | Result := nil;
338 | end;
339 | end;
340 |
341 | function TGridFS.find(remoteName : string) : TGridfile;
342 | begin
343 | Result := find(BSON(['filename', System.UTF8Encode(remoteName)]));
344 | end;
345 |
346 | constructor TGridfile.Create(gridfs : TGridFS);
347 | begin
348 | gfs := gridfs;
349 | handle := gridfile_create();
350 | end;
351 |
352 | destructor TGridfile.Destroy();
353 | begin
354 | if handle <> nil then begin
355 | gridfile_destroy(handle);
356 | gridfile_dispose(handle);
357 | handle := nil;
358 | end;
359 | end;
360 |
361 | function TGridfile.getFilename() : string;
362 | begin
363 | Result := string(System.UTF8ToWideString(gridfile_get_filename(handle)));
364 | end;
365 |
366 | function TGridfile.getChunkSize() : Integer;
367 | begin
368 | Result := gridfile_get_chunksize(handle);
369 | end;
370 |
371 | function TGridfile.getLength() : Int64;
372 | begin
373 | Result := gridfile_get_contentlength(handle);
374 | end;
375 |
376 | function TGridfile.getContentType() : string;
377 | begin
378 | Result := string(System.UTF8ToWideString(gridfile_get_contenttype(handle)));
379 | end;
380 |
381 | function TGridfile.getUploadDate() : TDateTime;
382 | begin
383 | Result := Int64toDouble(gridfile_get_uploaddate(handle)) / (1000 * 24 * 60 * 60) + 25569;
384 | end;
385 |
386 | function TGridfile.getMD5() : string;
387 | begin
388 | Result := string(gridfile_get_md5(handle));
389 | end;
390 |
391 | function TGridfile.getMetadata() : TBson;
392 | var
393 | b : Pointer;
394 | res : TBson;
395 | begin
396 | b := bson_create();
397 | gridfile_get_metadata(handle, b);
398 | if bson_size(b) <= 5 then
399 | Result := nil
400 | else begin
401 | res := TBson.Create(bson_create());
402 | bson_copy(res.handle, b);
403 | Result := res;
404 | end;
405 | bson_dispose(b);
406 | end;
407 |
408 | function TGridfile.getChunkCount() : Integer;
409 | begin
410 | Result := gridfile_get_numchunks(handle);
411 | end;
412 |
413 | function TGridfile.getDescriptor() : TBson;
414 | var
415 | b : Pointer;
416 | res : TBson;
417 | begin
418 | b := bson_create();
419 | gridfile_get_descriptor(handle, b);
420 | res := TBson.Create(bson_create());
421 | bson_copy(res.handle, b);
422 | bson_dispose(b);
423 | Result := res;
424 | end;
425 |
426 | function TGridfile.getChunk(i : Integer) : TBson;
427 | var
428 | b : TBson;
429 | begin
430 | b := TBson.Create(bson_create());
431 | gridfile_get_chunk(handle, i, b.handle);
432 | if b.size() <= 5 then
433 | begin
434 | b.Free;
435 | Result := nil;
436 | end
437 | else
438 | Result := b;
439 | end;
440 |
441 | function TGridfile.getChunks(i : Integer; count : Integer) : TMongoCursor;
442 | var
443 | cursor : TMongoCursor;
444 | begin
445 | cursor := TMongoCursor.Create();
446 | cursor.handle := gridfile_get_chunks(handle, i, count);
447 | if cursor.handle = nil then
448 | begin
449 | cursor.free;
450 | Result := nil;
451 | end
452 | else
453 | Result := cursor;
454 | end;
455 |
456 | function TGridfile.read(p : Pointer; length : Int64) : Int64;
457 | begin
458 | Result := gridfile_read(handle, length, p);
459 | end;
460 |
461 | function TGridfile.seek(offset : Int64) : Int64;
462 | begin
463 | Result := gridfile_seek(handle, offset);
464 | end;
465 |
466 |
467 | end.
468 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/MongoBson.pas:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | { This unit implements BSON, a binary JSON-like document format.
17 | It is used to represent documents in MongoDB and also for network traffic.
18 | See http://www.mongodb.org/display/DOCS/BSON }
19 |
20 | unit MongoBson;
21 |
22 | interface
23 | type TBson = class;
24 | TIntegerArray = array of Integer;
25 | TDoubleArray = array of Double;
26 | TBooleanArray = array of Boolean;
27 | TStringArray = array of string;
28 |
29 | { A value of TBsonType indicates the type of the data associated
30 | with a field within a BSON document. }
31 | TBsonType = (
32 | bsonEOO = 0,
33 | bsonDOUBLE = 1,
34 | bsonSTRING = 2,
35 | bsonOBJECT = 3,
36 | bsonARRAY = 4,
37 | bsonBINDATA = 5,
38 | bsonUNDEFINED = 6,
39 | bsonOID = 7,
40 | bsonBOOL = 8,
41 | bsonDATE = 9,
42 | bsonNULL = 10,
43 | bsonREGEX = 11,
44 | bsonDBREF = 12, (* Deprecated. *)
45 | bsonCODE = 13,
46 | bsonSYMBOL = 14,
47 | bsonCODEWSCOPE = 15,
48 | bsonINT = 16,
49 | bsonTIMESTAMP = 17,
50 | bsonLONG = 18);
51 |
52 | TBsonIterator = class;
53 |
54 | { A TBsonOID is used to store BSON Object IDs.
55 | See http://www.mongodb.org/display/DOCS/Object+IDs }
56 | TBsonOID = class(TObject)
57 | var
58 | { the oid data }
59 | value : array[0..11] of Byte;
60 | { Generate an Object ID }
61 | constructor Create(); overload;
62 | { Create an ObjectID from a 24-digit hex string }
63 | constructor Create(s : string); overload;
64 | { Create an Object ID from a TBsonIterator pointing to an oid field }
65 | constructor Create(i : TBsonIterator); overload;
66 | { Convert this Object ID to a 24-digit hex string }
67 | function AsString() : string;
68 | end;
69 |
70 | { A TBsonCodeWScope is used to hold javascript code and its associated scope.
71 | See TBsonIterator.getCodeWScope() }
72 | TBsonCodeWScope = class(TObject)
73 | var
74 | code : string;
75 | scope : TBson;
76 | { Create a TBsonCodeWScope from a javascript string and a TBson scope }
77 | constructor Create(code_ : string; scope_ : TBson); overload;
78 | { Create a TBsonCodeWScope from a TBSonIterator pointing to a
79 | CODEWSCOPE field. }
80 | constructor Create(i : TBsonIterator); overload;
81 | end;
82 |
83 | { A TBsonRegex is used to hold a regular expression string and its options.
84 | See TBsonIterator.getRegex(). }
85 | TBsonRegex = class(TObject)
86 | var
87 | pattern : string;
88 | options : string;
89 | { Create a TBsonRegex from reqular expression and options strings }
90 | constructor Create(pattern_ : string; options_ : string); overload;
91 | { Create a TBsonRegex from a TBsonIterator pointing to a REGEX field }
92 | constructor Create(i : TBsonIterator); overload;
93 | end;
94 |
95 | { A TBsonTimestamp is used to hold a TDateTime and an increment value.
96 | See http://www.mongodb.org/display/DOCS/Timestamp+data+type and
97 | TBsonIterator.getTimestamp() }
98 | TBsonTimestamp = class(TObject)
99 | var
100 | time : TDateTime;
101 | increment : Integer;
102 | { Create a TBsonTimestamp from a TDateTime and an increment }
103 | constructor Create(time_ : TDateTime; increment_ : Integer); overload;
104 | { Create a TBSonTimestamp from a TBsonIterator pointing to a TIMESTAMP
105 | field. }
106 | constructor Create(i : TBsonIterator); overload;
107 | end;
108 |
109 | { A TBsonBinary is used to hold the contents of BINDATA fields.
110 | See TBsonIterator.getBinary() }
111 | TBsonBinary = class(TObject)
112 | var
113 | { Pointer to data allocated on the heap with GetMem }
114 | data : Pointer;
115 | { The length of the data in bytes }
116 | len : Integer;
117 | { The subtype of the BINDATA (usually 0) }
118 | kind : Integer;
119 | { Create a TBsonBinary from a pointer and a length. The data
120 | is copied to the heap. kind is initialized to 0 }
121 | constructor Create(p : Pointer; length : Integer); overload;
122 | { Create a TBsonBinary from a TBsonIterator pointing to a BINDATA
123 | field. }
124 | constructor Create(i : TBsonIterator); overload;
125 | { Destroys the TBsonBinary and releases its memory with FreeMem() }
126 | destructor Destroy(); override;
127 | end;
128 |
129 | { A TBsonBuffer is used to build a BSON document by appending the
130 | names and values of fields. Call finish() when done to convert
131 | the buffer to a TBson which can be used in database operations.
132 | Example: @longcode(#
133 | var
134 | bb : TBsonBuffer;
135 | b : TBson;
136 | begin
137 | bb := TBsonBuffer.Create();
138 | bb.append('name', 'Joe');
139 | bb.append('age', 33);
140 | bb.append('city', 'Boston');
141 | b := bb.finish();
142 | end;
143 | #) }
144 | TBsonBuffer = class(TObject)
145 | private
146 | var handle : Pointer;
147 | public
148 | { Create an empty TBsonBuffer ready to have fields appended. }
149 | constructor Create();
150 | { Append a string (PAnsiChar) to the buffer }
151 | function append(name : string; value : PAnsiChar) : Boolean; overload;
152 | { Append an Integer to the buffer }
153 | function append(name : string; value : Integer) : Boolean; overload;
154 | { Append an Int64 to the buffer }
155 | function append(name : string; value : Int64) : Boolean; overload;
156 | { Append a Double to the buffer }
157 | function append(name : string; value : Double) : Boolean; overload;
158 | { Append a TDateTime to the buffer; converted to 64-bit POSIX time }
159 | function append(name : string; value : TDateTime) : Boolean; overload;
160 | { Append a Boolean to the buffer }
161 | function append(name : string; value : Boolean) : Boolean; overload;
162 | { Append an Object ID to the buffer }
163 | function append(name : string; value : TBsonOID) : Boolean; overload;
164 | { Append a CODEWSCOPE to the buffer }
165 | function append(name : string; value : TBsonCodeWScope) : Boolean; overload;
166 | { Append a REGEX to the buffer }
167 | function append(name : string; value : TBsonRegex) : Boolean; overload;
168 | { Append a TIMESTAMP to the buffer }
169 | function append(name : string; value : TBsonTimestamp) : Boolean; overload;
170 | { Append BINDATA to the buffer }
171 | function append(name : string; value : TBsonBinary) : Boolean; overload;
172 | { Append a TBson document as a subobject }
173 | function append(name : string; value : TBson) : Boolean; overload;
174 | { Generic version of append. Calls one of the other append functions
175 | if the type contained in the variant is supported. }
176 | function append(name : string; value : OleVariant) : Boolean; overload;
177 | { Append an array of Integers }
178 | function appendArray(name : string; value : array of Integer) : Boolean; overload;
179 | { Append an array of Doubles }
180 | function appendArray(name : string; value : array of Double) : Boolean; overload;
181 | { Append an array of Booleans }
182 | function appendArray(name : string; value : array of Boolean) : Boolean; overload;
183 | { Append an array of strings }
184 | function appendArray(name : string; value : array of string) : Boolean; overload;
185 | { Append a NULL field to the buffer }
186 | function appendNull(name : string) : Boolean;
187 | { Append an UNDEFINED field to the buffer }
188 | function appendUndefined(name : string) : Boolean;
189 | { Append javascript code to the buffer }
190 | function appendCode(name : string; value : PAnsiChar) : Boolean;
191 | { Append a SYMBOL to the buffer }
192 | function appendSymbol(name : string; value : PAnsiChar) : Boolean;
193 | { Alternate way to append BINDATA directly without first creating a
194 | TBsonBinary value }
195 | function appendBinary(name : string; kind : Integer; data : Pointer; length : Integer) : Boolean;
196 | { Indicate that you will be appending more fields as a subobject }
197 | function startObject(name : string) : Boolean;
198 | { Indicate that you will be appending more fields as an array }
199 | function startArray(name : string) : Boolean;
200 | { Indicate that a subobject or array is done. }
201 | function finishObject() : Boolean;
202 | { Return the current size of the BSON document you are building }
203 | function size() : Integer;
204 | { Call this when finished appending fields to the buffer to turn it into
205 | a TBson for network transport. }
206 | function finish() : TBson;
207 | { Destroy this TBsonBuffer. Releases external resources. }
208 | destructor Destroy(); override;
209 | end;
210 |
211 | { A TBson holds a BSON document. BSON is a binary, JSON-like document format.
212 | It is used to represent documents in MongoDB and also for network traffic.
213 | See http://www.mongodb.org/display/DOCS/BSON }
214 | TBson = class(TObject)
215 | { Pointer to externally managed data. User code should not modify this.
216 | It is public only because the MongoDB and GridFS units must access it. }
217 | var handle : Pointer;
218 | { Return the size of this BSON document in bytes }
219 | function size() : Integer;
220 | { Get a TBsonIterator that points to the first field of this BSON }
221 | function iterator() : TBsonIterator;
222 | { Get a TBsonIterator that points to the field with the given name.
223 | If name is not found, nil is returned. }
224 | function find(name : string) : TBsonIterator;
225 | { Get the value of a field given its name. This function does not support
226 | all BSON field types. Use find() and one of the 'get' functions of
227 | TBsonIterator to retrieve special values. }
228 | function value(name : string) : Variant;
229 | { Display this BSON document on the console. subobjects and arrays are
230 | appropriately indented. }
231 | procedure display();
232 | { Create a TBson given a pointer to externally managed data describing
233 | the document. User code should not instantiate TBson directly. Use
234 | TBsonBuffer and finish() to create BSON documents. }
235 | constructor Create(h : Pointer);
236 | { Destroy this TBson. Releases the externally managed data. }
237 | destructor Destroy; override;
238 | end;
239 |
240 | { TBsonIterators are used to step through the fields of a TBson document. }
241 | TBsonIterator = class(TObject)
242 | private
243 | { Pointer to externally managed data. }
244 | var handle : Pointer;
245 | public
246 | { Return the TBsonType of the field pointed to by this iterator. }
247 | function kind() : TBsonType;
248 | { Return the key (or name) of the field pointed to by this iterator. }
249 | function key() : string;
250 | { Step to the first or next field of a TBson document. Returns True
251 | if there is a next field; otherwise, returns false at the end of the
252 | document (or subobject).
253 | Example: @longcode(#
254 | iter := b.iterator;
255 | while i.next() do
256 | if i.kind = bsonNULL then
257 | WriteLn(i.key, ' is a NULL field.');
258 | #) }
259 | function next() : Boolean;
260 | { Get the value of the field pointed to by this iterator. This function
261 | does not support all BSON field types and will throw an exception for
262 | those it does not. Use one of the 'get' functions to extract one of these
263 | special types. }
264 | function value() : Variant;
265 | { Get an TBsonIterator pointing to the first field of a subobject or array.
266 | kind() must be bsonOBJECT or bsonARRAY. }
267 | function subiterator() : TBsonIterator;
268 | { Get an Object ID from the field pointed to by this iterator. }
269 | function getOID() : TBsonOID;
270 | { Get a TBsonCodeWScope object for a CODEWSCOPE field pointed to by this
271 | iterator. }
272 | function getCodeWScope() : TBsonCodeWScope;
273 | { Get a TBsonRegex for a REGEX field }
274 | function getRegex() : TBsonRegex;
275 | { Get a TBsonTimestamp object for a TIMESTAMP field pointed to by this
276 | iterator. }
277 | function getTimestamp() : TBsonTimestamp;
278 | { Get a TBsonBinary object for the BINDATA field pointed to by this
279 | iterator. }
280 | function getBinary() : TBsonBinary;
281 | { Get an array of Integers. This iterator must point to ARRAY field
282 | which has each component type as Integer }
283 | function getIntegerArray() : TIntegerArray;
284 | { Get an array of Doubles. This iterator must point to ARRAY field
285 | which has each component type as Double }
286 | function getDoubleArray() : TDoubleArray;
287 | { Get an array of strings. This iterator must point to ARRAY field
288 | which has each component type as string }
289 | function getStringArray() : TStringArray;
290 | { Get an array of Booleans. This iterator must point to ARRAY field
291 | which has each component type as Boolean }
292 | function getBooleanArray() : TBooleanArray;
293 | { Internal usage only. Create an uninitialized TBsonIterator }
294 | constructor Create(); overload;
295 | { Create a TBsonIterator that points to the first field of the given
296 | TBson }
297 | constructor Create(b : TBson); overload;
298 | { Destroy this TBsonIterator. Releases external resources. }
299 | destructor Destroy; override;
300 | end;
301 |
302 | var
303 | { An empty BSON document }
304 | bsonEmpty : TBson;
305 |
306 | (* The idea for this shorthand way to build a BSON
307 | document from an array of variants came from Stijn Sanders
308 | and his TMongoWire, located here:
309 | https://github.com/stijnsanders/TMongoWire
310 |
311 | Subobjects are started with '{' and ended with '}'
312 |
313 | Example: @longcode(#
314 | var b : TBson;
315 | begin
316 | b := BSON(['name', 'Albert', 'age', 64,
317 | 'address', '{',
318 | 'street', '109 Vine Street',
319 | 'city', 'New Haven',
320 | '}' ]);
321 | #) *)
322 | function BSON(x : array of OleVariant) : TBson;
323 |
324 | { Convert a byte to a 2-digit hex string }
325 | function ByteToHex(InByte : Byte) : string;
326 |
327 | { Convert an Int64 to a Double. Some loss of precision may occur. }
328 | function Int64toDouble(i64 : int64) : double;
329 | cdecl; external 'mongoc.dll' name 'bson_int64_to_double';
330 |
331 | implementation
332 | uses SysUtils, Variants;
333 |
334 | procedure set_bson_err_handler(err_handler : Pointer); cdecl; external 'mongoc.dll';
335 |
336 | function bson_create() : Pointer; cdecl; external 'mongoc.dll';
337 | procedure bson_init(b : Pointer); cdecl; external 'mongoc.dll';
338 | procedure bson_destroy(b : Pointer); cdecl; external 'mongoc.dll';
339 | procedure bson_dispose(b : Pointer); cdecl; external 'mongoc.dll';
340 | procedure bson_copy(dest : Pointer; src : Pointer); cdecl; external 'mongoc.dll';
341 | function bson_finish(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
342 | procedure bson_oid_gen(oid : Pointer); cdecl; external 'mongoc.dll';
343 | procedure bson_oid_to_string(oid : Pointer; s : PAnsiChar); cdecl; external 'mongoc.dll';
344 | procedure bson_oid_from_string(oid : Pointer; s : PAnsiChar); cdecl; external 'mongoc.dll';
345 | function bson_append_string(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
346 | cdecl; external 'mongoc.dll';
347 | function bson_append_code(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
348 | cdecl; external 'mongoc.dll';
349 | function bson_append_symbol(b : Pointer; name : PAnsiChar; value : PAnsiChar) : Integer;
350 | cdecl; external 'mongoc.dll';
351 | function bson_append_int(b : Pointer; name : PAnsiChar; value : Integer) : Integer;
352 | cdecl; external 'mongoc.dll';
353 | function bson_append_long(b : Pointer; name : PAnsiChar; value : Int64) : Integer;
354 | cdecl; external 'mongoc.dll';
355 | function bson_append_double(b : Pointer; name : PAnsiChar; value : Double) : Integer;
356 | cdecl; external 'mongoc.dll';
357 | function bson_append_date(b : Pointer; name : PAnsiChar; value : Int64) : Integer;
358 | cdecl; external 'mongoc.dll';
359 | function bson_append_bool(b : Pointer; name : PAnsiChar; value : Boolean) : Integer;
360 | cdecl; external 'mongoc.dll';
361 | function bson_append_null(b : Pointer; name : PAnsiChar) : Integer;
362 | cdecl; external 'mongoc.dll';
363 | function bson_append_undefined(b : Pointer; name : PAnsiChar) : Integer;
364 | cdecl; external 'mongoc.dll';
365 | function bson_append_start_object(b : Pointer; name : PAnsiChar) : Integer;
366 | cdecl; external 'mongoc.dll';
367 | function bson_append_start_array(b : Pointer; name : PAnsiChar) : Integer;
368 | cdecl; external 'mongoc.dll';
369 | function bson_append_finish_object(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
370 | function bson_append_oid(b : Pointer; name : PAnsiChar; oid : Pointer) : Integer; cdecl; external 'mongoc.dll';
371 | function bson_append_code_w_scope(b : Pointer; name : PAnsiChar; code : PAnsiChar; scope : Pointer) : Integer;
372 | cdecl; external 'mongoc.dll';
373 | function bson_append_regex(b : Pointer; name : PAnsiChar; pattern : PAnsiChar; options : PAnsiChar) : Integer;
374 | cdecl; external 'mongoc.dll';
375 | function bson_append_timestamp2(b : Pointer; name : PAnsiChar; time : Integer; increment : Integer) : Integer;
376 | cdecl; external 'mongoc.dll';
377 | function bson_append_binary(b : Pointer; name : PAnsiChar; kind : Byte; data : Pointer; len : Integer) : Integer;
378 | cdecl; external 'mongoc.dll';
379 | function bson_append_bson(b : Pointer; name : PAnsiChar; value : Pointer) : Integer;
380 | cdecl; external 'mongoc.dll';
381 | function bson_buffer_size(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
382 | function bson_size(b : Pointer) : Integer; cdecl; external 'mongoc.dll';
383 | function bson_iterator_create() : Pointer; cdecl; external 'mongoc.dll';
384 | procedure bson_iterator_dispose(i : Pointer); cdecl; external 'mongoc.dll';
385 | procedure bson_iterator_init(i : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
386 | function bson_find(i : Pointer; b : Pointer; name : PAnsiChar) : TBsonType;
387 | cdecl; external 'mongoc.dll';
388 | function bson_iterator_type(i : Pointer) : TBsonType; cdecl; external 'mongoc.dll';
389 | function bson_iterator_next(i : Pointer) : TBsonType; cdecl; external 'mongoc.dll';
390 | function bson_iterator_key(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
391 | function bson_iterator_double(i : Pointer) : Double; cdecl; external 'mongoc.dll';
392 | function bson_iterator_long(i : Pointer) : Int64; cdecl; external 'mongoc.dll';
393 | function bson_iterator_int(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
394 | function bson_iterator_bool(i : Pointer) : Boolean; cdecl; external 'mongoc.dll';
395 | function bson_iterator_string(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
396 | function bson_iterator_date(i : Pointer) : Int64; cdecl; external 'mongoc.dll';
397 | procedure bson_iterator_subiterator(i : Pointer; sub : Pointer);
398 | cdecl; external 'mongoc.dll';
399 | function bson_iterator_oid(i : Pointer) : Pointer; cdecl; external 'mongoc.dll';
400 | function bson_iterator_code(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
401 | procedure bson_iterator_code_scope(i : Pointer; b : Pointer); cdecl; external 'mongoc.dll';
402 | function bson_iterator_regex(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
403 | function bson_iterator_regex_opts(i : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
404 | function bson_iterator_timestamp_time(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
405 | function bson_iterator_timestamp_increment(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
406 | function bson_iterator_bin_len(i : Pointer) : Integer; cdecl; external 'mongoc.dll';
407 | function bson_iterator_bin_type(i : Pointer) : Byte; cdecl; external 'mongoc.dll';
408 | function bson_iterator_bin_data(i : Pointer) : Pointer; cdecl; external 'mongoc.dll';
409 |
410 |
411 | constructor TBsonOID.Create();
412 | begin
413 | bson_oid_gen(@value);
414 | end;
415 |
416 | constructor TBsonOID.Create(s : string);
417 | begin
418 | if length(s) <> 24 then
419 | Raise Exception.Create('Expected a 24 digit hex string');
420 | bson_oid_from_string(@value, PAnsiChar(AnsiString(s)));
421 | end;
422 |
423 | constructor TBsonOID.Create(i : TBsonIterator);
424 | var
425 | p : PByte;
426 | begin
427 | p := bson_iterator_oid(i.handle);
428 | Move(p^, value, 12);
429 | end;
430 |
431 | function TBsonOID.AsString() : string;
432 | var
433 | buf : array[0..24] of AnsiChar;
434 | begin
435 | bson_oid_to_string(@value, @buf);
436 | Result := string(buf);
437 | end;
438 |
439 | constructor TBsonIterator.Create();
440 | begin
441 | inherited Create();
442 | handle := bson_iterator_create();
443 | end;
444 |
445 | constructor TBsonIterator.Create(b : TBson);
446 | begin
447 | inherited Create();
448 | handle := bson_iterator_create();
449 | bson_iterator_init(handle, b.handle);
450 | end;
451 |
452 | destructor TBsonIterator.Destroy;
453 | begin
454 | bson_iterator_dispose(handle);
455 | end;
456 |
457 | function TBsonIterator.kind() : TBsonType;
458 | begin
459 | Result := bson_iterator_type(handle);
460 | end;
461 |
462 | function TBsonIterator.next() : Boolean;
463 | begin
464 | Result := bson_iterator_next(handle) <> bsonEOO;
465 | end;
466 |
467 | function TBsonIterator.key() : string;
468 | begin
469 | Result := string(System.UTF8ToWideString(bson_iterator_key(handle)));
470 | end;
471 |
472 | function TBsonIterator.value() : Variant;
473 | var
474 | k : TBsonType;
475 | d : TDateTime;
476 | begin
477 | k := kind();
478 | case k of
479 | bsonEOO, bsonNULL : Result := Null;
480 | bsonDOUBLE: Result := bson_iterator_double(handle);
481 | bsonSTRING, bsonCODE, bsonSYMBOL:
482 | Result := string(System.UTF8ToWideString(bson_iterator_string(handle)));
483 | bsonINT: Result := bson_iterator_int(handle);
484 | bsonBOOL: Result := bson_iterator_bool(handle);
485 | bsonDATE: begin
486 | d := Int64toDouble(bson_iterator_date(handle)) / (1000 * 24 * 60 * 60) + 25569;
487 | Result := d;
488 | end;
489 | bsonLONG: Result := bson_iterator_long(handle);
490 | else
491 | Raise Exception.Create('BsonType (' + IntToStr(Ord(k)) + ') not supported by TBsonIterator.value');
492 | end;
493 | end;
494 |
495 | function TBsonIterator.getOID() : TBsonOID;
496 | begin
497 | Result := TBsonOID.Create(Self);
498 | end;
499 |
500 | function TBsonIterator.getCodeWScope() : TBsonCodeWScope;
501 | begin
502 | Result := TBsonCodeWScope.Create(Self);
503 | end;
504 |
505 | function TBsonIterator.getRegex() : TBsonRegex;
506 | begin
507 | Result := TBsonRegex.Create(Self);
508 | end;
509 |
510 | function TBsonIterator.getTimestamp() : TBsonTimestamp;
511 | begin
512 | Result := TBsonTimestamp.Create(Self);
513 | end;
514 |
515 | function TBsonIterator.getBinary() : TBsonBinary;
516 | begin
517 | Result := TBsonBinary.Create(Self);
518 | end;
519 |
520 | function TBsonIterator.subiterator() : TBsonIterator;
521 | var
522 | i : TBsonIterator;
523 | begin
524 | i := TBsonIterator.Create();
525 | bson_iterator_subiterator(handle, i.handle);
526 | Result := i;
527 | end;
528 |
529 | function TBsonIterator.getIntegerArray() : TIntegerArray;
530 | var
531 | i : TBsonIterator;
532 | j, count : Integer;
533 | begin
534 | if kind() <> bsonArray then
535 | raise Exception.Create('Iterator does not point to an array');
536 | i := subiterator();
537 | count := 0;
538 | while i.next() do begin
539 | if i.kind() <> bsonINT then
540 | raise Exception.Create('Array component is not an Integer');
541 | inc(count);
542 | end;
543 | i := subiterator;
544 | j := 0;
545 | SetLength(Result, count);
546 | while i.next() do begin
547 | Result[j] := i.value();
548 | inc(j);
549 | end;
550 | end;
551 |
552 | function TBsonIterator.getDoubleArray() : TDoubleArray;
553 | var
554 | i : TBsonIterator;
555 | j, count : Integer;
556 | begin
557 | if kind() <> bsonArray then
558 | raise Exception.Create('Iterator does not point to an array');
559 | i := subiterator();
560 | count := 0;
561 | while i.next() do begin
562 | if i.kind() <> bsonDOUBLE then
563 | raise Exception.Create('Array component is not a Double');
564 | inc(count);
565 | end;
566 | i := subiterator;
567 | j := 0;
568 | SetLength(Result, count);
569 | while i.next() do begin
570 | Result[j] := i.value();
571 | inc(j);
572 | end;
573 | end;
574 |
575 | function TBsonIterator.getStringArray() : TStringArray;
576 | var
577 | i : TBsonIterator;
578 | j, count : Integer;
579 | begin
580 | if kind() <> bsonArray then
581 | raise Exception.Create('Iterator does not point to an array');
582 | i := subiterator();
583 | count := 0;
584 | while i.next() do begin
585 | if i.kind() <> bsonSTRING then
586 | raise Exception.Create('Array component is not a string');
587 | inc(count);
588 | end;
589 | i := subiterator;
590 | j := 0;
591 | SetLength(Result, count);
592 | while i.next() do begin
593 | Result[j] := System.UTF8ToWideString(i.value());
594 | inc(j);
595 | end;
596 | end;
597 |
598 | function TBsonIterator.getBooleanArray() : TBooleanArray;
599 | var
600 | i : TBsonIterator;
601 | j, count : Integer;
602 | begin
603 | if kind() <> bsonArray then
604 | raise Exception.Create('Iterator does not point to an array');
605 | i := subiterator();
606 | count := 0;
607 | while i.next() do begin
608 | if i.kind() <> bsonBOOL then
609 | raise Exception.Create('Array component is not a Boolean');
610 | inc(count);
611 | end;
612 | i := subiterator;
613 | j := 0;
614 | SetLength(Result, count);
615 | while i.next() do begin
616 | Result[j] := i.value();
617 | inc(j);
618 | end;
619 | end;
620 |
621 | function TBson.value(name : string) : Variant;
622 | var
623 | i : TBsonIterator;
624 | begin
625 | i := find(name);
626 | if i = nil then
627 | Result := Null
628 | else
629 | Result := i.value;
630 | i.Free; { Thanks to SamJokO }
631 | end;
632 |
633 | function TBson.iterator() : TBsonIterator;
634 | begin
635 | Result := TBsonIterator.Create(Self);
636 | end;
637 |
638 | constructor TBsonBuffer.Create();
639 | begin
640 | inherited Create();
641 | handle := bson_create();
642 | bson_init(handle);
643 | end;
644 |
645 | destructor TBsonBuffer.Destroy();
646 | begin
647 | bson_destroy(handle);
648 | bson_dispose(handle);
649 | inherited Destroy();
650 | end;
651 |
652 | function TBsonBuffer.append(name : string; value: PAnsiChar) : Boolean;
653 | begin
654 | if handle = nil then
655 | raise Exception.Create('BsonBuffer already finished');
656 | Result := (bson_append_string(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
657 | end;
658 |
659 | function TBsonBuffer.appendCode(name : string; value: PAnsiChar) : Boolean;
660 | begin
661 | if handle = nil then
662 | raise Exception.Create('BsonBuffer already finished');
663 | Result := (bson_append_code(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
664 | end;
665 |
666 | function TBsonBuffer.appendSymbol(name : string; value: PAnsiChar) : Boolean;
667 | begin
668 | if handle = nil then
669 | raise Exception.Create('BsonBuffer already finished');
670 | Result := (bson_append_symbol(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
671 | end;
672 |
673 | function TBsonBuffer.append(name : string; value: Integer) : Boolean;
674 | begin
675 | if handle = nil then
676 | raise Exception.Create('BsonBuffer already finished');
677 | Result := (bson_append_int(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
678 | end;
679 |
680 | function TBsonBuffer.append(name : string; value: Int64) : Boolean;
681 | begin
682 | if handle = nil then
683 | raise Exception.Create('BsonBuffer already finished');
684 | Result := (bson_append_long(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
685 | end;
686 |
687 | function TBsonBuffer.append(name : string; value: Double) : Boolean;
688 | begin
689 | if handle = nil then
690 | raise Exception.Create('BsonBuffer already finished');
691 | Result := (bson_append_double(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
692 | end;
693 |
694 | function TBsonBuffer.append(name : string; value: TDateTime) : Boolean;
695 | begin
696 | if handle = nil then
697 | raise Exception.Create('BsonBuffer already finished');
698 | Result := (bson_append_date(handle, PAnsiChar(System.UTF8Encode(name)), Trunc((value - 25569) * 1000 * 60 * 60 * 24)) = 0);
699 | end;
700 |
701 | function TBsonBuffer.append(name : string; value: Boolean) : Boolean;
702 | begin
703 | if handle = nil then
704 | raise Exception.Create('BsonBuffer already finished');
705 | Result := (bson_append_bool(handle, PAnsiChar(System.UTF8Encode(name)), value) = 0);
706 | end;
707 |
708 | function TBsonBuffer.append(name : string; value: TBsonOID) : Boolean;
709 | begin
710 | if handle = nil then
711 | raise Exception.Create('BsonBuffer already finished');
712 | Result := (bson_append_oid(handle, PAnsiChar(System.UTF8Encode(name)), @value.value) = 0);
713 | end;
714 |
715 | function TBsonBuffer.append(name : string; value: TBsonCodeWScope) : Boolean;
716 | begin
717 | if handle = nil then
718 | raise Exception.Create('BsonBuffer already finished');
719 | Result := (bson_append_code_w_scope(handle, PAnsiChar(System.UTF8Encode(name)), PAnsiChar(System.UTF8Encode(value.code)), value.scope.handle) = 0);
720 | end;
721 |
722 | function TBsonBuffer.append(name : string; value: TBsonRegex) : Boolean;
723 | begin
724 | if handle = nil then
725 | raise Exception.Create('BsonBuffer already finished');
726 | Result := (bson_append_regex(handle, PAnsiChar(System.UTF8Encode(name)), PAnsiChar(System.UTF8Encode(value.pattern)), PAnsiChar(System.UTF8Encode(value.options))) = 0);
727 | end;
728 |
729 | function TBsonBuffer.append(name : string; value: TBsonTimestamp) : Boolean;
730 | begin
731 | if handle = nil then
732 | raise Exception.Create('BsonBuffer already finished');
733 | Result := (bson_append_timestamp2(handle, PAnsiChar(System.UTF8Encode(name)), Trunc((value.time - 25569) * 60 * 60 * 24), value.increment) = 0);
734 | end;
735 |
736 | function TBsonBuffer.append(name : string; value: TBsonBinary) : Boolean;
737 | begin
738 | if handle = nil then
739 | raise Exception.Create('BsonBuffer already finished');
740 | Result := (bson_append_binary(handle, PAnsiChar(System.UTF8Encode(name)), value.kind, value.data, value.len) = 0);
741 | end;
742 |
743 | function TBsonBuffer.append(name : string; value : OleVariant) : Boolean;
744 | var
745 | d : double;
746 | begin
747 | case VarType(value) of
748 | varNull: Result := appendNull(name);
749 | varInteger: Result := append(name, Integer(value));
750 | varSingle, varDouble, varCurrency: begin
751 | d := value;
752 | Result := append(name, d);
753 | end;
754 | varDate: Result := append(name, TDateTime(value));
755 | varInt64: Result := append(name, Int64(value));
756 | varBoolean: Result := append(name, Boolean(value));
757 | varOleStr: Result := append(name, PAnsiChar(System.UTF8Encode(value)));
758 | else
759 | raise Exception.Create('TBson.append(variant): type not supported (' + IntToStr(VarType(value)) + ')');
760 | end;
761 | end;
762 |
763 | function TBsonBuffer.appendNull(name : string) : Boolean;
764 | begin
765 | if handle = nil then
766 | raise Exception.Create('BsonBuffer already finished');
767 | Result := (bson_append_null(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
768 | end;
769 |
770 | function TBsonBuffer.appendUndefined(name : string) : Boolean;
771 | begin
772 | if handle = nil then
773 | raise Exception.Create('BsonBuffer already finished');
774 | Result := (bson_append_undefined(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
775 | end;
776 |
777 | function TBsonBuffer.appendBinary(name : string; kind : Integer; data : Pointer; length : Integer) : Boolean;
778 | begin
779 | if handle = nil then
780 | raise Exception.Create('BsonBuffer already finished');
781 | Result := (bson_append_binary(handle, PAnsiChar(System.UTF8Encode(name)), kind, data, length) = 0);
782 | end;
783 |
784 | function TBsonBuffer.append(name : string; value : TBson) : Boolean;
785 | begin
786 | Result := (bson_append_bson(handle, PAnsiChar(System.UTF8Encode(name)), value.handle) = 0);
787 | end;
788 |
789 | function TBsonBuffer.appendArray(name : string; value : array of Integer) : Boolean;
790 | var
791 | success : Boolean;
792 | i, len : Integer;
793 | begin
794 | success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
795 | len := Length(value);
796 | i := 0;
797 | while success and (i < len) do begin
798 | success := (bson_append_int(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
799 | inc(i);
800 | end;
801 | if success then
802 | success := (bson_append_finish_object(handle) = 0);
803 | Result := success;
804 | end;
805 |
806 | function TBsonBuffer.appendArray(name : string; value : array of Double) : Boolean;
807 | var
808 | success : Boolean;
809 | i, len : Integer;
810 | begin
811 | success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
812 | len := Length(value);
813 | i := 0;
814 | while success and (i < len) do begin
815 | success := (bson_append_double(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
816 | inc(i);
817 | end;
818 | if success then
819 | success := (bson_append_finish_object(handle) = 0);
820 | Result := success;
821 | end;
822 |
823 | function TBsonBuffer.appendArray(name : string; value : array of Boolean) : Boolean;
824 | var
825 | success : Boolean;
826 | i, len : Integer;
827 | begin
828 | success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
829 | len := Length(value);
830 | i := 0;
831 | while success and (i < len) do begin
832 | success := (bson_append_bool(handle, PAnsiChar(AnsiString(IntToStr(i))), value[i]) = 0);
833 | inc(i);
834 | end;
835 | if success then
836 | success := (bson_append_finish_object(handle) = 0);
837 | Result := success;
838 | end;
839 |
840 | function TBsonBuffer.appendArray(name : string; value : array of string) : Boolean;
841 | var
842 | success : Boolean;
843 | i, len : Integer;
844 | begin
845 | success := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
846 | len := Length(value);
847 | i := 0;
848 | while success and (i < len) do begin
849 | success := (bson_append_string(handle, PAnsiChar(AnsiString(IntToStr(i))), PAnsiChar(System.UTF8Encode(value[i]))) = 0);
850 | inc(i);
851 | end;
852 | if success then
853 | success := (bson_append_finish_object(handle) = 0);
854 | Result := success;
855 | end;
856 |
857 | function TBsonBuffer.startObject(name : string) : Boolean;
858 | begin
859 | if handle = nil then
860 | raise Exception.Create('BsonBuffer already finished');
861 | Result := (bson_append_start_object(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
862 | end;
863 |
864 | function TBsonBuffer.startArray(name : string) : Boolean;
865 | begin
866 | if handle = nil then
867 | raise Exception.Create('BsonBuffer already finished');
868 | Result := (bson_append_start_array(handle, PAnsiChar(System.UTF8Encode(name))) = 0);
869 | end;
870 |
871 | function TBsonBuffer.finishObject() : Boolean;
872 | begin
873 | if handle = nil then
874 | raise Exception.Create('BsonBuffer already finished');
875 | Result := (bson_append_finish_object(handle) = 0);
876 | end;
877 |
878 | function TBsonBuffer.size() : Integer;
879 | begin
880 | if handle = nil then
881 | raise Exception.Create('BsonBuffer already finished');
882 | Result := bson_buffer_size(handle);
883 | end;
884 |
885 | function TBsonBuffer.finish() : TBson;
886 | begin
887 | if handle = nil then
888 | raise Exception.Create('BsonBuffer already finished');
889 | if bson_finish(handle) = 0 Then begin
890 | Result := TBson.Create(handle);
891 | handle := nil;
892 | end
893 | else
894 | Result := nil;
895 | end;
896 |
897 | constructor TBson.Create(h : Pointer);
898 | begin
899 | handle := h;
900 | end;
901 |
902 | destructor TBson.Destroy();
903 | begin
904 | bson_destroy(handle);
905 | bson_dispose(handle);
906 | inherited Destroy();
907 | end;
908 |
909 | function TBson.size() : Integer;
910 | begin
911 | Result := bson_size(handle);
912 | end;
913 |
914 | function TBson.find(name : string) : TBsonIterator;
915 | var
916 | i : TBsonIterator;
917 | begin
918 | i := TBsonIterator.Create();
919 | if bson_find(i.handle, handle, PAnsiChar(System.UTF8Encode(name))) = bsonEOO Then
920 | i := nil;
921 | Result := i;
922 | end;
923 |
924 | procedure _display(i : TBsonIterator; depth : Integer);
925 | var
926 | t : TBsonType;
927 | j,k : Integer;
928 | cws : TBsonCodeWScope;
929 | regex : TBsonRegex;
930 | ts : TBsonTimestamp;
931 | bin : TBsonBinary;
932 | p : PByte;
933 | begin
934 | while i.next() do begin
935 | t := i.kind();
936 | if t = bsonEOO then
937 | break;
938 | for j:= 1 To depth do
939 | Write(' ');
940 | Write(i.key, ' (', Ord(t), ') : ');
941 | case t of
942 | bsonDOUBLE,
943 | bsonSTRING, bsonSYMBOL, bsonCODE,
944 | bsonBOOL, bsonDATE, bsonINT, bsonLONG :
945 | Write(i.value);
946 | bsonUNDEFINED :
947 | Write('UNDEFINED');
948 | bsonNULL :
949 | Write('NULL');
950 | bsonOBJECT, bsonARRAY : begin
951 | Writeln;
952 | _display(i.subiterator, depth+1);
953 | end;
954 | bsonOID : write(i.getOID().AsString());
955 | bsonCODEWSCOPE : begin
956 | Write('CODEWSCOPE ');
957 | cws := i.getCodeWScope();
958 | WriteLn(cws.code);
959 | _display(cws.scope.iterator, depth+1);
960 | end;
961 | bsonREGEX: begin
962 | regex := i.getRegex();
963 | write(regex.pattern, ', ', regex.options);
964 | end;
965 | bsonTIMESTAMP: begin
966 | ts := i.getTimestamp();
967 | write(DateTimeToStr(ts.time), ' (', ts.increment, ')');
968 | end;
969 | bsonBINDATA: begin
970 | bin := i.getBinary();
971 | Write('BINARY (', bin.kind, ')');
972 | p := bin.data;
973 | for j := 0 to bin.len-1 do begin
974 | if j and 15 = 0 then begin
975 | WriteLn;
976 | for k := 1 To depth+1 do
977 | Write(' ');
978 | end;
979 | write(ByteToHex(p^), ' ');
980 | Inc(p);
981 | end;
982 | end;
983 | else
984 | Write('UNKNOWN');
985 | end;
986 | Writeln;
987 | end;
988 | end;
989 |
990 | procedure TBson.display();
991 | begin
992 | if Self = nil then
993 | WriteLn('nil BSON')
994 | else
995 | _display(iterator, 0);
996 | end;
997 |
998 | constructor TBsonCodeWScope.Create(code_ : string; scope_ : TBson);
999 | begin
1000 | code := code_;
1001 | scope := scope_;
1002 | end;
1003 |
1004 | constructor TBsonCodeWScope.Create(i : TBsonIterator);
1005 | var
1006 | b, c : Pointer;
1007 | begin
1008 | code := string(bson_iterator_code(i.handle));
1009 | b := bson_create();
1010 | bson_iterator_code_scope(i.handle, b);
1011 | c := bson_create();
1012 | bson_copy(c, b);
1013 | scope := TBson.Create(c);
1014 | bson_dispose(b);
1015 | end;
1016 |
1017 | constructor TBsonRegex.Create(pattern_ : string; options_ : string);
1018 | begin
1019 | pattern := pattern_;
1020 | options := options_;
1021 | end;
1022 |
1023 | constructor TBsonRegex.Create(i : TBsonIterator);
1024 | begin
1025 | pattern := string(bson_iterator_regex(i.handle));
1026 | options := string(bson_iterator_regex_opts(i.handle));
1027 | end;
1028 |
1029 |
1030 | constructor TBsonTimestamp.Create(time_ : TDateTime; increment_ : Integer);
1031 | begin
1032 | time := time_;
1033 | increment := increment_;
1034 | end;
1035 |
1036 | constructor TBsonTimestamp.Create(i : TBsonIterator);
1037 | begin
1038 | time := bson_iterator_timestamp_time(i.handle) / (60.0 * 60 * 24) + 25569;
1039 | increment := bson_iterator_timestamp_increment(i.handle);
1040 | end;
1041 |
1042 | constructor TBsonBinary.Create(p: Pointer; length: Integer);
1043 | begin
1044 | GetMem(data, length);
1045 | Move(p^, data^, length);
1046 | kind := 0;
1047 | end;
1048 |
1049 | constructor TBsonBinary.Create(i : TBsonIterator);
1050 | var
1051 | p : Pointer;
1052 | begin
1053 | kind := bson_iterator_bin_type(i.handle);
1054 | len := bson_iterator_bin_len(i.handle);
1055 | p := bson_iterator_bin_data(i.handle);
1056 | GetMem(data, len);
1057 | Move(p^, data^, len);
1058 | end;
1059 |
1060 | destructor TBsonBinary.Destroy;
1061 | begin
1062 | FreeMem(data);
1063 | end;
1064 |
1065 | function ByteToHex(InByte : Byte) : string;
1066 | const digits : array[0..15] of Char = '0123456789ABCDEF';
1067 | begin
1068 | result := digits[InByte shr 4] + digits[InByte and $0F];
1069 | end;
1070 |
1071 | function BSON(x : array of OleVariant) : TBson;
1072 | var
1073 | len : Integer;
1074 | i : Integer;
1075 | bb : TBsonBuffer;
1076 | depth : Integer;
1077 | key : string;
1078 | value : string;
1079 | begin
1080 | bb := TBsonBuffer.Create();
1081 | len := Length(x);
1082 | i := 0;
1083 | depth := 0;
1084 | while i < len do begin
1085 | key := VarToStr(x[i]);
1086 | if key = '}' then begin
1087 | if depth = 0 then
1088 | Raise Exception.Create('BSON(): unexpected "}"');
1089 | bb.finishObject();
1090 | dec(depth);
1091 | end
1092 | else begin
1093 | inc(i);
1094 | if i = Len then
1095 | raise Exception.Create('BSON(): expected value for ' + key);
1096 | value := VarToStr(x[i]);
1097 | if value = '{' then begin
1098 | bb.startObject(key);
1099 | inc(depth);
1100 | end
1101 | else
1102 | bb.append(key, x[i]);
1103 | end;
1104 | inc(i);
1105 | end;
1106 | if depth > 0 then
1107 | Raise Exception.Create('BSON: open subobject');
1108 | Result := bb.finish();
1109 | end;
1110 |
1111 | procedure err_handler(msg : PAnsiChar);
1112 | begin
1113 | Raise Exception.Create(string(msg));
1114 | end;
1115 |
1116 | initialization
1117 | bsonEmpty := BSON([]);
1118 | set_bson_err_handler(Addr(err_handler));
1119 |
1120 | end.
1121 |
1122 |
--------------------------------------------------------------------------------
/MongoDB.pas:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | { This unit implements the TMongo connection class for connecting to a MongoDB server
17 | and performing database operations on that server. }
18 | unit MongoDB;
19 |
20 | interface
21 | Uses
22 | MongoBson;
23 |
24 | const
25 | updateUpsert = 1;
26 | updateMulti = 2;
27 | updateBasic = 4;
28 |
29 | indexUnique = 1;
30 | indexDropDups = 4;
31 | indexBackground = 8;
32 | indexSparse = 16;
33 |
34 | { Create a tailable cursor. }
35 | cursorTailable = 2;
36 | { Allow queries on a non-primary node. }
37 | cursorSlaveOk = 4;
38 | { Disable cursor timeouts. }
39 | cursorNoTimeout = 16;
40 | { Momentarily block for more data. }
41 | cursorAwaitData = 32;
42 | { Stream in multiple 'more' packages. }
43 | cursorExhaust = 64;
44 | { Allow reads even if a shard is down. }
45 | cursorPartial = 128;
46 |
47 | type
48 | TMongoCursor = class;
49 | TStringArray = array of string;
50 |
51 | { TMongo objects establish a connection to a MongoDB server and are
52 | used for subsequent database operations on that server. }
53 | TMongo = class(TObject)
54 | { Pointer to externally managed data describing the connection.
55 | User code should not access this. It is public only for
56 | access from the GridFS unit. }
57 | var handle : Pointer;
58 | { Create a TMongo connection object. A connection is attempted on the
59 | MongoDB server running on the localhost '127.0.0.1:27017'.
60 | Check isConnected() to see if it was successful. }
61 | constructor Create(); overload;
62 | { Create a TMongo connection object. The host[:port] to connect to is given
63 | as the host string. port defaults to 27017 if not given.
64 | Check the result of isConnected() to see if it was successful. }
65 | constructor Create(host : string); overload;
66 | { Determine whether this TMongo is currently connected to a MongoDB server.
67 | Returns True if connected; False, if not. }
68 | function isConnected() : Boolean;
69 | { Check the connection. This returns True if isConnected() and the server
70 | responded to a 'ping'; otherwise, False. }
71 | function checkConnection() : Boolean;
72 | { Return True if the server reports that it is a master; otherwise, False. }
73 | function isMaster() : Boolean;
74 | { Temporarirly disconnect from the server. The connection may be reestablished
75 | by calling reconnect. This works on both normal connections and replsets. }
76 | procedure disconnect();
77 | { Reconnect to the MongoDB server after having called disconnect to suspend
78 | operations. }
79 | function reconnect() : Boolean;
80 | { Get an error code indicating the reason a connection or network communication
81 | failed. See mongo-c-driver/src/mongo.h and mongo_error_t. }
82 | function getErr() : Integer;
83 | { Set the timeout in milliseconds of a network operation. The default of 0
84 | indicates that there is no timeout. }
85 | function setTimeout(millis : Integer) : Boolean;
86 | { Get the network operation timeout value in milliseconds. The default of 0
87 | indicates that there is no timeout. }
88 | function getTimeout() : Integer;
89 | { Get the host:post of the primary server that this TMongo is connected to. }
90 | function getPrimary() : string;
91 | { Get the TCP/IP socket number being used for network communication }
92 | function getSocket() : Integer;
93 | { Get a list of databases from the server as an array of string }
94 | function getDatabases() : TStringArray;
95 | { Given a database name as a string, get the namespaces of the collections
96 | in that database as an array of string. }
97 | function getDatabaseCollections(db : string) : TStringArray;
98 | { Rename a collection. from_ns is the current namespace of the collection
99 | to be renamed. to_ns is the target namespace.
100 | The collection namespaces (from_ns, to_ns) are in the form 'database.collection'.
101 | Returns True if successful; otherwise, False. Note that this function may
102 | be used to move a collection from one database to another. }
103 | function rename(from_ns : string; to_ns : string) : Boolean;
104 | { Drop a collection. Removes the collection of the given name from the server.
105 | Exercise care when using this function.
106 | The collection namespace (ns) is in the form 'database.collection'. }
107 | function drop(ns : string) : Boolean;
108 | { Drop a database. Removes the entire database of the given name from the server.
109 | Exercise care when using this function. }
110 | function dropDatabase(db : string) : Boolean;
111 | { Insert a document into the given namespace.
112 | The collection namespace (ns) is in the form 'database.collection'.
113 | See http://www.mongodb.org/display/DOCS/Inserting.
114 | Returns True if successful; otherwise, False. }
115 | function insert(ns : string; b : TBson) : Boolean; overload;
116 | { Insert a batch of documents into the given namespace (collection).
117 | The collection namespace (ns) is in the form 'database.collection'.
118 | See http://www.mongodb.org/display/DOCS/Inserting.
119 | Returns True if successful; otherwise, False. }
120 | function insert(ns : string; bs : array of TBson) : Boolean; overload;
121 | { Perform an update on the server. The collection namespace (ns) is in the
122 | form 'database.collection'. criteria indicates which records to update
123 | and objNew gives the replacement document.
124 | See http://www.mongodb.org/display/DOCS/Updating.
125 | Returns True if successful; otherwise, False. }
126 | function update(ns : string; criteria : TBson; objNew : TBson) : Boolean; overload;
127 | { Perform an update on the server. The collection namespace (ns) is in the
128 | form 'database.collection'. criteria indicates which records to update
129 | and objNew gives the replacement document. flags is a bit mask containing update
130 | options; updateUpsert, updateMulti, or updateBasic.
131 | See http://www.mongodb.org/display/DOCS/Updating.
132 | Returns True if successful; otherwise, False. }
133 | function update(ns : string; criteria : TBson; objNew : TBson; flags : Integer) : Boolean; overload;
134 | { Remove documents from the server. The collection namespace (ns) is in the
135 | form 'database.collection'. Documents that match the given criteria
136 | are removed from the collection.
137 | See http://www.mongodb.org/display/DOCS/Removing.
138 | Returns True if successful; otherwise, False. }
139 | function remove(ns : string; criteria : TBson) : Boolean;
140 | { Find the first document in the given namespace that matches a query.
141 | See http://www.mongodb.org/display/DOCS/Querying
142 | The collection namespace (ns) is in the form 'database.collection'.
143 | Returns the document as a TBson if found; otherwise, nil. }
144 | function findOne(ns : string; query : TBson) : TBson; overload;
145 | { Find the first document in the given namespace that matches a query.
146 | See http://www.mongodb.org/display/DOCS/Querying
147 | The collection namespace (ns) is in the form 'database.collection'.
148 | A subset of the documents fields to be returned is specified in fields.
149 | This can cut down on network traffic.
150 | Returns the document as a TBson if found; otherwise, nil. }
151 | function findOne(ns : string; query : TBson; fields : TBson) : TBson; overload;
152 | { Issue a query to the database.
153 | See http://www.mongodb.org/display/DOCS/Querying
154 | Requires a TMongoCursor that is used to specify optional parameters to
155 | the find and to step through the result set.
156 | The collection namespace (ns) is in the form 'database.collection'.
157 | Returns true if the query was successful and at least one document is
158 | in the result set; otherwise, false.
159 | Optionally, set other members of the TMongoCursor before calling
160 | find. The TMongoCursor must be destroyed after finishing with a query.
161 | Instatiate a new cursor for another query.
162 | Example: @longcode(#
163 | var cursor : TMongoCursor;
164 | begin
165 | (* This finds all documents in the collection that have
166 | name equal to 'John' and steps through them. *)
167 | cursor := TMongoCursor.Create(BSON(['name', 'John']));
168 | if mongo.find(ns, cursor) then
169 | while cursor.next() do
170 | (* Do something with cursor.value() *)
171 | (* This finds all documents in the collection that have
172 | age equal to 32, but sorts them by name. *)
173 | cursor := TMongoCursor.Create(BSON(['age', 32]));
174 | cursor.sort := BSON(['name', True]);
175 | if mongo.find(ns, cursor) then
176 | while cursor.next() do
177 | (* Do something with cursor.value() *)
178 | end;
179 | #) }
180 | function find(ns : string; cursor : TMongoCursor) : Boolean;
181 | { Return the count of all documents in the given namespace.
182 | The collection namespace (ns) is in the form 'database.collection'. }
183 | function count(ns : string) : Double; overload;
184 | { Return the count of all documents in the given namespace that match
185 | the given query.
186 | The collection namespace (ns) is in the form 'database.collection'. }
187 | function count(ns : string; query : TBson) : Double; overload;
188 | { Create an index for the given collection so that accesses by the given
189 | key are faster.
190 | The collection namespace (ns) is in the form 'database.collection'.
191 | key is the name of the field on which to index.
192 | Returns nil if successful; otherwise, a TBson document that describes the error. }
193 | function distinct(ns : string; key : string) : TBson;
194 | { Returns a BSON document containing a field 'values' which
195 | is an array of the distinct values of the key in the given collection (ns).
196 | Example:
197 | var
198 | b : TBson;
199 | names : TStringArray;
200 | begin
201 | b := mongo.distinct('test.people', 'name');
202 | names := b.find('values').GetStringArray();
203 | end
204 | }
205 | function indexCreate(ns : string; key : string) : TBson; overload;
206 | { Create an index for the given collection so that accesses by the given
207 | key are faster.
208 | The collection namespace (ns) is in the form 'database.collection'.
209 | key is the name of the field on which to index.
210 | options specifies a bit mask of indexUnique, indexDropDups, indexBackground,
211 | and/or indexSparse.
212 | Returns nil if successful; otherwise, a TBson document that describes the error. }
213 | function indexCreate(ns : string; key : string; options : Integer) : TBson; overload;
214 | { Create an index for the given collection so that accesses by the given
215 | key are faster.
216 | The collection namespace (ns) is in the form 'database.collection'.
217 | key is a TBson document that (possibly) defines a compound key.
218 | For example, @longcode(#
219 | mongo.indexCreate(ns, BSON(['age', True, 'name', True]));
220 | (* speed up accesses of documents by age and then name *)
221 | #)
222 | Returns nil if successful; otherwise, a TBson document that describes the error. }
223 | function indexCreate(ns : string; key : TBson) : TBson; overload;
224 | { Create an index for the given collection so that accesses by the given
225 | key are faster.
226 | The collection namespace (ns) is in the form 'database.collection'.
227 | key is a TBson document that (possibly) defines a compound key.
228 | For example, @longcode(#
229 | mongo.indexCreate(ns, BSON(['age', True, 'name', True]));
230 | (* speed up accesses of documents by age and then name *)
231 | #)
232 | options specifies a bit mask of indexUnique, indexDropDups, indexBackground,
233 | and/or indexSparse.
234 | Returns nil if successful; otherwise, a TBson document that describes the error. }
235 | function indexCreate(ns : string; key : TBson; options : Integer) : TBson; overload;
236 | { Add a user name / password to the 'admin' database. This may be authenticated
237 | with the authenticate function.
238 | See http://www.mongodb.org/display/DOCS/Security+and+Authentication }
239 | function addUser(name : string; password : string) : Boolean; overload;
240 | { Add a user name / password to the given database. This may be authenticated
241 | with the authenticate function.
242 | See http://www.mongodb.org/display/DOCS/Security+and+Authentication }
243 | function addUser(name : string; password : string; db : string) : Boolean; overload;
244 | { Authenticate a user name / password with the 'admin' database.
245 | See http://www.mongodb.org/display/DOCS/Security+and+Authentication }
246 | function authenticate(name : string; password : string) : Boolean; overload;
247 | { Authenticate a user name / password with the given database.
248 | See http://www.mongodb.org/display/DOCS/Security+and+Authentication }
249 | function authenticate(name : string; password : string; db : string) : Boolean; overload;
250 | { Issue a command to the server. This supports all commands by letting you
251 | specify the command object as a TBson document.
252 | If successful, the response from the server is returned as a TBson document;
253 | otherwise, nil is returned.
254 | See http://www.mongodb.org/display/DOCS/List+of+Database+Commands }
255 | function command(db : string; command : TBson) : TBson; overload;
256 | { Issue a command to the server. This version of the command() function
257 | supports that subset of commands which may be described by a cmdstr and
258 | an argument.
259 | If successful, the response from the server is returned as a TBson document;
260 | otherwise, nil is returned.
261 | See http://www.mongodb.org/display/DOCS/List+of+Database+Commands }
262 | function command(db : string; cmdstr : string; arg : OleVariant) : TBson; overload;
263 | { Get the last error reported by the server. Returns a TBson document describing
264 | the error if there was one; otherwise, nil. }
265 | function getLastErr(db : string) : TBson;
266 | { Get the previous error reported by the server. Returns a TBson document describing
267 | the error if there was one; otherwise, nil. }
268 | function getPrevErr(db : string) : TBson;
269 | { Reset the error status of the server. After calling this function, both
270 | getLastErr() and getPrevErr() will return nil. }
271 | procedure resetErr(db : string);
272 | { Get the server error code. As a convenience, this is saved here after calling
273 | getLastErr() or getPrevErr(). }
274 | function getServerErr() : Integer;
275 | { Get the server error string. As a convenience, this is saved here after calling
276 | getLastErr() or getPrevErr(). }
277 | function getServerErrString() : string;
278 | { Destroy this TMongo object. Severs the connection to the server and releases
279 | external resources. }
280 | destructor Destroy(); override;
281 | end;
282 |
283 | { TMongoReplset is a superclass of the TMongo connection class that implements
284 | a different constructor and several functions for connecting to a replset. }
285 | TMongoReplset = class(TMongo)
286 | { Create a TMongoReplset object given the replset name. Unlike the constructor
287 | for TMongo, this does not yet establish the connection. Call addSeed() for each
288 | of the seed hosts and then call Connect to connect to the replset. }
289 | constructor Create(name : string);
290 | { Add a seed to the replset. The host string should be in the form 'host[:port]'.
291 | port defaults to 27017 if not given/
292 | After constructing a TMongoReplset, call this for each seed and then call
293 | Connect(). }
294 | procedure addSeed(host : string);
295 | { Connect to the replset. The seeds added with addSeed() are polled to determine
296 | if they belong to the replset name given to the constructor. Their hosts
297 | are then polled to determine the master to connect to.
298 | Returns True if it successfully connected; otherwise, False. }
299 | function Connect() : Boolean;
300 | { Get the number of hosts reported by the seeds }
301 | function getHostCount() : Integer;
302 | { Get the Ith host as a 'host:port' string. }
303 | function getHost(i : Integer) : string;
304 | end;
305 |
306 | { Objects of class TMongoCursor are used with TMongo.find() to specify
307 | optional parameters of the find and also to step though the result set.
308 | A TMongoCursor object is also returned by GridFS.TGridfile.getChunks() which
309 | is used to step through the chunks of a gridfile. }
310 | TMongoCursor = class(TObject)
311 | var
312 | { Pointer to externally managed data. User code should not modify this. }
313 | handle : Pointer;
314 | { A TBson document describing the query.
315 | See http://www.mongodb.org/display/DOCS/Querying }
316 | query : TBson;
317 | { A TBson document describing the sort to be applied to the result set.
318 | See the example for TMongo.find(). Defaults to nil (no sort). }
319 | sort : TBson;
320 | { A TBson document listing those fields to be included in the result set.
321 | This can be used to cut down on network traffic. Defaults to nil \
322 | (returns all fields of matching documents). }
323 | fields : TBson;
324 | { Specifies a limiting count on the number of documents returned. The
325 | default of 0 indicates no limit on the number of records returned.}
326 | limit : Integer;
327 | { Specifies the number of matched documents to skip. Default is 0. }
328 | skip : Integer;
329 | { Specifies cursor options. A bit mask of cursorTailable, cursorSlaveOk,
330 | cursorNoTimeout, cursorAwaitData, cursorExhaust , and/or cursorPartial.
331 | Defaults to 0 - no special handling. }
332 | options : Integer;
333 | { hold ref to the TMongo object of the find. Prevents release of the
334 | TMongo object until after this cursor is destroyed. }
335 | conn : TMongo;
336 | { Create a cursor with a empty query (which matches everything) }
337 | constructor Create(); overload;
338 | { Create a cursor with the given query. }
339 | constructor Create(query_ : TBson); overload;
340 | { Step to the first or next document in the result set.
341 | Returns True if there was a first or next document; otherwise,
342 | returns False when there are no more documents. }
343 | function next() : Boolean;
344 | { Return the current document of the result set }
345 | function value() : TBson;
346 | { Destroy this cursor. TMongoCursor objects should be released and destroyed
347 | after using them with TMongo.find(). This releases resources associated
348 | with the query on both the client and server ends. Construct a new
349 | TMongoCursor for another query. }
350 | destructor Destroy(); override;
351 | end;
352 |
353 | implementation
354 | Uses
355 | SysUtils;
356 |
357 | function mongo_env_sock_init() : Integer; cdecl; external 'mongoc.dll';
358 | function mongo_create() : Pointer; cdecl; external 'mongoc.dll';
359 | procedure mongo_dispose(c : Pointer); cdecl; external 'mongoc.dll';
360 | function mongo_client(c : Pointer; host : PAnsiChar; port : Integer) : Integer;
361 | cdecl; external 'mongoc.dll';
362 | procedure mongo_destroy(c : Pointer); cdecl; external 'mongoc.dll';
363 | procedure mongo_replica_set_init(c : Pointer; name : PAnsiChar); cdecl; external 'mongoc.dll';
364 | procedure mongo_replica_set_add_seed(c : Pointer; host : PAnsiChar; port : Integer);
365 | cdecl; external 'mongoc.dll';
366 | function mongo_replica_set_client(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
367 | function mongo_is_connected(c : Pointer) : Boolean; cdecl; external 'mongoc.dll';
368 | function mongo_get_err(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
369 | function mongo_set_op_timeout(c : Pointer; millis : Integer) : Integer;
370 | cdecl; external 'mongoc.dll';
371 | function mongo_get_op_timeout(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
372 | function mongo_get_primary(c : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
373 | function mongo_check_connection(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
374 | procedure mongo_disconnect(c : Pointer); cdecl; external 'mongoc.dll';
375 | function mongo_reconnect(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
376 | function mongo_cmd_ismaster(c : Pointer; b : Pointer) : Boolean;
377 | cdecl; external 'mongoc.dll';
378 | function mongo_get_socket(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
379 | function mongo_get_host_count(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
380 | function mongo_get_host(c : Pointer; i : Integer) : PAnsiChar; cdecl; external 'mongoc.dll';
381 | function mongo_insert(c : Pointer; ns : PAnsiChar; b : Pointer; wc : Pointer) : Integer;
382 | cdecl; external 'mongoc.dll';
383 | function mongo_insert_batch(c : Pointer; ns : PAnsiChar; bsons : Pointer; count : Integer; wc : Pointer; flags : Integer) : Integer;
384 | cdecl; external 'mongoc.dll';
385 | function mongo_update(c : Pointer; ns : PAnsiChar; cond : Pointer; op : Pointer; flags : Integer; wc : Pointer) : Integer;
386 | cdecl; external 'mongoc.dll';
387 | function mongo_remove(c : Pointer; ns : PAnsiChar; criteria : Pointer; wc : Pointer) : Integer;
388 | cdecl; external 'mongoc.dll';
389 | function mongo_find_one(c : Pointer; ns : PAnsiChar; query : Pointer; fields : Pointer; result : Pointer) : Integer;
390 | cdecl; external 'mongoc.dll';
391 | function bson_create() : Pointer; external 'mongoc.dll';
392 | procedure bson_dispose(b : Pointer); cdecl; external 'mongoc.dll';
393 | procedure bson_copy(dest : Pointer; src : Pointer); cdecl; external 'mongoc.dll';
394 | function mongo_cursor_create() : Pointer; cdecl; external 'mongoc.dll';
395 | procedure mongo_cursor_dispose(cursor : Pointer); cdecl; external 'mongoc.dll';
396 | procedure mongo_cursor_destroy(cursor : Pointer); cdecl; external 'mongoc.dll';
397 | function mongo_find(c : Pointer; ns : PAnsiChar; query : Pointer; fields : Pointer;
398 | limit, skip, options : Integer) : Pointer; cdecl; external 'mongoc.dll';
399 | function mongo_cursor_next(cursor : Pointer) : Integer; cdecl; external 'mongoc.dll';
400 | function mongo_cursor_bson(cursor : Pointer) : Pointer; cdecl; external 'mongoc.dll';
401 | function mongo_cmd_drop_collection(c : Pointer; db : PAnsiChar; collection : PAnsiChar; result : Pointer) : Integer;
402 | cdecl; external 'mongoc.dll';
403 | function mongo_cmd_drop_db(c : Pointer; db : PAnsiChar) : Integer; cdecl; external 'mongoc.dll';
404 | function mongo_count(c : Pointer; db : PAnsiChar; collection : PAnsiChar; query : Pointer) : Double;
405 | cdecl; external 'mongoc.dll';
406 | function mongo_create_index(c : Pointer; ns : PAnsiChar; key : Pointer; options : Integer; res : Pointer) : Integer;
407 | cdecl; external 'mongoc.dll';
408 | function mongo_cmd_add_user(c : Pointer; db : PAnsiChar; name : PAnsiChar; password : PAnsiChar) : Integer;
409 | cdecl; external 'mongoc.dll';
410 | function mongo_cmd_authenticate(c : Pointer; db : PAnsiChar; name : PAnsiChar; password : PAnsiChar) : Integer;
411 | cdecl; external 'mongoc.dll';
412 | function mongo_run_command(c : Pointer; db : PAnsiChar; command : Pointer; res: Pointer) : Integer;
413 | cdecl; external 'mongoc.dll';
414 | function mongo_cmd_get_last_error(c : Pointer; db : PAnsiChar; res: Pointer) : Integer;
415 | cdecl; external 'mongoc.dll';
416 | function mongo_cmd_get_prev_error(c : Pointer; db : PAnsiChar; res: Pointer) : Integer;
417 | cdecl; external 'mongoc.dll';
418 | function mongo_get_server_err(c : Pointer) : Integer; cdecl; external 'mongoc.dll';
419 | function mongo_get_server_err_string(c : Pointer) : PAnsiChar; cdecl; external 'mongoc.dll';
420 |
421 | procedure parseHost(host : string; var hosturl : string; var port : Integer);
422 | var i : Integer;
423 | begin
424 | i := Pos(':', host);
425 | if i = 0 then begin
426 | hosturl := host;
427 | port := 27017;
428 | end
429 | else begin
430 | hosturl := Copy(host, 1, i - 1);
431 | port := StrToInt(Copy(host, i + 1, Length(host) - i));
432 | end;
433 | end;
434 |
435 | constructor TMongo.Create();
436 | begin
437 | handle := mongo_create();
438 | mongo_client(handle, '127.0.0.1', 27017);
439 | end;
440 |
441 | constructor TMongo.Create(host : string);
442 | var
443 | hosturl : string;
444 | port : Integer;
445 | begin
446 | handle := mongo_create();
447 | parseHost(host, hosturl, port);
448 | mongo_client(handle, PAnsiChar(System.UTF8Encode(hosturl)), port);
449 | end;
450 |
451 | destructor TMongo.Destroy();
452 | begin
453 | mongo_destroy(handle);
454 | mongo_dispose(handle);
455 | end;
456 |
457 | constructor TMongoReplset.Create(name: string);
458 | begin
459 | handle := mongo_create();
460 | mongo_replica_set_init(handle, PAnsiChar(System.UTF8Encode(name)));
461 | end;
462 |
463 | procedure TMongoReplset.addSeed(host : string);
464 | var
465 | hosturl : string;
466 | port : Integer;
467 | begin
468 | parseHost(host, hosturl, port);
469 | mongo_replica_set_add_seed(handle, PAnsiChar(System.UTF8Encode(hosturl)), port);
470 | end;
471 |
472 | function TMongoReplset.Connect() : Boolean;
473 | begin
474 | Result := (mongo_replica_set_client(handle) = 0);
475 | end;
476 |
477 | function TMongo.isConnected() : Boolean;
478 | begin
479 | Result := mongo_is_connected(handle);
480 | end;
481 |
482 | function TMongo.checkConnection() : Boolean;
483 | begin
484 | Result := (mongo_check_connection(handle) = 0);
485 | end;
486 |
487 | function TMongo.isMaster() : Boolean;
488 | begin
489 | Result := mongo_cmd_ismaster(handle, nil);
490 | end;
491 |
492 | procedure TMongo.disconnect();
493 | begin
494 | mongo_disconnect(handle);
495 | end;
496 |
497 | function TMongo.reconnect() : Boolean;
498 | begin
499 | Result := (mongo_reconnect(handle) = 0);
500 | end;
501 |
502 | function TMongo.getErr() : Integer;
503 | begin
504 | Result := mongo_get_err(handle);
505 | end;
506 |
507 | function TMongo.setTimeout(millis: Integer) : Boolean;
508 | begin
509 | Result := (mongo_set_op_timeout(handle, millis) = 0);
510 | end;
511 |
512 | function TMongo.getTimeout() : Integer;
513 | begin
514 | Result := mongo_get_op_timeout(handle);
515 | end;
516 |
517 | function TMongo.getPrimary() : string;
518 | begin
519 | Result := string(mongo_get_primary(handle));
520 | end;
521 |
522 | function TMongo.getSocket() : Integer;
523 | begin
524 | Result := mongo_get_socket(handle);
525 | end;
526 |
527 | function TMongoReplset.getHostCount() : Integer;
528 | begin
529 | Result := mongo_get_host_count(handle);
530 | end;
531 |
532 | function TMongoReplset.getHost(i : Integer) : string;
533 | begin
534 | Result := string(mongo_get_host(handle, i));
535 | end;
536 |
537 | function TMongo.getDatabases() : TStringArray;
538 | var
539 | b : TBson;
540 | it, databases, database : TBsonIterator;
541 | name : string;
542 | count, i : Integer;
543 | begin
544 | b := command('admin', 'listDatabases', True);
545 | if b = nil then
546 | Result := nil
547 | else begin
548 | it := b.iterator;
549 | it.next();
550 | count := 0;
551 | databases := it.subiterator();
552 | while databases.next() do begin
553 | database := databases.subiterator();
554 | database.next();
555 | name := database.value();
556 | if (name <> 'admin') and (name <> 'local') then
557 | inc(count);
558 | end;
559 | SetLength(Result, count);
560 | i := 0;
561 | databases := it.subiterator();
562 | while databases.next() do begin
563 | database := databases.subiterator();
564 | database.next();
565 | name := database.value();
566 | if (name <> 'admin') and (name <> 'local') then begin
567 | Result[i] := name;
568 | inc(i);
569 | end;
570 | end;
571 | end;
572 | end;
573 |
574 | function TMongo.getDatabaseCollections(db : string) : TStringArray;
575 | var
576 | cursor : TMongoCursor;
577 | count, i : Integer;
578 | ns, name : string;
579 | b : TBson;
580 | begin
581 | count := 0;
582 | ns := db + '.system.namespaces';
583 | cursor := TMongoCursor.Create();
584 | if find(ns, cursor) then
585 | while cursor.next() do begin
586 | b := cursor.value();
587 | name := b.value('name');
588 | if (Pos('.system.', name) = 0) and (Pos('$', name) = 0) then
589 | inc(count);
590 | end;
591 | SetLength(Result, count);
592 | i := 0;
593 | cursor := TMongoCursor.Create();
594 | if find(ns, cursor) then
595 | while cursor.next() do begin
596 | b := cursor.value();
597 | name := b.value('name');
598 | if (Pos('.system.', name) = 0) and (Pos('$', name) = 0) then begin
599 | Result[i] := name;
600 | inc(i);
601 | end;
602 | end;
603 | end;
604 |
605 | function TMongo.rename(from_ns : string; to_ns : string) : Boolean;
606 | begin
607 | Result := (command('admin', BSON(['renameCollection', from_ns, 'to', to_ns])) <> nil);
608 | end;
609 |
610 | function TMongo.drop(ns : string) : Boolean;
611 | var
612 | db : string;
613 | collection : string;
614 | i : Integer;
615 | begin
616 | i := Pos('.', ns);
617 | if i = 0 then
618 | Raise Exception.Create('TMongo.drop: expected a ''.'' in the namespace.');
619 | db := Copy(ns, 1, i - 1);
620 | collection := Copy(ns, i+1, Length(ns) - i);
621 | Result := (mongo_cmd_drop_collection(handle, PAnsiChar(System.UTF8Encode(db)),
622 | PAnsiChar(System.UTF8Encode(collection)), nil) = 0);
623 | end;
624 |
625 | function TMongo.dropDatabase(db : string) : Boolean;
626 | begin
627 | Result := (mongo_cmd_drop_db(handle, PAnsiChar(System.UTF8Encode(db))) = 0);
628 | end;
629 |
630 | function TMongo.insert(ns: string; b: TBson) : Boolean;
631 | begin
632 | Result := (mongo_insert(handle, PAnsiChar(System.UTF8Encode(ns)), b.handle, nil) = 0);
633 | end;
634 |
635 | function TMongo.insert(ns: string; bs: array of TBson) : Boolean;
636 | var
637 | ps : array of Pointer;
638 | i : Integer;
639 | len : Integer;
640 | begin
641 | len := Length(bs);
642 | SetLength(ps, Len);
643 | for i := 0 to Len-1 do
644 | ps[i] := bs[i].handle;
645 | Result := (mongo_insert_batch(handle, PAnsiChar(System.UTF8Encode(ns)), &ps, len, nil, 0) = 0);
646 | end;
647 |
648 | function TMongo.update(ns : string; criteria : TBson; objNew : TBson; flags : Integer) : Boolean;
649 | begin
650 | Result := (mongo_update(handle, PAnsiChar(System.UTF8Encode(ns)), criteria.handle, objNew.handle, flags, nil) = 0);
651 | end;
652 |
653 | function TMongo.update(ns : string; criteria : TBson; objNew : TBson) : Boolean;
654 | begin
655 | Result := update(ns, criteria, objNew, 0);
656 | end;
657 |
658 | function TMongo.remove(ns : string; criteria : TBson) : Boolean;
659 | begin
660 | Result := (mongo_remove(handle, PAnsiChar(System.UTF8Encode(ns)), criteria.handle, nil) = 0);
661 | end;
662 |
663 | function TMongo.findOne(ns : string; query : TBson; fields : TBson) : TBson;
664 | var
665 | res : Pointer;
666 | begin
667 | res := bson_create();
668 | if (mongo_find_one(handle, PAnsiChar(System.UTF8Encode(ns)), query.handle, fields.handle, res) = 0) then
669 | Result := TBson.Create(res)
670 | else begin
671 | mongo_dispose(res);
672 | Result := nil;
673 | end;
674 | end;
675 |
676 | function TMongo.findOne(ns : string; query : TBson) : TBson;
677 | begin
678 | Result := findOne(ns, query, TBson.Create(nil));
679 | end;
680 |
681 | constructor TMongoCursor.Create();
682 | begin
683 | handle := nil;
684 | query := nil;
685 | sort := nil;
686 | fields := nil;
687 | limit := 0;
688 | skip := 0;
689 | options := 0;
690 | conn := nil;
691 | end;
692 |
693 | constructor TMongoCursor.Create(query_ : TBson);
694 | begin
695 | handle := nil;
696 | query := query_;
697 | sort := nil;
698 | fields := nil;
699 | limit := 0;
700 | skip := 0;
701 | options := 0;
702 | conn := nil;
703 | end;
704 |
705 | destructor TMongoCursor.Destroy();
706 | begin
707 | mongo_cursor_destroy(handle);
708 | // mongo_cursor_dispose(handle);
709 | end;
710 |
711 | function TMongo.find(ns : string; cursor : TMongoCursor) : Boolean;
712 | var
713 | q : TBson;
714 | bb : TBsonBuffer;
715 | ch : Pointer;
716 | begin
717 | if cursor.fields = nil then
718 | cursor.fields := TBson.Create(nil);
719 | q := cursor.query;
720 | if q = nil then
721 | q := bsonEmpty;
722 | if cursor.sort <> nil then begin
723 | bb := TBsonBuffer.Create();
724 | bb.append('$query', cursor.query);
725 | bb.append('$orderby', cursor.sort);
726 | q := bb.finish;
727 | end;
728 | cursor.conn := Self;
729 | ch := mongo_find(handle, PAnsiChar(System.UTF8Encode(ns)), q.handle, cursor.fields.handle,
730 | cursor.limit, cursor.skip, cursor.options);
731 | if ch <> nil then begin
732 | cursor.handle := ch;
733 | Result := True;
734 | end
735 | else
736 | Result := False;
737 | end;
738 |
739 |
740 | function TMongoCursor.next() : Boolean;
741 | begin
742 | Result := (mongo_cursor_next(handle) = 0);
743 | end;
744 |
745 | function TMongoCursor.value() : TBson;
746 | var
747 | b : TBson;
748 | h : Pointer;
749 | begin
750 | h := bson_create();
751 | b := TBson.Create(h);
752 | bson_copy(h, mongo_cursor_bson(handle));
753 | Result := b;
754 | end;
755 |
756 | function TMongo.count(ns : string; query : TBson) : Double;
757 | var
758 | db : string;
759 | collection : string;
760 | i : Integer;
761 | begin
762 | i := Pos('.', ns);
763 | if i = 0 then
764 | Raise Exception.Create('TMongo.drop: expected a ''.'' in the namespace.');
765 | db := Copy(ns, 1, i - 1);
766 | collection := Copy(ns, i+1, Length(ns) - i);
767 | Result := mongo_count(handle, PAnsiChar(System.UTF8Encode(db)),
768 | PAnsiChar(System.UTF8Encode(collection)), query.handle);
769 | end;
770 |
771 | function TMongo.count(ns : string) : Double;
772 | begin
773 | Result := count(ns, TBson.Create(nil));
774 | end;
775 |
776 | function TMongo.indexCreate(ns : string; key : TBson; options : Integer) : TBson;
777 | var
778 | res : TBson;
779 | created : Boolean;
780 | begin
781 | res := TBson.Create(bson_create());
782 | created := (mongo_create_index(handle, PAnsiChar(System.UTF8Encode(ns)), key.handle, options, res.handle) = 0);
783 | if not created then
784 | Result := res
785 | else
786 | begin
787 | res.Free;
788 | Result := nil;
789 | end;
790 | end;
791 |
792 | function TMongo.indexCreate(ns : string; key : TBson) : TBson;
793 | begin
794 | Result := indexCreate(ns, key, 0);
795 | end;
796 |
797 | function TMongo.indexCreate(ns : string; key : string; options : Integer) : TBson;
798 | begin
799 | Result := indexCreate(ns, BSON([key, True]), options);
800 | end;
801 |
802 | function TMongo.indexCreate(ns : string; key : string) : TBson;
803 | begin
804 | Result := indexCreate(ns, key, 0);
805 | end;
806 |
807 | function TMongo.addUser(name : string; password : string; db : string) : Boolean;
808 | begin
809 | Result := (mongo_cmd_add_user(handle, PAnsiChar(System.UTF8Encode(db)),
810 | PAnsiChar(System.UTF8Encode(name)),
811 | PAnsiChar(System.UTF8Encode(password))) = 0);
812 | end;
813 |
814 | function TMongo.addUser(name : string; password : string) : Boolean;
815 | begin
816 | Result := addUser(name, password, 'admin');
817 | end;
818 |
819 | function TMongo.authenticate(name : string; password : string; db : string) : Boolean;
820 | begin
821 | Result := (mongo_cmd_authenticate(handle, PAnsiChar(System.UTF8Encode(db)),
822 | PAnsiChar(System.UTF8Encode(name)),
823 | PAnsiChar(System.UTF8Encode(password))) = 0);
824 | end;
825 |
826 | function TMongo.authenticate(name : string; password : string) : Boolean;
827 | begin
828 | Result := authenticate(name, password, 'admin');
829 | end;
830 |
831 | function TMongo.command(db : string; command : TBson) : TBson;
832 | var
833 | b : TBson;
834 | res : Pointer;
835 | begin
836 | res := bson_create();
837 | if mongo_run_command(handle, PAnsiChar(System.UTF8Encode(db)), command.handle, res) = 0 then begin
838 | b := TBson.Create(bson_create());
839 | bson_copy(b.handle, res);
840 | Result := b;
841 | end
842 | else
843 | Result := nil;
844 | bson_dispose(res);
845 | end;
846 |
847 | function TMongo.distinct(ns : string; key : string) : TBson;
848 | var b : TBson;
849 | buf : TBsonBuffer;
850 | p : Integer;
851 | db, collection : string;
852 | begin
853 | p := pos('.', ns);
854 | if p = 0 then
855 | Raise Exception.Create('Expected a ''.'' in the namespace');
856 | db := Copy(ns, 1, p-1);
857 | collection := Copy(ns, p+1, Length(ns) - p);
858 | buf := TBsonBuffer.Create();
859 | buf.append('distinct', collection);
860 | buf.append('key', key);
861 | b := buf.finish;
862 | Result := command(db, b);
863 | end;
864 |
865 | function TMongo.command(db : string; cmdstr : string; arg : OleVariant) : TBson;
866 | begin
867 | Result := command(db, BSON([cmdstr, arg]));
868 | end;
869 |
870 | function TMongo.getLastErr(db : string) : TBson;
871 | var
872 | b : TBson;
873 | res : Pointer;
874 | begin
875 | res := bson_create();
876 | if mongo_cmd_get_last_error(handle, PAnsiChar(System.UTF8Encode(db)), res) <> 0 then begin
877 | b := TBson.Create(bson_create());
878 | bson_copy(b.handle, res);
879 | Result := b;
880 | end
881 | else
882 | Result := nil;
883 | bson_dispose(res);
884 | end;
885 |
886 | function TMongo.getPrevErr(db : string) : TBson;
887 | var
888 | b : TBson;
889 | res : Pointer;
890 | begin
891 | res := bson_create();
892 | if mongo_cmd_get_prev_error(handle, PAnsiChar(System.UTF8Encode(db)), res) <> 0 then begin
893 | b := TBson.Create(bson_create());
894 | bson_copy(b.handle, res);
895 | Result := b;
896 | end
897 | else
898 | Result := nil;
899 | bson_dispose(res);
900 | end;
901 |
902 | procedure TMongo.resetErr(db : string);
903 | begin
904 | command(db, 'reseterror', True);
905 | end;
906 |
907 | function TMongo.getServerErr() : Integer;
908 | begin
909 | Result := mongo_get_server_err(handle);
910 | end;
911 |
912 | function TMongo.getServerErrString() : string;
913 | begin
914 | Result := string(mongo_get_server_err_string(handle));
915 | end;
916 |
917 | initialization
918 | mongo_env_sock_init();
919 | end.
920 |
921 |
--------------------------------------------------------------------------------
/MongoDelphiDriver.dpk:
--------------------------------------------------------------------------------
1 | package MongoDelphiDriver;
2 |
3 | {$R *.res}
4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
5 | {$ALIGN 8}
6 | {$ASSERTIONS ON}
7 | {$BOOLEVAL OFF}
8 | {$DEBUGINFO ON}
9 | {$EXTENDEDSYNTAX ON}
10 | {$IMPORTEDDATA ON}
11 | {$IOCHECKS ON}
12 | {$LOCALSYMBOLS ON}
13 | {$LONGSTRINGS ON}
14 | {$OPENSTRINGS ON}
15 | {$OPTIMIZATION OFF}
16 | {$OVERFLOWCHECKS OFF}
17 | {$RANGECHECKS OFF}
18 | {$REFERENCEINFO ON}
19 | {$SAFEDIVIDE OFF}
20 | {$STACKFRAMES ON}
21 | {$TYPEDADDRESS OFF}
22 | {$VARSTRINGCHECKS ON}
23 | {$WRITEABLECONST OFF}
24 | {$MINENUMSIZE 1}
25 | {$IMAGEBASE $400000}
26 | {$DEFINE DEBUG}
27 | {$ENDIF IMPLICITBUILDING}
28 | {$IMPLICITBUILD ON}
29 |
30 | requires
31 | rtl;
32 |
33 | contains
34 | MongoBson in 'MongoBson.pas',
35 | MongoDB in 'MongoDB.pas',
36 | GridFS in 'GridFS.pas';
37 |
38 | end.
39 |
--------------------------------------------------------------------------------
/MongoDelphiDriver.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {F9C9AC27-5CCA-400D-97FA-2E6931FA838E}
4 | MongoDelphiDriver.dpk
5 | 13.4
6 | None
7 | True
8 | Debug
9 | Win32
10 | 3
11 | Package
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | All
50 | true
51 | true
52 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
53 | .\$(Platform)\$(Config)
54 | .\$(Platform)\$(Config)
55 | false
56 | false
57 | false
58 | false
59 | false
60 |
61 |
62 | true
63 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
64 | 1033
65 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
66 |
67 |
68 | true
69 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
70 | 1033
71 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
72 |
73 |
74 | DEBUG;$(DCC_Define)
75 | false
76 | true
77 | true
78 | true
79 |
80 |
81 | true
82 | 1033
83 |
84 |
85 | true
86 | 1033
87 | false
88 |
89 |
90 | false
91 | RELEASE;$(DCC_Define)
92 | 0
93 | false
94 |
95 |
96 |
97 | MainSource
98 |
99 |
100 |
101 |
102 |
103 |
104 | Cfg_2
105 | Base
106 |
107 |
108 | Base
109 |
110 |
111 | Cfg_1
112 | Base
113 |
114 |
115 |
116 | Delphi.Personality.12
117 | Package
118 |
119 |
120 |
121 | MongoDelphiDriver.dpk
122 |
123 |
124 | True
125 | False
126 | 1
127 | 0
128 | 0
129 | 0
130 | False
131 | False
132 | False
133 | False
134 | False
135 | 1033
136 | 1252
137 |
138 |
139 |
140 |
141 | 1.0.0.0
142 |
143 |
144 |
145 |
146 |
147 | 1.0.0.0
148 |
149 |
150 |
151 | Microsoft Office 2000 Sample Automation Server Wrapper Components
152 | Microsoft Office XP Sample Automation Server Wrapper Components
153 |
154 |
155 |
156 |
157 | True
158 | False
159 | True
160 |
161 |
162 | 12
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/MongoDelphiDriver.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {A85C4061-9C73-443B-9DD9-773DB55C4F7E}
4 |
5 |
6 |
7 |
8 |
9 |
10 | MongoDelphiDriver.dproj
11 |
12 |
13 |
14 |
15 |
16 |
17 | Default.Personality.12
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 |
--------------------------------------------------------------------------------
/MongoDelphiDriver.groupproj.local:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MongoDelphiDriver.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gerald-lindsly/mongo-delphi-driver/6f4e145bab99ad3d737c484a8d0c3f284828a6f6/MongoDelphiDriver.res
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a Delphi package supporting access to MongoDB.
2 |
3 | After downloading this repo, download and build [mongo-c-driver](http://github.com/mongodb/mongo-c-driver) with scons.
4 | Use the --m32 option with SCons to generate a 32-bit dll.
5 | Copy the produced mongoc.dll to C:\10gen\mongo-delphi-driver\Win32\Debug or ...\Release as appropriate.
6 |
7 | Load the project group, MongoDelphiDriver.groupproj, into RAD Studio.
8 |
9 | To run the examples, in the Project Manager, right-click on either Test.exe or
10 | AddressBook.exe and Activate. Hit F9 to build and run.
11 |
12 | The documentation for package is in the 3 unit files: MongoDB.pas, MongoBson.pas, and GridFS.pas
13 |
14 |
--------------------------------------------------------------------------------
/Test.dpr:
--------------------------------------------------------------------------------
1 | {
2 | Copyright 2009-2011 10gen Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | }
16 | program Test;
17 |
18 | {$APPTYPE CONSOLE}
19 |
20 | {$R *.res}
21 |
22 | uses
23 | System.SysUtils,
24 | Variants,
25 | MongoBson, MongoDB, GridFS;
26 |
27 | var
28 | bb : TBsonBuffer;
29 | cws : TBsonCodeWScope;
30 | b, b2, x, y, z, criteria, query, cmd : TBson;
31 | i : TBsonIterator;
32 | oid : TBsonOID;
33 | ts : TBsonTimestamp;
34 | bin : TBsonBinary;
35 | sing : Single;
36 | mongo : TMongo;
37 | j : Integer;
38 | cursor : TMongoCursor;
39 | databases : TStringArray;
40 | gfs : TGridFS;
41 | gfw : TGridfileWriter;
42 | gf : TGridfile;
43 | buf : array[0..100] of AnsiChar;
44 | ia1 : array[0..4] of Integer;
45 | ia2 : TIntegerArray;
46 |
47 | const
48 | db = 'test';
49 | ns = db + '.people';
50 |
51 | procedure displayCollections(db : string);
52 | var
53 | collections : TStringArray;
54 | j : Integer;
55 | begin
56 | collections := mongo.getDatabaseCollections(db);
57 | for j := 0 to Length(collections)-1 do
58 | Writeln(collections[j]);
59 | end;
60 |
61 | procedure ExtractFile(gfs : TGridFS; gfsname : string; filename : string = '');
62 | var chunk : Integer;
63 | gf : TGridfile;
64 | f : File;
65 | b : TBson;
66 | bin : TBsonBinary;
67 | begin
68 | if filename = '' then filename := gfsname;
69 | gf := gfs.find(gfsname);
70 | Assign(f, filename);
71 | Rewrite(f, 1);
72 | for chunk := 0 to gf.getChunkCount - 1 do
73 | begin
74 | b := gf.getChunk(chunk);
75 | bin := b.find('data').getBinary;
76 | BlockWrite(f, bin.data^, bin.len);
77 | end;
78 | Close(f);
79 | end;
80 |
81 | begin
82 | try
83 |
84 | bb := TBsonBuffer.Create();
85 | ia1[0] := 5;
86 | ia1[1] := 7;
87 | ia1[2] := 9;
88 | ia1[3] := 11;
89 | ia1[4] := 13;
90 | bb.appendArray('ia', ia1);
91 | b := bb.finish;
92 | i := b.iterator;
93 | ia2 := i.getIntegerArray();
94 | for j := 0 to Length(ia2) - 1 do
95 | WriteLn(ia2[j]);
96 |
97 | bb := TBsonBuffer.Create();
98 | bb.append('test', 'testing');
99 | cws := TBsonCodeWScope.Create('Code for scope', bb.finish());
100 |
101 | bb := TBsonBuffer.Create();
102 | bb.append('name', 'Gerald');
103 | bb.append('age', 35);
104 | bb.append('long', Int64(89));
105 | bb.append('bool', True);
106 | bb.append('date', StrToDate('1/3/1970'));
107 | bb.startObject('object');
108 | bb.append('sub1', 'sub1');
109 | bb.append('sub2', False);
110 | bb.finishObject();
111 | oid := TBsonOID.Create();
112 | writeln(oid.AsString());
113 | bb.append('oid1', oid);
114 | bb.append('oid2', TBsonOID.Create('4eb6a93dad14000000000099'));
115 | bb.appendCode('code', '{ this = is + code; }');
116 | bb.appendSymbol('symbol', 'symbol');
117 | bb.append('cws', cws);
118 | bb.append('regex', TBsonRegex.Create('pattern', 'options'));
119 | ts := TBsonTimestamp.Create(now, 21);
120 | bb.append('timestamp', ts);
121 | bb.appendBinary('binary', 0, @ts, sizeof(ts));
122 |
123 | b := bb.finish;
124 | Writeln(b.size());
125 |
126 | b.display();
127 |
128 | Writeln(b.value('long'));
129 | i := b.find('oid1');
130 | WriteLn(i.getOID().AsString());
131 |
132 | i := b.find('binary');
133 | bin := i.getBinary();
134 |
135 | WriteLn(bin.len);
136 | sing := 3.14159;
137 |
138 | b2 := BSON(['test', 'testing', 'age', 32,
139 | 'subobj', '{',
140 | 'single', sing,
141 | '}',
142 | 'int64', Int64(1234567890123),
143 | 'double', 98.7, 'null', Null, 'logical', False, 'now', now ]);
144 | b2.display();
145 |
146 | mongo := TMongo.Create();
147 | if mongo.isConnected() then begin
148 | mongo.setTimeout(0);
149 | WriteLn('Timeout = ', mongo.getTimeout());
150 | WriteLn('Primary = ', mongo.getPrimary());
151 | WriteLn('IsMaster = ', mongo.isMaster());
152 | WriteLn('Socket = ', mongo.getSocket());
153 | WriteLn('Check = ', mongo.checkConnection());
154 | WriteLn('disconnect');
155 | mongo.disconnect();
156 | WriteLn(' Check = ', mongo.checkConnection());
157 | WriteLn('reconnect');
158 | mongo.reconnect();
159 | WriteLn(' Check = ', mongo.checkConnection());
160 |
161 | databases := mongo.getDatabases();
162 | for j := 0 to Length(databases)-1 do
163 | Writeln(databases[j]);
164 |
165 | displayCollections(db);
166 | mongo.rename(ns, 'test.renamed');
167 | displayCollections(db);
168 | mongo.rename('test.renamed', ns);
169 | displayCollections(db);
170 |
171 |
172 | WriteLn('Drop = ', mongo.drop(ns));
173 |
174 | mongo.indexCreate(ns, 'name', indexUnique);
175 |
176 | (* display hosts for a TMongoReplset
177 | Count := mongo.getHostCount();
178 | WriteLn('Replset Host Count = ', Count);
179 | for j := 0 to count - 1 do
180 | WriteLn('Host = ', mongo.getHost(j));
181 | *)
182 |
183 | (* insert the collage document *)
184 | mongo.insert(ns, b);
185 |
186 | (* Insert a couple more people *)
187 | bb := TBsonBuffer.Create();
188 | bb.append('name', 'Abe');
189 | bb.append('age', 32);
190 | bb.append('city', 'Washington');
191 | x := bb.finish;
192 | x.display();
193 | Writeln(mongo.insert(ns, x));
194 |
195 | bb := TBsonBuffer.Create();
196 | bb.append('name', 'Joe');
197 | bb.append('age', 35);
198 | bb.append('city', 'Natick');
199 | x := bb.finish;
200 | x.display();
201 | Writeln(mongo.insert(ns, x));
202 |
203 | (* Batch insert 3 people *)
204 | bb := TBsonBuffer.Create();
205 | bb.append('name', 'Jeff');
206 | bb.append('age', 19);
207 | bb.append('city', 'Florence');
208 | x := bb.finish;
209 | x.display();
210 |
211 | bb := TBsonBuffer.Create();
212 | bb.append('name', 'Harry');
213 | bb.append('age', 36);
214 | bb.append('city', 'Fort Aspenwood');
215 | y := bb.finish;
216 | y.display();
217 |
218 | bb := TBsonBuffer.Create();
219 | bb.append('name', 'John');
220 | bb.append('age', 21);
221 | bb.append('city', 'Cincinnati');
222 | z := bb.finish;
223 | z.display();
224 | Writeln(mongo.insert(ns, [x, y, z]));
225 |
226 | (* update Joe's document with a new one *)
227 | bb := TBsonBuffer.Create();
228 | bb.append('name', 'Joe');
229 | bb.append('age', 36);
230 | bb.append('city', 'Austin');
231 | x := bb.finish;
232 | criteria := BSON(['name', 'Joe']);
233 | x.display();
234 | Writeln(mongo.update(ns, criteria, x));
235 |
236 | (* do an upsert *)
237 | bb := TBsonBuffer.Create();
238 | bb.append('name', 'Paul');
239 | bb.append('age', 53);
240 | bb.append('city', 'Seattle');
241 | x := bb.finish;
242 | criteria := BSON(['name', 'Paul']);
243 | criteria.display();
244 | x.display();
245 | Writeln(mongo.update(ns, criteria, x, updateUpsert));
246 |
247 | (* Remove a record *)
248 | WriteLn(mongo.remove(ns, BSON(['name', 'John'])));
249 |
250 | (* successful findOne *)
251 | x := mongo.findOne(ns, criteria);
252 | x.display();
253 |
254 | (* unsuccessful findOne *)
255 | x := mongo.findOne(ns, BSON(['name', 'unknown']));
256 | x.display();
257 |
258 | (* display all people *)
259 | cursor := TMongoCursor.Create();
260 | if mongo.find(ns, cursor) then
261 | while cursor.next() do
262 | cursor.value.display();
263 |
264 | (* display all people age 36 *)
265 | query := BSON(['age', 36]);
266 | cursor := TMongoCursor.Create(query);
267 | if mongo.find(ns, cursor) then
268 | while cursor.next() do
269 | cursor.value.display();
270 |
271 | WriteLn(mongo.count(ns));
272 | cmd := BSON(['count', 'people']);
273 | b := mongo.command(db, cmd);
274 | WriteLn(b.value('n'));
275 | b := mongo.command(db, 'count', 'people');
276 | WriteLn(b.value('n'));
277 |
278 | WriteLn(mongo.count(ns, query));
279 |
280 | (* get distinct names *)
281 | x := mongo.distinct(ns, 'name');
282 | i := x.find('values').subiterator;
283 | while i.next do
284 | writeln(i.value);
285 |
286 | (* add a user to database 'admin' *)
287 | mongo.addUser('Gerald', 'P97gwep16');
288 |
289 | (* authenticate with correct credentials *)
290 | WriteLn(mongo.authenticate('Gerald', 'P97gwep16'));
291 |
292 | (* try authenicate with bad password *)
293 | WriteLn(mongo.authenticate('Gerald', 'BadPass21'));
294 |
295 | (* try authenticate with bad user *)
296 | WriteLn(mongo.authenticate('Unsub', 'BadUser67'));
297 |
298 | b := BSON(['name', 'dupkey']);
299 | mongo.insert(ns, b);
300 | mongo.insert(ns, b);
301 | b := mongo.getLastErr(db);
302 | b.display();
303 |
304 | b := BSON(['name', '{', '$badop', true, '}' ]);
305 | b2 := mongo.findOne(ns, b);
306 | b2.display();
307 | b := mongo.getLastErr(db);
308 | b.display();
309 | b := mongo.getPrevErr(db);
310 | b.display();
311 | WriteLn(mongo.getServerErr());
312 | WriteLn(mongo.getServerErrString());
313 |
314 | mongo.resetErr(db);
315 | b := mongo.getLastErr(db);
316 | b.display();
317 |
318 | gfs := TGridFS.Create(mongo, 'grid');
319 | WriteLn('Store test.exe = ', gfs.storeFile('test.exe'));
320 |
321 | WriteLn('Store bin = ', gfs.store(bin.data, bin.len, 'bin'));
322 |
323 | gfs.removeFile('bin');
324 |
325 | gfw := gfs.writerCreate('writer');
326 | gfw.write(bin.data, bin.len);
327 | gfw.write(bin.data, bin.len);
328 | gfw.finish();
329 |
330 | gf := gfs.find('writer');
331 |
332 | WriteLn('name = ', gf.getFilename());
333 | WriteLn('length = ', gf.getLength());
334 | WriteLn('chunkSize = ', gf.getChunkSize());
335 | WriteLn('chunkCount = ', gf.getChunkCount());
336 | WriteLn('contentType = ', gf.getContentType());
337 | WriteLN('uploadDate = ', DateTimeToStr(gf.getUploadDate()));
338 | WriteLN('md5 = ', gf.getMD5());
339 | b := gf.getDescriptor();
340 | b.display();
341 |
342 | gf.read(@j, sizeof(j));
343 | WriteLn(j);
344 |
345 | gf := gfs.find('test.exe');
346 | cursor := gf.getChunks(1, 5);
347 | while cursor.next() do
348 | Writeln(cursor.value.size());
349 |
350 | WriteLn(gf.seek(100000));
351 |
352 | gfs.storeFile('../../MongoDB.pas', 'MongoDB.pas');
353 | gf := gfs.find('MongoDB.pas');
354 | gf.seek(100);
355 | gf.read(@buf, 20);
356 | buf[20] := Chr(0);
357 | WriteLn(buf);
358 |
359 | ExtractFile(gfs, 'MongoDB.pas');
360 | WriteLn('Done');
361 | ReadLn;
362 | end
363 | else
364 | WriteLn('No Connection, Err = ', mongo.getErr());
365 |
366 | except
367 | on E: Exception do
368 | Writeln(E.ClassName, ': ', E.Message);
369 | end;
370 | end.
371 |
--------------------------------------------------------------------------------
/Test.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {FAAEB811-D3CA-4036-A456-D65CA8564F65}
4 | 13.4
5 | None
6 | Test.dpr
7 | True
8 | Debug
9 | Win32
10 | 3
11 | Console
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Base
40 | true
41 |
42 |
43 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;ibxpress;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;FMXTee;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;CloudService;FmxTeeUI;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)
44 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
45 | .\$(Platform)\$(Config)
46 | .\$(Platform)\$(Config)
47 | false
48 | false
49 | false
50 | false
51 | false
52 |
53 |
54 | TeeDB;vclib;Tee;DBXOdbcDriver;DBXSybaseASEDriver;vclimg;TeeUI;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;vclribbon;VclSmp;vcl;DataSnapConnectors;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;adortl;$(DCC_UsePackage)
55 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
56 | 1033
57 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
58 |
59 |
60 | vcldbx;frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;VclSmp;fsDB16;vcl;DataSnapConnectors;DBXMSSQLDriver;CodeSiteExpressPkg;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage)
61 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
62 | 1033
63 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
64 |
65 |
66 | DEBUG;$(DCC_Define)
67 | false
68 | true
69 | true
70 | true
71 |
72 |
73 | false
74 |
75 |
76 | false
77 | RELEASE;$(DCC_Define)
78 | 0
79 | false
80 |
81 |
82 |
83 | MainSource
84 |
85 |
86 | Cfg_2
87 | Base
88 |
89 |
90 | Base
91 |
92 |
93 | Cfg_1
94 | Base
95 |
96 |
97 |
98 | Delphi.Personality.12
99 |
100 |
101 |
102 |
103 | False
104 | False
105 | 1
106 | 0
107 | 0
108 | 0
109 | False
110 | False
111 | False
112 | False
113 | False
114 | 1033
115 | 1252
116 |
117 |
118 |
119 |
120 | 1.0.0.0
121 |
122 |
123 |
124 |
125 |
126 | 1.0.0.0
127 |
128 |
129 |
130 | Test.dpr
131 |
132 |
133 |
134 |
135 | True
136 | False
137 | True
138 |
139 |
140 | 12
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/Test.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gerald-lindsly/mongo-delphi-driver/6f4e145bab99ad3d737c484a8d0c3f284828a6f6/Test.res
--------------------------------------------------------------------------------
/mongo-c-driver.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gerald-lindsly/mongo-delphi-driver/6f4e145bab99ad3d737c484a8d0c3f284828a6f6/mongo-c-driver.zip
--------------------------------------------------------------------------------