├── .gitignore
├── .gitmodules
├── CONTRIBUTING.md
├── COPYING.md
├── HowToBuild.md
├── Libraries
├── Build.wl
└── MongoLink
│ ├── bulk_operation.cpp
│ ├── management.cpp
│ ├── wl_bson.cpp
│ ├── wl_bson_parser.cpp
│ ├── wl_client.cpp
│ ├── wl_collection.cpp
│ ├── wl_common.cpp
│ ├── wl_common.h
│ ├── wl_cursor.cpp
│ ├── wl_database.cpp
│ ├── wl_uri.cpp
│ └── wl_write_concern.cpp
├── MongoLink
├── Documentation
│ └── English
│ │ ├── Guides
│ │ └── MongoLinkOperations.nb
│ │ ├── ReferencePages
│ │ └── Symbols
│ │ │ ├── $MongoDefaultCAFile.nb
│ │ │ ├── BSONDecimal128.nb
│ │ │ ├── BSONObjectID.nb
│ │ │ ├── MongoClient.nb
│ │ │ ├── MongoCollection.nb
│ │ │ ├── MongoCollectionAggregate.nb
│ │ │ ├── MongoCollectionCount.nb
│ │ │ ├── MongoCollectionDeleteMany.nb
│ │ │ ├── MongoCollectionDeleteOne.nb
│ │ │ ├── MongoCollectionDistinct.nb
│ │ │ ├── MongoCollectionDrop.nb
│ │ │ ├── MongoCollectionFind.nb
│ │ │ ├── MongoCollectionFindOne.nb
│ │ │ ├── MongoCollectionInsert.nb
│ │ │ ├── MongoCollectionName.nb
│ │ │ ├── MongoCollectionReplaceOne.nb
│ │ │ ├── MongoCollectionStats.nb
│ │ │ ├── MongoCollectionUpdateMany.nb
│ │ │ ├── MongoCollectionUpdateOne.nb
│ │ │ ├── MongoCollectionValidate.nb
│ │ │ ├── MongoConnect.nb
│ │ │ ├── MongoCursor.nb
│ │ │ ├── MongoCursorGetBatchSize.nb
│ │ │ ├── MongoCursorNext.nb
│ │ │ ├── MongoCursorSetBatchSize.nb
│ │ │ ├── MongoCursorToArray.nb
│ │ │ ├── MongoDatabase.nb
│ │ │ ├── MongoDatabaseDrop.nb
│ │ │ ├── MongoDatabaseName.nb
│ │ │ ├── MongoDriverVersion.nb
│ │ │ ├── MongoGetCollection.nb
│ │ │ ├── MongoGetCollectionNames.nb
│ │ │ ├── MongoGetDatabase.nb
│ │ │ ├── MongoGetDatabaseNames.nb
│ │ │ ├── MongoInsertResult.nb
│ │ │ ├── MongoWriteConcern.nb
│ │ │ └── MongoWriteConcernCreate.nb
│ │ └── Tutorials
│ │ └── MongoLinkSimpleTutorial.nb
├── Kernel
│ ├── ACommon.m
│ ├── BSON.m
│ ├── BulkOp.m
│ ├── Client.m
│ ├── Collection.m
│ ├── Cursor.m
│ ├── Database.m
│ ├── SSL
│ │ └── client.pem
│ ├── URI.m
│ ├── Version.m
│ ├── WriteConcern.m
│ └── init.m
└── PacletInfo.m
├── Notes
├── DeveloperNotes.md
├── LocalBuild.nb
└── MongoDBLink.nb
├── Readme.md
├── Tests
├── BSON.wlt
├── Certificates
│ ├── ca.pem
│ └── client.pem
├── RunTests.nb
└── RunTestsCommon.m
└── scripts
├── re_build_MongoLink.wl
└── re_build_MongoLink.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | build-local.properties
3 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WolframResearch/MongoLink/dffb4d150af9d616fc3f268492346a1d1e8cac72/.gitmodules
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Wolfram®
2 |
3 | Thank you for taking the time to contribute to the [Wolfram Research](https://github.com/wolframresearch) repos on GitHub.
4 |
5 | ## Licensing of Contributions
6 |
7 | By contributing to Wolfram, you agree and affirm that:
8 |
9 | > Wolfram may release your contribution under the terms of the [MIT license](https://opensource.org/licenses/MIT); and
10 |
11 | > You have read and agreed to the [Developer Certificate of Origin](http://developercertificate.org/), version 1.1 or later.
12 |
13 | Please see [COPYING.md](COPYING.md) for licensing conditions pertaining
14 | to individual repositories.
15 |
16 | ## Style
17 |
18 | Please use the [LLVM style](http://llvm.org/docs/CodingStandards.html) for the C/C++ interface code. Use of `clang-format` to conform code is encouraged, rather than conforming by hand.
19 |
20 | For Wolfram Language code, try follow the style used in the current
21 |
22 | ## Bug reports
23 |
24 | ### Security Bugs
25 |
26 | Please **DO NOT** file a public issue regarding a security issue.
27 | Rather, send your report privately to security@wolfram.com. Security
28 | reports are appreciated and we will credit you for it. We do not offer
29 | a security bounty, but the forecast in your neighborhood will be cloudy
30 | with a chance of Wolfram schwag!
31 |
32 | ### General Bugs
33 |
34 | Please use the repository issues page to submit general bug issues.
35 |
36 | Please do not duplicate issues.
37 |
38 | Please do send a complete and well-written report to us. Note: **the
39 | thoroughness of your report will positively correlate to our willingness
40 | and ability to address it**.
41 |
42 | When reporting issues, always include:
43 |
44 | * Your version of *Mathematica*® or the Wolfram Language™.
45 | * Your operating system.
46 | * If you built MongoLink yourself, then the version of Mongo C Driver you are using.
--------------------------------------------------------------------------------
/COPYING.md:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
--------------------------------------------------------------------------------
/HowToBuild.md:
--------------------------------------------------------------------------------
1 | ## How to build MongoLink
2 |
3 | MongoLink has two buildable components: the documentation, and a shared library component which is loaded via LibraryLink. This document covers only how to build and run the shared library component.
4 |
5 | #### Building the Mongo C Driver
6 | Follow the instructions on the Mongo Driver page (http://mongoc.org/libmongoc/current/installing.html). Both build and install the driver.
7 |
8 | #### Building MongoLink
9 | Let `$PacletDir` be the MongoLink base directory. Then:
10 | ```
11 | Get@FileNameJoin[{$PacletDir, "Libraries", "Build.wl"}]
12 | BuildMongoLink[]
13 | ```
14 | will build MongoLink, and create a folder `LibraryResources` which will contain the built library.
15 |
16 | Equivalently, open the `Notes\LocalBuild.nb` notebook follow the instructions.
17 |
18 | `BuildMongoLink[]` assumes you have build the Mongo C Driver and installed it in the default location, (`C:\mongo-c-driver` for Windows). It will fail if the built Mongo C Driver is not in this location.
19 |
20 | #### Using the local build of MongoLink
21 | Evaluate the following:
22 | ```
23 | PacletDirectoryAdd[{$PacletDir}];
24 | < False,
24 | "CompileOptions" -> "",
25 | "ShellCommandFunction" -> None
26 | };
27 |
28 | BuildMongoLink[opts:OptionsPattern[]] := Catch @ Module[
29 | {
30 | compileOpts, wlSrc, lib, libResourceLib, libResourceDir,
31 | libNames, fullIncl, includeDir, libDir
32 | }
33 | ,
34 | compileOpts = OptionValue["CompileOptions"];
35 | Switch[$OperatingSystem,
36 | "Windows",
37 | includeDir = {"C:\\mongo-c-driver"};
38 | libDir = {"C:\\mongo-c-driver"}
39 | ,
40 | "MacOSX",
41 | compileOpts = StringJoin[
42 | "-std=c++11 ",
43 | "-Xlinker -install_name ",
44 | "-Xlinker @rpath/MongoLink.dylib ",
45 | "-Xlinker -rpath -Xlinker @loader_path/ ",
46 | compileOpts
47 | ];
48 | includeDir =
49 | {"/usr/local/include/libbson-1.0", "/usr/local/include/libmongoc-1.0"};
50 | libDir = {"/usr/local/lib"};
51 | libDir = {"/Users/sebastianb/Documents/workspace/MongoC/1.7.0/MacOSX-x86-64/libcxx-min10.9/lib/"}
52 | ,
53 | "Unix",
54 | compileOpts = "-std=c++11 -fvisibility=hidden " <> compileOpts;
55 | ];
56 | libNames = {"mongoc-1.0.0", "bson-1.0.0"};
57 |
58 | (* WL Source *)
59 | wlSrc = FileNames["*.cpp", {FileNameJoin[{$RootDir, "Libraries", "MongoLink"}]}];
60 | fullIncl = Join[{FileNameJoin[{$RootDir, "Libraries", "MongoLink"}]}, includeDir];
61 | (* Build *)
62 | lib = CreateLibrary[
63 | wlSrc, "MongoLink",
64 | "IncludeDirectories"-> fullIncl,
65 | "Libraries" -> libNames,
66 | "LibraryDirectories" -> libDir,
67 | "CompileOptions" -> compileOpts,
68 | "Language" -> "C++",
69 | "Debug" -> OptionValue["Debug"],
70 | "CleanIntermediate"-> True,
71 | "ShellCommandFunction" -> OptionValue["ShellCommandFunction"]
72 | ];
73 |
74 | (* Postprocessing: copy build to paclet *)
75 | libResourceDir = FileNameJoin[{$RootDir , "MongoLink", "LibraryResources", $SystemID}];
76 | libResourceLib = FileNameJoin[{libResourceDir, FileNameTake[lib]}];
77 |
78 | If[FileExistsQ[libResourceLib],
79 | DeleteFile[libResourceLib]
80 | ];
81 | If[Not @ FileExistsQ[libResourceDir],
82 | CreateDirectory[libResourceDir]
83 | ];
84 | CopyFile[lib, libResourceLib];
85 |
86 | (* test whether lib can be loaded *)
87 | LibraryLoad[libResourceLib];
88 | {lib, LibraryLink`$LibraryError}
89 | ]
90 |
91 | (*************************************************************************)
92 | End[ ]
93 |
94 | EndPackage[ ]
--------------------------------------------------------------------------------
/Libraries/MongoLink/bulk_operation.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // Bulk Op
3 | // - For API guide, see:
4 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_t.html
5 | ////////////////////////////////////////////////////////////////////////////////
6 |
7 | #include "wl_common.h"
8 |
9 | bool is_transaction_acknowledged(mongoc_write_concern_t *wc,
10 | mongoc_collection_t *coll) {
11 | // if wc was NULL, then the write concern from the collection is used.
12 | // insertMany and insertOne require the return of whether the transaction was
13 | // acknowledged
14 | bool acknowledged;
15 | if (!wc)
16 | acknowledged = mongoc_write_concern_is_acknowledged(
17 | mongoc_collection_get_write_concern(coll));
18 | else
19 | acknowledged = mongoc_write_concern_is_acknowledged(wc);
20 | return acknowledged;
21 | }
22 |
23 | /*----------------------------------------------------------------------------*/
24 |
25 | EXTERN_C DLLEXPORT int WL_CreateBulkOpFromCollection(WolframLibraryData libData,
26 | mint Argc, MArgument *Args,
27 | MArgument Res) {
28 | int bulkop_handle_key = MArgument_getInteger(Args[0]);
29 | COLLECTION_GET(collection, 1)
30 | WRITE_CONCERN_GET(wc, 2)
31 | bool ordered = MArgument_getBoolean(Args[3]);
32 |
33 | mongoc_bulk_operation_t *bulk =
34 | mongoc_collection_create_bulk_operation(collection, ordered, wc);
35 |
36 | bulkOperationHandleMap[bulkop_handle_key] = bulk;
37 |
38 | mbool ack = is_transaction_acknowledged(wc, collection);
39 | MArgument_setBoolean(Res, ack);
40 | return LIBRARY_NO_ERROR;
41 | }
42 |
43 | EXTERN_C DLLEXPORT int WL_BulkOpExecute(WolframLibraryData libData, mint Argc,
44 | MArgument *Args, MArgument Res) {
45 | BULK_OP_GET(bulk, 0)
46 | int reply_bson_key = MArgument_getInteger(Args[1]);
47 | bson_t reply;
48 | bson_error_t error;
49 | bool res = mongoc_bulk_operation_execute(bulk, &reply, &error);
50 | if (!res) {
51 | errorString = error.message;
52 | return LIBRARY_FUNCTION_ERROR;
53 | }
54 | bsonHandleMap[reply_bson_key] = bson_copy(&reply);
55 | return LIBRARY_NO_ERROR;
56 | }
57 |
58 | EXTERN_C DLLEXPORT int
59 | WL_mongoc_bulk_operation_update(WolframLibraryData libData, mint Argc,
60 | MArgument *Args, MArgument Res) {
61 | BULK_OP_GET(bulk, 0)
62 | BSON_GET(selector, 1)
63 | BSON_GET(document, 2)
64 | BSON_GET(opts, 3)
65 | bool many = MArgument_getBoolean(Args[4]);
66 |
67 | bson_error_t error;
68 | bool res;
69 | if (many) {
70 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_update_many_with_opts.html
71 | res = mongoc_bulk_operation_update_many_with_opts(bulk, selector, document,
72 | opts, &error);
73 | } else {
74 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_update_one_with_opts.html
75 | res = mongoc_bulk_operation_update_one_with_opts(bulk, selector, document,
76 | opts, &error);
77 | }
78 | if (!res) {
79 | errorString = error.message;
80 | return LIBRARY_FUNCTION_ERROR;
81 | }
82 |
83 | return LIBRARY_NO_ERROR;
84 | }
85 |
86 | EXTERN_C DLLEXPORT int
87 | WL_mongoc_bulk_operation_insert(WolframLibraryData libData, mint Argc,
88 | MArgument *Args, MArgument Res) {
89 | BULK_OP_GET(bulk, 0)
90 | BSON_GET(opts, 1)
91 | auto doc_keys_tensor = MArgument_getMTensor(Args[2]);
92 | auto num_docs = libData->MTensor_getFlattenedLength(doc_keys_tensor);
93 | auto doc_keys = libData->MTensor_getIntegerData(doc_keys_tensor);
94 |
95 | // insert docs
96 | bson_t *doc;
97 | bson_oid_t oid;
98 | bson_error_t error;
99 | for (int i = 0; i < num_docs; i++) {
100 | mint doc_key = doc_keys[i];
101 | if (bsonHandleMap.count(doc_key) == 0) {
102 | return LIBRARY_FUNCTION_ERROR;
103 | }
104 | doc = bsonHandleMap[doc_key];
105 | // check whether bson has oid. If not, create oid and append to bson
106 | // Need to do this as insertOne API requires returning "_id" field of
107 | // inserted docs, and C Driver does not support this
108 | if (!bson_has_field(doc, "_id")) {
109 | bson_oid_init(&oid, NULL);
110 | BSON_APPEND_OID(doc, "_id", &oid);
111 | }
112 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_insert_with_opts.html
113 | bool res = mongoc_bulk_operation_insert_with_opts(bulk, doc, opts, &error);
114 | if (!res) {
115 | errorString = error.message;
116 | return LIBRARY_FUNCTION_ERROR;
117 | }
118 | }
119 | return LIBRARY_NO_ERROR;
120 | }
121 |
122 | EXTERN_C DLLEXPORT int
123 | WL_mongoc_bulk_operation_remove(WolframLibraryData libData, mint Argc,
124 | MArgument *Args, MArgument Res) {
125 | BULK_OP_GET(bulk, 0)
126 | BSON_GET(selector, 1)
127 | BSON_GET(opts, 2)
128 | bool many = MArgument_getBoolean(Args[3]);
129 |
130 | bson_error_t error;
131 | bool res;
132 | if (many) {
133 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_remove_many_with_opts.html
134 | res = mongoc_bulk_operation_remove_many_with_opts(bulk, selector, opts,
135 | &error);
136 | } else {
137 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_remove_one_with_opts.html
138 | res = mongoc_bulk_operation_remove_one_with_opts(bulk, selector, opts,
139 | &error);
140 | }
141 | if (!res) {
142 | errorString = error.message;
143 | return LIBRARY_FUNCTION_ERROR;
144 | }
145 |
146 | return LIBRARY_NO_ERROR;
147 | }
148 |
149 | EXTERN_C DLLEXPORT int
150 | WL_mongoc_bulk_operation_replace_one(WolframLibraryData libData, mint Argc,
151 | MArgument *Args, MArgument Res) {
152 | BULK_OP_GET(bulk, 0)
153 | BSON_GET(selector, 1)
154 | BSON_GET(document, 2)
155 | BSON_GET(opts, 3)
156 |
157 | // http://mongoc.org/libmongoc/current/mongoc_bulk_operation_replace_one_with_opts.html
158 | bson_error_t error;
159 | bool res =
160 | mongoc_bulk_operation_replace_one_with_opts(bulk, selector, document, opts, &error);
161 | if (!res) {
162 | errorString = error.message;
163 | return LIBRARY_FUNCTION_ERROR;
164 | }
165 |
166 | return LIBRARY_NO_ERROR;
167 | }
--------------------------------------------------------------------------------
/Libraries/MongoLink/management.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // ManagedLibraryExpression code
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | #include "wl_common.h"
6 |
7 | /*----------------------------------------------------------------------------*/
8 |
9 | DLLEXPORT void manage_instance_mongobson(WolframLibraryData libData, mbool mode,
10 | mint id) {
11 | // Destruction
12 | if ((mode != 0) && (bsonHandleMap.count(id) > 0)) {
13 | bson_destroy(bsonHandleMap[id]);
14 | bsonHandleMap.erase(id);
15 | }
16 | }
17 |
18 | DLLEXPORT void manage_instance_mongobulkoperation(WolframLibraryData libData,
19 | mbool mode, mint id) {
20 | // Only do destruction. Deal with creation later
21 | if ((mode != 0) && (bulkOperationHandleMap.count(id) > 0)) {
22 | mongoc_bulk_operation_destroy(bulkOperationHandleMap[id]);
23 | bulkOperationHandleMap.erase(id);
24 | }
25 | }
26 |
27 | DLLEXPORT void manage_instance_mongoclient(WolframLibraryData libData,
28 | mbool mode, mint id) {
29 | // Only do destruction. Deal with creation later
30 | if ((mode != 0) && (clientHandleMap.count(id) > 0)) {
31 | // API: http://api.mongodb.org/c/current/mongoc_client_destroy.html
32 | mongoc_client_destroy(clientHandleMap[id]);
33 | clientHandleMap.erase(id);
34 | }
35 | }
36 |
37 | DLLEXPORT void manage_instance_mongocollection(WolframLibraryData libData,
38 | mbool mode, mint id) {
39 | // Only do destruction. Deal with creation later
40 | if ((mode != 0) && (collectionHandleMap.count(id) > 0)) {
41 | mongoc_collection_destroy(collectionHandleMap[id]);
42 | collectionHandleMap.erase(id);
43 | }
44 | }
45 |
46 | DLLEXPORT void manage_instance_mongodatabase(WolframLibraryData libData,
47 | mbool mode, mint id) {
48 | // Only do destruction. Deal with creation later
49 | if ((mode != 0) && (databaseHandleMap.count(id) > 0)) {
50 | mongoc_database_destroy(databaseHandleMap[id]);
51 | databaseHandleMap.erase(id);
52 | }
53 | }
54 |
55 | DLLEXPORT void manage_instance_mongocursor(WolframLibraryData libData,
56 | mbool mode, mint id) {
57 | // Destruction
58 | if ((mode != 0) && (cursorHandleMap.count(id) > 0)) {
59 | mongoc_cursor_destroy(cursorHandleMap[id]);
60 | cursorHandleMap.erase(id);
61 | }
62 | }
63 |
64 | DLLEXPORT void manage_instance_mongouri(WolframLibraryData libData, mbool mode,
65 | mint id) {
66 | // Only do destruction. Deal with creation later
67 | if ((mode != 0) && (uriHandleMap.count(id) > 0)) {
68 | // API: http://mongoc.org/libmongoc/current/mongoc_uri_destroy.html
69 | mongoc_uri_destroy(uriHandleMap[id]);
70 | uriHandleMap.erase(id);
71 | }
72 | }
73 |
74 | DLLEXPORT void manage_instance_mongowriteconcern(WolframLibraryData libData,
75 | mbool mode, mint id) {
76 | // Destruction
77 | if (mode != 0 && (writeConcernHandleMap.count(id) > 0)) {
78 | mongoc_write_concern_destroy(writeConcernHandleMap[id]);
79 | writeConcernHandleMap.erase(id);
80 | }
81 | }
82 |
83 | /*----------------------------------------------------------------------------*/
84 | void my_logger(mongoc_log_level_t log_level, const char *log_domain,
85 | const char *message, void *user_data) {
86 | errorString = std::string(message);
87 | }
88 |
89 |
90 | /* Return the version of Library Link */
91 | EXTERN_C DLLEXPORT mint WolframLibrary_getVersion() {
92 | return WolframLibraryVersion;
93 | }
94 |
95 | EXTERN_C DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) {
96 | // initialize mongodb
97 | mongoc_init();
98 | mongoc_log_set_handler(my_logger, NULL);
99 |
100 | // Register All Library Managers
101 | (*libData->registerLibraryExpressionManager)("URI", manage_instance_mongouri);
102 | (*libData->registerLibraryExpressionManager)("Client",
103 | manage_instance_mongoclient);
104 | (*libData->registerLibraryExpressionManager)(
105 | "BulkOp", manage_instance_mongobulkoperation);
106 | (*libData->registerLibraryExpressionManager)("Database",
107 | manage_instance_mongodatabase);
108 | (*libData->registerLibraryExpressionManager)("Collection",
109 | manage_instance_mongocollection);
110 | (*libData->registerLibraryExpressionManager)(
111 | "WriteConcern", manage_instance_mongowriteconcern);
112 | (*libData->registerLibraryExpressionManager)("BSON",
113 | manage_instance_mongobson);
114 | (*libData->registerLibraryExpressionManager)("Cursor",
115 | manage_instance_mongocursor);
116 | return 0;
117 | }
118 |
119 | EXTERN_C DLLEXPORT void
120 | WolframLibrary_uninitialize(WolframLibraryData libData) {
121 | // Cleanup mongo
122 | mongoc_cleanup();
123 | // Unitialize All Library Managers
124 | (*libData->unregisterLibraryExpressionManager)("URI");
125 | (*libData->unregisterLibraryExpressionManager)("BulkOp");
126 | (*libData->unregisterLibraryExpressionManager)("Client");
127 | (*libData->unregisterLibraryExpressionManager)("Database");
128 | (*libData->unregisterLibraryExpressionManager)("Collection");
129 | (*libData->unregisterLibraryExpressionManager)("WriteConcern");
130 | (*libData->unregisterLibraryExpressionManager)("BSON");
131 | (*libData->unregisterLibraryExpressionManager)("Cursor");
132 | return;
133 | }
134 |
135 | /*----------------------------------------------------------------------------*/
136 |
137 | EXTERN_C DLLEXPORT int WL_MongoGetLastError(WolframLibraryData libData,
138 | mint Argc, MArgument *Args,
139 | MArgument Res) {
140 | MArgument_setUTF8String(Res, const_cast(errorString.c_str()));
141 | return LIBRARY_NO_ERROR;
142 | }
143 |
144 | EXTERN_C DLLEXPORT int WL_MongoEraseLastError(WolframLibraryData libData,
145 | mint Argc, MArgument *Args,
146 | MArgument Res) {
147 | errorString = "";
148 | return LIBRARY_NO_ERROR;
149 | }
150 |
151 | EXTERN_C DLLEXPORT int WL_MongoGetVersion(WolframLibraryData libData, mint Argc,
152 | MArgument *Args, MArgument Res) {
153 | returnString = MONGOC_VERSION_S;
154 | MArgument_setUTF8String(Res, const_cast(returnString.c_str()));
155 | return LIBRARY_NO_ERROR;
156 | }
157 |
158 | // initializer: "It is responsible for initializing global state such as \
159 | // process counters, SSL, and threading primitives."
160 | // http://mongoc.org/libmongoc/current/mongoc_init.html
161 | EXTERN_C DLLEXPORT int WL_MongoInitialize(WolframLibraryData libData, mint Argc,
162 | MArgument *Args, MArgument Res) {
163 | mongoc_init();
164 | return LIBRARY_NO_ERROR;
165 | }
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_bson.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // BSON functions
3 | // - For API guide, see: http://mongoc.org/libbson/current/index.html
4 | ////////////////////////////////////////////////////////////////////////////////
5 |
6 | #include "wl_common.h"
7 |
8 | /*----------------------------------------------------------------------------*/
9 |
10 | EXTERN_C DLLEXPORT int WL_CreateBSONfromJSON(WolframLibraryData libData,
11 | mint Argc, MArgument *Args,
12 | MArgument Res) {
13 | int bson_handle_key = MArgument_getInteger(Args[0]);
14 | char *json = MArgument_getUTF8String(Args[1]);
15 |
16 | bson_error_t error;
17 | auto b = bson_new_from_json((const uint8_t *)json, -1, &error);
18 | if (!b) {
19 | errorString = error.message;
20 | libData->UTF8String_disown(json);
21 | return LIBRARY_FUNCTION_ERROR;
22 | }
23 | bsonHandleMap[bson_handle_key] = b;
24 | // Disown string
25 | libData->UTF8String_disown(json);
26 | return LIBRARY_NO_ERROR;
27 | }
28 |
29 | EXTERN_C DLLEXPORT int WL_bsonAsJSON(WolframLibraryData libData, mint Argc,
30 | MArgument *Args, MArgument Res) {
31 | BSON_GET(bson, 0)
32 | bool relaxed = MArgument_getInteger(Args[1]);
33 | // the returned json strings lifetime must be longer than this function
34 | // (standard string return in LibraryLink)
35 | if (returnBSONJSON) {
36 | bson_free(returnBSONJSON);
37 | returnBSONJSON = NULL;
38 | }
39 | if (relaxed) {
40 | returnBSONJSON = bson_as_relaxed_extended_json(bson, NULL);
41 | } else {
42 | returnBSONJSON = bson_as_canonical_extended_json(bson, NULL);
43 | }
44 | MArgument_setUTF8String(Res, returnBSONJSON);
45 | return LIBRARY_NO_ERROR;
46 | }
47 |
48 | EXTERN_C DLLEXPORT int WL_raw_array_to_bson(WolframLibraryData libData,
49 | mint Argc, MArgument *Args,
50 | MArgument Res) {
51 | int bson_handle_key = MArgument_getInteger(Args[0]);
52 | MRawArray data_tensor = MArgument_getMRawArray(Args[1]);
53 |
54 | size_t size = libData->rawarrayLibraryFunctions->MRawArray_getFlattenedLength(
55 | data_tensor);
56 | auto data = reinterpret_cast(
57 | libData->rawarrayLibraryFunctions->MRawArray_getData(data_tensor));
58 |
59 | auto b = bson_new_from_data(data, size);
60 | if (!b)
61 | return LIBRARY_FUNCTION_ERROR;
62 |
63 | bsonHandleMap[bson_handle_key] = b;
64 | return LIBRARY_NO_ERROR;
65 | }
66 |
67 | EXTERN_C DLLEXPORT int WL_bson_to_rawarray(WolframLibraryData libData,
68 | mint Argc, MArgument *Args,
69 | MArgument Res) {
70 | BSON_GET(bson, 0)
71 | auto data = bson_get_data(bson);
72 | mint dims[1] = {bson->len};
73 |
74 | MRawArray output_raw;
75 | libData->rawarrayLibraryFunctions->MRawArray_new(MRawArray_Type_Ubit8, 1,
76 | dims, &output_raw);
77 |
78 | auto data_raw = reinterpret_cast(
79 | libData->rawarrayLibraryFunctions->MRawArray_getData(output_raw));
80 | std::copy(data, data + bson->len, data_raw);
81 |
82 | // Return RawArray
83 | MArgument_setMRawArray(Res, output_raw);
84 | return LIBRARY_NO_ERROR;
85 | }
86 |
87 | EXTERN_C DLLEXPORT int WL_get_bson_key(WolframLibraryData libData, mint Argc,
88 | MArgument *Args, MArgument Res) {
89 | BSON_GET(bson, 0)
90 | mint out_bson_key = MArgument_getInteger(Args[1]);
91 | char *key = MArgument_getUTF8String(Args[2]);
92 |
93 | bson_iter_t iter;
94 | // return 0 if key not found, 1 if found
95 | // http://mongoc.org/libbson/current/bson_iter_init_find_case.html
96 | bool result = bson_iter_init_find(&iter, bson, key);
97 |
98 | bson_t *out_bson = bson_new();
99 | bsonHandleMap[out_bson_key] = out_bson;
100 | // http://mongoc.org/libbson/current/bson_append_iter.html
101 | if (result)
102 | bson_append_iter(out_bson, key, -1, &iter);
103 |
104 | libData->UTF8String_disown(key);
105 | MArgument_setInteger(Res, static_cast(result));
106 | return LIBRARY_NO_ERROR;
107 | }
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_bson_parser.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // BSON Parser
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | #include "wl_common.h"
6 |
7 | /*----------------------------------------------------------------------------*/
8 |
9 | #define MATH_CHECK(func) \
10 | { \
11 | int mathlink_func_err = (func); \
12 | if (mathlink_func_err == 0) { \
13 | return true; \
14 | } \
15 | }
16 |
17 | /*
18 | * Structures.
19 | */
20 |
21 | typedef struct {
22 | uint32_t count;
23 | bool keys;
24 | uint32_t depth;
25 | MLINK *wstp_state;
26 | } bson_wl_state_t;
27 |
28 | /*
29 | * Forward declarations.
30 | */
31 | static bool _bson_as_wl_visit_array(const bson_iter_t *iter, const char *key,
32 | const bson_t *v_array, void *data);
33 |
34 | static bool _bson_as_wl_visit_document(const bson_iter_t *iter, const char *key,
35 | const bson_t *v_document, void *data);
36 |
37 | bool _bson_as_wl_visit_before(const bson_iter_t *iter, const char *key,
38 | void *data) {
39 | auto s = reinterpret_cast(data);
40 |
41 | s->count++;
42 | MLINK *mlp = s->wstp_state;
43 |
44 | if (s->keys) {
45 | MATH_CHECK(MLPutFunction(*mlp, "Rule", 2));
46 | int key_len = strlen(key);
47 | MATH_CHECK(MLPutUTF8String(
48 | *mlp, reinterpret_cast(key), key_len));
49 | }
50 |
51 | return false;
52 | }
53 |
54 | void visit_corrupt(const bson_iter_t *iter, void *data) {
55 | errorString = "Error: Visited corrupt data!";
56 | std::cout << errorString << std::endl;
57 | }
58 |
59 | /* normal bson field callbacks */
60 | bool _bson_as_wl_visit_double(const bson_iter_t *iter, const char *key,
61 | double v_double, void *data) {
62 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
63 | MATH_CHECK(MLPutReal64(*mlp, v_double));
64 |
65 | return false;
66 | }
67 |
68 | bool _bson_as_wl_visit_utf8(const bson_iter_t *iter, const char *key,
69 | size_t v_utf8_len, const char *v_utf8, void *data) {
70 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
71 | MATH_CHECK(MLPutUTF8String(*mlp,
72 | reinterpret_cast(v_utf8),
73 | static_cast(v_utf8_len)));
74 | return false;
75 | }
76 |
77 | bool _bson_as_wl_visit_binary(const bson_iter_t *iter, const char *key,
78 | bson_subtype_t v_subtype, size_t v_binary_len,
79 | const uint8_t *v_binary, void *data) {
80 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
81 | MATH_CHECK(MLPutFunction(*mlp, "ByteArray", 1));
82 | MATH_CHECK(MLPutInteger8List(*mlp, (unsigned char *)v_binary,
83 | static_cast(v_binary_len)));
84 | return false;
85 | }
86 |
87 | /* normal field with deprecated "Undefined" BSON type */
88 | bool _bson_as_wl_visit_undefined(const bson_iter_t *iter, const char *key,
89 | void *data) {
90 | errorString = "Encountered Undefined type. Not currently supported.";
91 | return true;
92 | }
93 |
94 | bool _bson_as_wl_visit_oid(const bson_iter_t *iter, const char *key,
95 | const bson_oid_t *v_oid, void *data) {
96 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
97 | char str[25];
98 | bson_oid_to_string(v_oid, str);
99 | MATH_CHECK(MLPutFunction(*mlp, "BSONObjectID", 1));
100 | // don't need general UTF8 string here
101 | MATH_CHECK(MLPutString(*mlp, str));
102 | return false;
103 | }
104 |
105 | bool _bson_as_wl_visit_bool(const bson_iter_t *iter, const char *key,
106 | bool v_bool, void *data) {
107 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
108 | if (v_bool) {
109 | MATH_CHECK(MLPutSymbol(*mlp, "True"));
110 | } else {
111 | MATH_CHECK(MLPutSymbol(*mlp, "False"));
112 | }
113 |
114 | return false;
115 | }
116 |
117 | bool _bson_as_wl_visit_date_time(const bson_iter_t *iter, const char *key,
118 | int64_t msec_since_epoch, void *data) {
119 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
120 | MATH_CHECK(
121 | MLPutFunction(*mlp, "MongoLink`PackageScope`FromMillisecondUnixTime", 1));
122 | MATH_CHECK(MLPutInteger64(*mlp, static_cast(msec_since_epoch)));
123 | return false;
124 | }
125 |
126 | bool _bson_as_wl_visit_null(const bson_iter_t *iter, const char *key,
127 | void *data) {
128 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
129 | MATH_CHECK(MLPutSymbol(*mlp, "Null"));
130 | return false;
131 | }
132 |
133 | bool _bson_as_wl_visit_regex(const bson_iter_t *iter, const char *key,
134 | const char *v_regex, const char *v_options,
135 | void *data) {
136 | errorString = "Encountered regex type. Not currently supported.";
137 | return true;
138 | }
139 |
140 | bool _bson_as_wl_visit_dbpointer(const bson_iter_t *iter, const char *key,
141 | size_t v_collection_len,
142 | const char *v_collection,
143 | const bson_oid_t *v_oid, void *data) {
144 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
145 | MATH_CHECK(MLPutFunction(*mlp, "BSONDBReference", 2));
146 | // Collection
147 | MATH_CHECK(MLPutString(*mlp, v_collection));
148 | // OID
149 | char str[25];
150 | bson_oid_to_string(v_oid, str);
151 | MATH_CHECK(MLPutFunction(*mlp, "BSONObjectID", 1));
152 | MATH_CHECK(MLPutString(*mlp, str));
153 |
154 | return false;
155 | }
156 |
157 | bool _bson_as_wl_visit_code(const bson_iter_t *iter, const char *key,
158 | size_t v_code_len, const char *v_code, void *data) {
159 | errorString = "Encountered javascript type. Not currently supported.";
160 | return true;
161 | }
162 |
163 | bool _bson_as_wl_visit_symbol(const bson_iter_t *iter, const char *key,
164 | size_t v_symbol_len, const char *v_symbol,
165 | void *data) {
166 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
167 | MATH_CHECK(MLPutSymbol(*mlp, v_symbol));
168 | return false;
169 | }
170 |
171 | bool _bson_as_wl_visit_codewscope(const bson_iter_t *iter, const char *key,
172 | size_t v_code_len, const char *v_code,
173 | const bson_t *v_scope, void *data) {
174 | errorString =
175 | "Encountered javascriptWithScope type. Not currently supported.";
176 | return true;
177 | }
178 |
179 | bool _bson_as_wl_visit_int32(const bson_iter_t *iter, const char *key,
180 | int32_t v_int32, void *data) {
181 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
182 | MATH_CHECK(MLPutInteger32(*mlp, static_cast(v_int32)));
183 | return false;
184 | }
185 |
186 | bool _bson_as_wl_visit_timestamp(const bson_iter_t *iter, const char *key,
187 | uint32_t v_timestamp, uint32_t v_increment,
188 | void *data) {
189 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
190 | MATH_CHECK(MLPutFunction(*mlp, "BSONTimestamp", 2));
191 | MATH_CHECK(MLPutInteger32(*mlp, static_cast(v_timestamp)));
192 | MATH_CHECK(MLPutInteger32(*mlp, static_cast(v_increment)));
193 | return false;
194 | }
195 |
196 | bool _bson_as_wl_visit_int64(const bson_iter_t *iter, const char *key,
197 | int64_t v_int64, void *data) {
198 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
199 | MATH_CHECK(MLPutInteger64(*mlp, static_cast(v_int64)));
200 | return false;
201 | }
202 |
203 | bool _bson_as_wl_visit_maxkey(const bson_iter_t *iter, const char *key,
204 | void *data) {
205 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
206 | MATH_CHECK(MLPutFunction(*mlp, "DirectedInfinity", 1));
207 | MATH_CHECK(MLPutInteger64(*mlp, 1));
208 | return false;
209 | }
210 |
211 | bool _bson_as_wl_visit_minkey(const bson_iter_t *iter, const char *key,
212 | void *data) {
213 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
214 | MATH_CHECK(MLPutFunction(*mlp, "DirectedInfinity", 1));
215 | MATH_CHECK(MLPutInteger64(*mlp, -1));
216 | return false;
217 | }
218 |
219 | void visit_unsupported_type(const bson_iter_t *iter, const char *key,
220 | uint32_t type_code, void *data) {
221 |
222 | errorString =
223 | "Encountered unsupported type with type code" + std::to_string(type_code);
224 | }
225 |
226 | bool _bson_as_wl_visit_decimal128(const bson_iter_t *iter, const char *key,
227 | const bson_decimal128_t *v_decimal128,
228 | void *data) {
229 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
230 | char decimal128_string[BSON_DECIMAL128_STRING];
231 | bson_decimal128_to_string(v_decimal128, decimal128_string);
232 | MATH_CHECK(MLPutFunction(*mlp, "ToExpression", 1));
233 | // don't need utf8
234 | MATH_CHECK(MLPutString(*mlp, decimal128_string));
235 | return false;
236 | }
237 |
238 | // See http://mongoc.org/libbson/current/bson_visitor_t.html
239 | const bson_visitor_t bson_as_wl_visitors = {
240 | _bson_as_wl_visit_before,
241 | NULL, /* visit_after */
242 | visit_corrupt, /* visit_corrupt */
243 | _bson_as_wl_visit_double,
244 | _bson_as_wl_visit_utf8,
245 | _bson_as_wl_visit_document,
246 | _bson_as_wl_visit_array,
247 | _bson_as_wl_visit_binary,
248 | _bson_as_wl_visit_undefined,
249 | _bson_as_wl_visit_oid,
250 | _bson_as_wl_visit_bool,
251 | _bson_as_wl_visit_date_time,
252 | _bson_as_wl_visit_null,
253 | _bson_as_wl_visit_regex,
254 | _bson_as_wl_visit_dbpointer,
255 | _bson_as_wl_visit_code,
256 | _bson_as_wl_visit_symbol,
257 | _bson_as_wl_visit_codewscope,
258 | _bson_as_wl_visit_int32,
259 | _bson_as_wl_visit_timestamp,
260 | _bson_as_wl_visit_int64,
261 | _bson_as_wl_visit_maxkey,
262 | _bson_as_wl_visit_minkey,
263 | visit_unsupported_type,
264 | _bson_as_wl_visit_decimal128,
265 | };
266 |
267 | static bool _bson_as_wl_visit_document(const bson_iter_t *iter, const char *key,
268 | const bson_t *v_document, void *data) {
269 | bson_wl_state_t *state = reinterpret_cast(data);
270 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
271 | bson_wl_state_t child_state = {0, true};
272 | bson_iter_t child;
273 |
274 | // should add check for max recursion
275 |
276 | if (bson_iter_init(&child, v_document)) {
277 | int num_initial_keys = static_cast(bson_count_keys(v_document));
278 | MATH_CHECK(MLPutFunction(*mlp, "Association", num_initial_keys));
279 | child_state.wstp_state = mlp;
280 | child_state.depth = state->depth + 1;
281 | return bson_iter_visit_all(&child, &bson_as_wl_visitors, &child_state);
282 | }
283 | return false;
284 | }
285 |
286 | static bool _bson_as_wl_visit_array(const bson_iter_t *iter, const char *key,
287 | const bson_t *v_array, void *data) {
288 | bson_wl_state_t *state = reinterpret_cast(data);
289 | MLINK *mlp = reinterpret_cast(data)->wstp_state;
290 | bson_wl_state_t child_state = {0, false};
291 | bson_iter_t child;
292 |
293 | // should add check for max recursion
294 |
295 | if (bson_iter_init(&child, v_array)) {
296 | int num_initial_keys = static_cast(bson_count_keys(v_array));
297 | MATH_CHECK(MLPutFunction(*mlp, "List", num_initial_keys));
298 | child_state.wstp_state = mlp;
299 | child_state.depth = state->depth + 1;
300 | return bson_iter_visit_all(&child, &bson_as_wl_visitors, &child_state);
301 | }
302 |
303 | return false;
304 | }
305 |
306 | EXTERN_C DLLEXPORT int WL_ParseBSON(WolframLibraryData libData, MLINK mlp) {
307 | errorString = ""; // Clear error string
308 | int bson_handle;
309 | int len;
310 | if (!MLTestHead(mlp, "List", &len) || len != 1)
311 | return LIBRARY_FUNCTION_ERROR;
312 | if (!MLGetInteger(mlp, &bson_handle))
313 | return LIBRARY_FUNCTION_ERROR;
314 | bson_t *bson = bsonHandleMap[bson_handle];
315 |
316 | // Read bson into LinkObject
317 | if (!MLNewPacket(mlp))
318 | return LIBRARY_FUNCTION_ERROR;
319 |
320 | bson_iter_t iter;
321 | if (!bson_iter_init(&iter, bson)) {
322 | return LIBRARY_FUNCTION_ERROR;
323 | }
324 |
325 | bson_wl_state_t state;
326 | state.count = 0;
327 | state.wstp_state = &mlp;
328 | state.depth = 0;
329 | state.keys = true;
330 |
331 | if (!bson || bson_empty(bson)) {
332 | if (!MLPutFunction(mlp, "Association", 0))
333 | return LIBRARY_FUNCTION_ERROR;
334 | return LIBRARY_NO_ERROR;
335 | }
336 |
337 | int num_initial_keys = static_cast(bson_count_keys(bson));
338 | MLPutFunction(mlp, "Association", num_initial_keys);
339 |
340 | if (bson_iter_visit_all(&iter, &bson_as_wl_visitors, &state) ||
341 | iter.err_off) {
342 | // We were prematurely exited due to corruption or failed visitor.
343 | errorString += " BSON parse error.";
344 | return LIBRARY_FUNCTION_ERROR;
345 | }
346 | return LIBRARY_NO_ERROR;
347 | }
348 |
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_client.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // Client-level functions
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | #include "wl_common.h"
6 |
7 | /*----------------------------------------------------------------------------*/
8 |
9 | EXTERN_C DLLEXPORT int WL_ClientHandleCreate(WolframLibraryData libData,
10 | mint Argc, MArgument *Args,
11 | MArgument Res) {
12 | int client_handle_key = MArgument_getInteger(Args[0]);
13 | URI_GET(uri, 1)
14 | auto client = mongoc_client_new_from_uri(uri);
15 | if (!client) {
16 | errorString = "Invalid URI. Cannot connect to client.";
17 | return LIBRARY_FUNCTION_ERROR;
18 | }
19 |
20 | mongoc_client_set_error_api(client, 2);
21 |
22 | // If connection was successful, add to clientHandleMap
23 | clientHandleMap[client_handle_key] = client;
24 | return LIBRARY_NO_ERROR;
25 | }
26 |
27 | EXTERN_C DLLEXPORT int WL_ClientSetSSL(WolframLibraryData libData, mint Argc,
28 | MArgument *Args, MArgument Res) {
29 | CLIENT_GET(client, 0)
30 | char *pem_file = MArgument_getUTF8String(Args[1]);
31 | char *pem_pwd = MArgument_getUTF8String(Args[2]);
32 | char *ca_file = MArgument_getUTF8String(Args[3]);
33 | char *ca_dir = MArgument_getUTF8String(Args[4]);
34 | char *crl_file = MArgument_getUTF8String(Args[5]);
35 | bool weak_cert = static_cast(MArgument_getInteger(Args[6]));
36 | bool inv_hostname = static_cast(MArgument_getInteger(Args[7]));
37 |
38 | mongoc_ssl_opt_t ssl_opts = {0};
39 |
40 | ssl_opts.weak_cert_validation = weak_cert;
41 | ssl_opts.allow_invalid_hostname = inv_hostname;
42 |
43 | // if string length is not zero, set values.
44 | if (strlen(pem_file) > 0)
45 | ssl_opts.pem_file = pem_file;
46 |
47 | if (strlen(pem_pwd) > 0)
48 | ssl_opts.pem_pwd = pem_pwd;
49 |
50 | if (strlen(ca_file) > 0)
51 | ssl_opts.ca_file = ca_file;
52 |
53 | if (strlen(ca_dir) > 0)
54 | ssl_opts.ca_dir = ca_dir;
55 |
56 | if (strlen(crl_file) > 0)
57 | ssl_opts.crl_file = crl_file;
58 |
59 | // Note: "As of 1.4.0, the mongoc_client_pool_set_ssl_opts() and
60 | // mongoc_client_set_ssl_opts() will not only shallow copy the struct, but
61 | // will also copy the const char*. It is therefore no longer needed to make
62 | // sure the values remain valid after setting them."
63 | // ~ http://mongoc.org/libmongoc/current/mongoc_ssl_opt_t.html
64 | mongoc_client_set_ssl_opts(client, &ssl_opts);
65 |
66 | // Free strings
67 | libData->UTF8String_disown(pem_file);
68 | libData->UTF8String_disown(pem_pwd);
69 | libData->UTF8String_disown(ca_file);
70 | libData->UTF8String_disown(ca_dir);
71 | libData->UTF8String_disown(crl_file);
72 |
73 | return LIBRARY_NO_ERROR;
74 | }
75 |
76 | EXTERN_C DLLEXPORT int WL_GetDatabaseNames(WolframLibraryData libData,
77 | MLINK mlp) {
78 | // Load database handle
79 | int client_handle;
80 | int len;
81 | if (!MLTestHead(mlp, "List", &len) || len != 1)
82 | return LIBRARY_FUNCTION_ERROR;
83 | if (!MLGetInteger(mlp, &client_handle))
84 | return LIBRARY_FUNCTION_ERROR;
85 | auto client = clientHandleMap[client_handle];
86 |
87 | // Create new output packet
88 | if (!MLNewPacket(mlp))
89 | return LIBRARY_FUNCTION_ERROR;
90 |
91 | // Get collection names
92 | bson_error_t error;
93 | char **strv;
94 | int length = 0;
95 | if ((strv =
96 | mongoc_client_get_database_names_with_opts(client, NULL, &error))) {
97 | for (int i = 0; strv[i]; i++) {
98 | ++length; // need to know length to initialize output list
99 | }
100 | } else {
101 | errorString = error.message;
102 | return LIBRARY_FUNCTION_ERROR;
103 | }
104 |
105 | // If success, loop over string array:
106 | if (!MLPutFunction(mlp, "List", length))
107 | return LIBRARY_FUNCTION_ERROR;
108 |
109 | for (int i = 0; i < length; i++)
110 | if (!MLPutString(mlp, strv[i]))
111 | return LIBRARY_FUNCTION_ERROR;
112 |
113 | // Free string array
114 | bson_strfreev(strv);
115 | // Return
116 | return LIBRARY_NO_ERROR;
117 | }
118 |
119 | EXTERN_C DLLEXPORT int WL_ClientGetCollection(WolframLibraryData libData,
120 | mint Argc, MArgument *Args,
121 | MArgument Res) {
122 | CLIENT_GET(client, 0)
123 | int collection_handle_key = MArgument_getInteger(Args[1]);
124 | char *databaseName = MArgument_getUTF8String(Args[2]);
125 | char *collectionName = MArgument_getUTF8String(Args[3]);
126 |
127 | // Create collection handle, append to collectionHandleMap if successfully
128 | // created.
129 | // API: http://api.mongodb.org/c/current/mongoc_client_get_collection.html
130 | auto collection =
131 | mongoc_client_get_collection(client, databaseName, collectionName);
132 |
133 | if (!collection) {
134 | errorString = "Cannot connect to collection.";
135 | return LIBRARY_FUNCTION_ERROR;
136 | }
137 | collectionHandleMap[collection_handle_key] = collection;
138 |
139 | // Disown strings
140 | libData->UTF8String_disown(databaseName);
141 | libData->UTF8String_disown(collectionName);
142 | return LIBRARY_NO_ERROR;
143 | }
144 |
145 | EXTERN_C DLLEXPORT int WL_ClientSimpleCommand(WolframLibraryData libData,
146 | mint Argc, MArgument *Args,
147 | MArgument Res) {
148 | CLIENT_GET(client, 0)
149 | BSON_GET(command, 1)
150 |
151 | const char *dbName = MArgument_getUTF8String(Args[2]);
152 | int bson_handle_key = MArgument_getInteger(Args[3]);
153 |
154 | bson_error_t error;
155 | bson_t reply;
156 | bool retval = mongoc_client_command_simple(client, dbName, command, NULL,
157 | &reply, &error);
158 | libData->UTF8String_disown(MArgument_getUTF8String(Args[2]));
159 |
160 | if (!retval) {
161 | errorString = error.message;
162 | return LIBRARY_FUNCTION_ERROR;
163 | }
164 | bsonHandleMap[bson_handle_key] = bson_copy(&reply);
165 | bson_destroy(&reply);
166 | return LIBRARY_NO_ERROR;
167 | }
168 |
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_collection.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // Collection-level functions
3 | // - For API guide, see:
4 | // http://mongoc.org/libmongoc/current/mongoc_collection_t.html
5 | ////////////////////////////////////////////////////////////////////////////////
6 |
7 | #include "wl_common.h"
8 |
9 | /*----------------------------------------------------------------------------*/
10 | // Collection handle creation
11 | EXTERN_C DLLEXPORT int WL_CollectionGetName(WolframLibraryData libData,
12 | mint Argc, MArgument *Args,
13 | MArgument Res) {
14 | COLLECTION_GET(collection, 0)
15 | // Set global returnString to name
16 | // Api: http://api.mongodb.org/c/current/mongoc_collection_get_name.html
17 | returnString = mongoc_collection_get_name(collection);
18 | // Return string
19 | MArgument_setUTF8String(Res, const_cast(returnString.c_str()));
20 | return LIBRARY_NO_ERROR;
21 | }
22 |
23 | EXTERN_C DLLEXPORT int WL_MongoCollectionCount(WolframLibraryData libData,
24 | mint Argc, MArgument *Args,
25 | MArgument Res) {
26 | COLLECTION_GET(collection, 0)
27 | BSON_GET(query, 1)
28 | BSON_GET(opts, 2)
29 |
30 | bson_error_t error;
31 | mint count = mongoc_collection_count_with_opts(collection, MONGOC_QUERY_NONE, query, 0,
32 | 0, opts, NULL, &error);
33 | // Error handling
34 | if (count < 0) {
35 | errorString = error.message;
36 | return LIBRARY_FUNCTION_ERROR;
37 | }
38 | MArgument_setInteger(Res, count);
39 | return LIBRARY_NO_ERROR;
40 | }
41 |
42 | EXTERN_C DLLEXPORT int WL_MongoCollectionFind(WolframLibraryData libData,
43 | mint Argc, MArgument *Args,
44 | MArgument Res) {
45 | COLLECTION_GET(collection, 0)
46 | BSON_GET(filter, 1)
47 | BSON_GET(opts, 2)
48 | mint outputCursorHandleKey = MArgument_getInteger(Args[3]);
49 |
50 | auto cursor =
51 | mongoc_collection_find_with_opts(collection, filter, opts, NULL);
52 | // Cursor can return Null if invalid parameters. Check
53 | if (!cursor) {
54 | errorString = "Unable to do perform query.";
55 | return LIBRARY_FUNCTION_ERROR;
56 | }
57 | // add cursor to map
58 | cursorHandleMap[outputCursorHandleKey] = cursor;
59 | return LIBRARY_NO_ERROR;
60 | }
61 |
62 | EXTERN_C DLLEXPORT int WL_MongoCollectionAggregation(WolframLibraryData libData,
63 | mint Argc, MArgument *Args,
64 | MArgument Res) {
65 | COLLECTION_GET(collection, 0)
66 | BSON_GET(pipeline, 1)
67 | BSON_GET(opts, 2)
68 | mint outputCursorHandleKey = MArgument_getInteger(Args[3]);
69 | // http://mongoc.org/libmongoc/current/mongoc_collection_aggregate.html
70 | mongoc_cursor_t *cursor = mongoc_collection_aggregate(
71 | collection, MONGOC_QUERY_NONE, pipeline, opts, NULL);
72 |
73 | // add cursor to map
74 | cursorHandleMap[outputCursorHandleKey] = cursor;
75 | return LIBRARY_NO_ERROR;
76 | }
77 |
78 | EXTERN_C DLLEXPORT int WL_MongoCollectionStats(WolframLibraryData libData,
79 | mint Argc, MArgument *Args,
80 | MArgument Res) {
81 | COLLECTION_GET(collection, 0)
82 | BSON_GET(opts, 1)
83 | mint reply_key = MArgument_getInteger(Args[2]);
84 |
85 | bson_t *reply = bson_new();
86 | bsonHandleMap[reply_key] = reply;
87 |
88 | // http://mongoc.org/libmongoc/current/mongoc_collection_stats.html
89 | bson_error_t error;
90 | bool result = mongoc_collection_stats(collection, opts, reply, &error);
91 |
92 | // Error handling
93 | if (!result) {
94 | std::cout << error.message << std::endl;
95 | errorString = error.message;
96 | return LIBRARY_FUNCTION_ERROR;
97 | }
98 |
99 | return LIBRARY_NO_ERROR;
100 | }
101 |
102 | EXTERN_C DLLEXPORT int WL_MongoCollectionDrop(WolframLibraryData libData,
103 | mint Argc, MArgument *Args,
104 | MArgument Res) {
105 | COLLECTION_GET(collection, 0)
106 | BSON_GET(opts, 1)
107 |
108 | // http://mongoc.org/libmongoc/current/mongoc_collection_drop_with_opts.html
109 | bson_error_t error;
110 | bool result = mongoc_collection_drop_with_opts(collection, opts, &error);
111 |
112 | // Error handling
113 | if (!result) {
114 | std::cout << error.message << std::endl;
115 | errorString = error.message;
116 | return LIBRARY_FUNCTION_ERROR;
117 | }
118 |
119 | return LIBRARY_NO_ERROR;
120 | }
121 |
122 | EXTERN_C DLLEXPORT int WL_MongoCollectionValidate(WolframLibraryData libData,
123 | mint Argc, MArgument *Args,
124 | MArgument Res) {
125 | COLLECTION_GET(collection, 0)
126 | BSON_GET(opts, 1)
127 | mint reply_key = MArgument_getInteger(Args[2]);
128 |
129 | bson_t *reply = bson_new();
130 | bsonHandleMap[reply_key] = reply;
131 |
132 | // http://mongoc.org/libmongoc/current/mongoc_collection_validate.html
133 | bson_error_t error;
134 | bool result = mongoc_collection_validate(collection, opts, reply, &error);
135 |
136 | // Error handling
137 | if (!result) {
138 | std::cout << error.message << std::endl;
139 | errorString = error.message;
140 | return LIBRARY_FUNCTION_ERROR;
141 | }
142 |
143 | return LIBRARY_NO_ERROR;
144 | }
145 |
146 | EXTERN_C DLLEXPORT int
147 | WL_MongoCollectionCommandSimple(WolframLibraryData libData, mint Argc,
148 | MArgument *Args, MArgument Res) {
149 | COLLECTION_GET(collection, 0)
150 | BSON_GET(command, 1)
151 | mint reply_key = MArgument_getInteger(Args[2]);
152 |
153 | bson_error_t error;
154 | bson_t reply;
155 | // http://mongoc.org/libmongoc/current/mongoc_collection_command_simple.html
156 | if (!mongoc_collection_command_simple(collection, command, NULL, &reply,
157 | &error)) {
158 | std::cout << error.message << std::endl;
159 | errorString = error.message;
160 | return LIBRARY_FUNCTION_ERROR;
161 | };
162 |
163 | // crashes without copy. Not sure why yet.
164 | bsonHandleMap[reply_key] = bson_copy(&reply);
165 | bson_destroy(&reply);
166 |
167 | return LIBRARY_NO_ERROR;
168 | }
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_common.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // All common functions + global variables live here
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | #include "wl_common.h"
6 |
7 | /*----------------------------------------------------------------------------*/
8 | // Global handle Map Variables
9 | std::map uriHandleMap;
10 | std::map clientHandleMap;
11 | std::map databaseHandleMap;
12 | std::map collectionHandleMap;
13 | std::map cursorHandleMap;
14 | std::map bulkOperationHandleMap;
15 | std::map writeConcernHandleMap;
16 | std::map bsonHandleMap;
17 |
18 | // Return string to store any returned strings outside of scope of functions
19 | char *returnCharArray = 0;
20 | char *returnBSONJSON = 0;
21 | std::string returnString = "";
22 | std::string errorString = "";
23 |
--------------------------------------------------------------------------------
/Libraries/MongoLink/wl_common.h:
--------------------------------------------------------------------------------
1 | #ifndef COMMON_H_INCLUDED
2 | #define COMMON_H_INCLUDED
3 |
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 | #include