├── .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 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "mathlink.h" 17 | #include "WolframLibrary.h" 18 | #include "WolframRawArrayLibrary.h" 19 | 20 | 21 | /*----------------------------------------------------------------------------*/ 22 | 23 | extern std::map uriHandleMap; 24 | extern std::map clientHandleMap; 25 | extern std::map databaseHandleMap; 26 | extern std::map collectionHandleMap; 27 | extern std::map cursorHandleMap; 28 | extern std::map bulkOperationHandleMap; 29 | extern std::map writeConcernHandleMap; 30 | extern std::map bsonHandleMap; 31 | 32 | extern char *returnCharArray; 33 | extern char *returnBSONJSON; // Used to parse bson to json. Special destructor 34 | extern std::string returnString; 35 | extern std::string errorString; 36 | 37 | #define URI_GET(var, key) \ 38 | mongoc_uri_t *var; \ 39 | if (uriHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 40 | return LIBRARY_FUNCTION_ERROR; \ 41 | } \ 42 | var = uriHandleMap[MArgument_getInteger(Args[key])]; 43 | 44 | #define CLIENT_GET(var, key) \ 45 | mongoc_client_t *var; \ 46 | if (clientHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 47 | return LIBRARY_FUNCTION_ERROR; \ 48 | } \ 49 | var = clientHandleMap[MArgument_getInteger(Args[key])]; 50 | 51 | #define DATABASE_GET(var, key) \ 52 | mongoc_database_t *var; \ 53 | if (databaseHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 54 | return LIBRARY_FUNCTION_ERROR; \ 55 | } \ 56 | var = databaseHandleMap[MArgument_getInteger(Args[key])]; 57 | 58 | #define COLLECTION_GET(var, key) \ 59 | mongoc_collection_t *var; \ 60 | if (collectionHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 61 | return LIBRARY_FUNCTION_ERROR; \ 62 | } \ 63 | var = collectionHandleMap[MArgument_getInteger(Args[key])]; 64 | 65 | #define CURSOR_GET(var, key) \ 66 | mongoc_cursor_t *var; \ 67 | if (cursorHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 68 | return LIBRARY_FUNCTION_ERROR; \ 69 | } \ 70 | var = cursorHandleMap[MArgument_getInteger(Args[key])]; 71 | 72 | #define BULK_OP_GET(var, key) \ 73 | mongoc_bulk_operation_t *var; \ 74 | if (bulkOperationHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 75 | return LIBRARY_FUNCTION_ERROR; \ 76 | } \ 77 | var = bulkOperationHandleMap[MArgument_getInteger(Args[key])]; 78 | 79 | #define BSON_GET(var, key) \ 80 | bson_t *var; \ 81 | if (bsonHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 82 | return LIBRARY_FUNCTION_ERROR; \ 83 | } \ 84 | var = bsonHandleMap[MArgument_getInteger(Args[key])]; 85 | 86 | // This macro is different from others: you often want this to be NULL to 87 | // inherit this option instead of specifying 88 | #define WRITE_CONCERN_GET(var, key) \ 89 | mongoc_write_concern_t *var; \ 90 | if (writeConcernHandleMap.count(MArgument_getInteger(Args[key])) == 0) { \ 91 | var = NULL; \ 92 | } else { \ 93 | var = writeConcernHandleMap[MArgument_getInteger(Args[key])]; \ 94 | } 95 | 96 | /*----------------------------------------------------------------------------*/ 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /Libraries/MongoLink/wl_cursor.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Cursor (Cursor) interface 3 | // - For API guide, see: 4 | // http://mongoc.org/libmongoc/current/mongoc_cursor_t.html 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "wl_common.h" 8 | 9 | /*----------------------------------------------------------------------------*/ 10 | 11 | EXTERN_C DLLEXPORT int WL_CursorNext(WolframLibraryData libData, mint Argc, 12 | MArgument *Args, MArgument Res) { 13 | CURSOR_GET(cursor, 0) 14 | int bson_handle_key = MArgument_getInteger(Args[1]); 15 | const bson_t *doc; 16 | // http://mongoc.org/libmongoc/current/mongoc_cursor_next.html 17 | bool has_next = mongoc_cursor_next(cursor, &doc); 18 | 19 | // handling according to http://mongoc.org/libmongoc/current/cursors.html 20 | bson_error_t error; 21 | if (mongoc_cursor_error(cursor, &error)) { 22 | errorString = error.message; 23 | return LIBRARY_FUNCTION_ERROR; 24 | } 25 | 26 | if (!has_next) { 27 | MArgument_setInteger(Res, 0); 28 | return LIBRARY_NO_ERROR; 29 | } 30 | 31 | // not efficient: fix this later! 32 | bsonHandleMap[bson_handle_key] = bson_copy(doc); 33 | MArgument_setInteger(Res, 1); 34 | return LIBRARY_NO_ERROR; 35 | } 36 | 37 | EXTERN_C DLLEXPORT int WL_CursorSetBatchSize(WolframLibraryData libData, 38 | mint Argc, MArgument *Args, 39 | MArgument Res) { 40 | CURSOR_GET(cursor, 0) 41 | uint32_t batch_size = MArgument_getInteger(Args[1]); 42 | // http://mongoc.org/libmongoc/current/mongoc_cursor_set_batch_size.html 43 | mongoc_cursor_set_batch_size(cursor, batch_size); 44 | return LIBRARY_NO_ERROR; 45 | } 46 | 47 | EXTERN_C DLLEXPORT int WL_CursorInfo(WolframLibraryData libData, mint Argc, 48 | MArgument *Args, MArgument Res) { 49 | CURSOR_GET(cursor, 0) 50 | mint type = MArgument_getInteger(Args[1]); 51 | mint out; 52 | switch (type) { 53 | case 1: 54 | out = mongoc_cursor_get_batch_size(cursor); 55 | break; 56 | case 2: 57 | out = mongoc_cursor_is_alive(cursor); 58 | break; 59 | case 3: 60 | out = mongoc_cursor_get_hint(cursor); 61 | break; 62 | case 4: 63 | out = mongoc_cursor_get_max_await_time_ms(cursor); 64 | break; 65 | case 5: 66 | out = mongoc_cursor_get_limit(cursor); 67 | break; 68 | } 69 | MArgument_setInteger(Res, out); 70 | return LIBRARY_NO_ERROR; 71 | } -------------------------------------------------------------------------------- /Libraries/MongoLink/wl_database.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Database-level functions 3 | // - For API guide, see: 4 | // http://mongoc.org/libmongoc/current/mongoc_database_t.html 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "wl_common.h" 8 | 9 | /*----------------------------------------------------------------------------*/ 10 | 11 | EXTERN_C DLLEXPORT int WL_DatabaseGetName(WolframLibraryData libData, mint Argc, 12 | MArgument *Args, MArgument Res) { 13 | auto database = databaseHandleMap[MArgument_getInteger(Args[0])]; 14 | // Set global returnString to name 15 | returnString = mongoc_database_get_name(database); 16 | MArgument_setUTF8String(Res, const_cast(returnString.c_str())); 17 | return LIBRARY_NO_ERROR; 18 | } 19 | 20 | EXTERN_C DLLEXPORT int WL_DatabaseHandleCreate(WolframLibraryData libData, 21 | mint Argc, MArgument *Args, 22 | MArgument Res) { 23 | int client_handle_key = MArgument_getInteger(Args[0]); 24 | int database_handle_key = MArgument_getInteger(Args[1]); 25 | char *databaseName = MArgument_getUTF8String(Args[2]); 26 | auto database = mongoc_client_get_database(clientHandleMap[client_handle_key], 27 | databaseName); 28 | if (!database) { 29 | errorString = "Cannot connect to database."; 30 | return LIBRARY_FUNCTION_ERROR; 31 | } 32 | databaseHandleMap[database_handle_key] = database; 33 | // Disown string 34 | libData->UTF8String_disown(databaseName); 35 | return LIBRARY_NO_ERROR; 36 | } 37 | 38 | EXTERN_C DLLEXPORT int WL_GetCollectionNames(WolframLibraryData libData, 39 | MLINK mlp) { 40 | // Load database handle 41 | int database_handle; 42 | int len; 43 | if (!MLTestHead(mlp, "List", &len) || len != 1) 44 | return LIBRARY_FUNCTION_ERROR; 45 | if (!MLGetInteger(mlp, &database_handle)) 46 | return LIBRARY_FUNCTION_ERROR; 47 | auto database = databaseHandleMap[database_handle]; 48 | // Create new output packet 49 | if (!MLNewPacket(mlp)) 50 | return LIBRARY_FUNCTION_ERROR; 51 | // Get collection names 52 | bson_error_t error; 53 | char **strv; 54 | int length = 0; 55 | if ((strv = mongoc_database_get_collection_names_with_opts(database, NULL, 56 | &error))) { 57 | for (int i = 0; strv[i]; i++) 58 | ++length; // need to know length to initialize output list 59 | } else { 60 | errorString = error.message; 61 | return LIBRARY_FUNCTION_ERROR; 62 | } 63 | // If success, loop over string array: 64 | if (!MLPutFunction(mlp, "List", length)) 65 | return LIBRARY_FUNCTION_ERROR; 66 | 67 | for (int i = 0; i < length; i++) 68 | if (!MLPutString(mlp, strv[i])) 69 | return LIBRARY_FUNCTION_ERROR; 70 | // Free string array 71 | bson_strfreev(strv); 72 | // Return 73 | return LIBRARY_NO_ERROR; 74 | } 75 | 76 | EXTERN_C DLLEXPORT int WL_DatabaseGetCollection(WolframLibraryData libData, 77 | mint Argc, MArgument *Args, 78 | MArgument Res) { 79 | auto database = databaseHandleMap[MArgument_getInteger(Args[0])]; 80 | int collection_handle_key = MArgument_getInteger(Args[1]); 81 | char *collectionName = MArgument_getUTF8String(Args[2]); 82 | // Create collection handle, append to collectionHandleMap if successfully 83 | // created. 84 | auto collection = mongoc_database_get_collection(database, collectionName); 85 | if (!collection) { 86 | errorString = "Cannot connect to collection."; 87 | return LIBRARY_FUNCTION_ERROR; 88 | } 89 | collectionHandleMap[collection_handle_key] = collection; 90 | // Disown strings 91 | libData->UTF8String_disown(collectionName); 92 | return LIBRARY_NO_ERROR; 93 | } 94 | 95 | //////////////////////////////////////////////////////////////////////////// 96 | EXTERN_C DLLEXPORT int WL_mongoc_database_drop(WolframLibraryData libData, 97 | mint Argc, MArgument *Args, 98 | MArgument Res) { 99 | 100 | bson_error_t error; 101 | DATABASE_GET(db, 0) 102 | auto res = mongoc_database_drop(db, &error); 103 | if (!res) { 104 | errorString = error.message; 105 | return LIBRARY_FUNCTION_ERROR; 106 | } 107 | return LIBRARY_NO_ERROR; 108 | } 109 | -------------------------------------------------------------------------------- /Libraries/MongoLink/wl_uri.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // URI Level Functions 3 | //////////////////////////////////////////////////////////////////////////////// 4 | 5 | #include "wl_common.h" 6 | 7 | /*----------------------------------------------------------------------------*/ 8 | 9 | EXTERN_C DLLEXPORT int WL_URICreate(WolframLibraryData libData, mint Argc, 10 | MArgument *Args, MArgument Res) { 11 | int uri_handle_key = MArgument_getInteger(Args[0]); 12 | char *uri_string = MArgument_getUTF8String(Args[1]); 13 | 14 | bson_error_t error; 15 | mongoc_uri_t *uri = mongoc_uri_new_with_error(uri_string, &error); 16 | if (!uri) { 17 | errorString = error.message; 18 | libData->UTF8String_disown(uri_string); 19 | return LIBRARY_FUNCTION_ERROR; 20 | } 21 | 22 | uriHandleMap[uri_handle_key] = uri; 23 | // Disown string 24 | libData->UTF8String_disown(uri_string); 25 | return LIBRARY_NO_ERROR; 26 | } 27 | 28 | EXTERN_C DLLEXPORT int WL_URISetOptionInt32(WolframLibraryData libData, 29 | mint Argc, MArgument *Args, 30 | MArgument Res) { 31 | URI_GET(uri, 0) 32 | char *name = MArgument_getUTF8String(Args[1]); 33 | int32_t value = MArgument_getInteger(Args[2]); 34 | bool res = mongoc_uri_set_option_as_int32(uri, name, value); 35 | // the mongo c driver seems to report invalid option values via logging, 36 | // but for some reason fails to report invalid options. Just fails. 37 | // so: logging writes to error string. If its empty, report error manually 38 | if (!res) { 39 | if (errorString.empty()) 40 | errorString = 41 | "Invalid option or value for \"" + std::string(name) + std::string("\""); 42 | libData->UTF8String_disown(name); 43 | return LIBRARY_FUNCTION_ERROR; 44 | } 45 | libData->UTF8String_disown(name); 46 | return LIBRARY_NO_ERROR; 47 | } 48 | 49 | EXTERN_C DLLEXPORT int WL_URISetOptionBool(WolframLibraryData libData, 50 | mint Argc, MArgument *Args, 51 | MArgument Res) { 52 | URI_GET(uri, 0) 53 | char *name = MArgument_getUTF8String(Args[1]); 54 | bool value = MArgument_getBoolean(Args[2]); 55 | bool res = mongoc_uri_set_option_as_bool(uri, name, value); 56 | // the mongo c driver seems to report invalid option values via logging, 57 | // but for some reason fails to report invalid options. Just fails. 58 | // so: logging writes to error string. If its empty, report error manually 59 | if (!res) { 60 | if (errorString.empty()) 61 | errorString = 62 | "Invalid option or value for \"" + std::string(name) + std::string("\""); 63 | libData->UTF8String_disown(name); 64 | return LIBRARY_FUNCTION_ERROR; 65 | } 66 | libData->UTF8String_disown(name); 67 | return LIBRARY_NO_ERROR; 68 | } 69 | 70 | EXTERN_C DLLEXPORT int WL_URISetOptionUTF8(WolframLibraryData libData, 71 | mint Argc, MArgument *Args, 72 | MArgument Res) { 73 | URI_GET(uri, 0) 74 | char *name = MArgument_getUTF8String(Args[1]); 75 | char *value = MArgument_getUTF8String(Args[2]); 76 | 77 | bool res = mongoc_uri_set_option_as_utf8(uri, name, value); 78 | libData->UTF8String_disown(value); 79 | // the mongo c driver seems to report invalid option values via logging, 80 | // but for some reason fails to report invalid options. Just fails. 81 | // so: logging writes to error string. If its empty, report error manually 82 | if (!res) { 83 | if (errorString.empty()) 84 | errorString = 85 | "Invalid option or value for \"" + std::string(name) + std::string("\""); 86 | libData->UTF8String_disown(name); 87 | return LIBRARY_FUNCTION_ERROR; 88 | } 89 | libData->UTF8String_disown(name); 90 | return LIBRARY_NO_ERROR; 91 | } 92 | 93 | EXTERN_C DLLEXPORT int WL_URIGetString(WolframLibraryData libData, mint Argc, 94 | MArgument *Args, MArgument Res) { 95 | URI_GET(uri, 0) 96 | 97 | auto temp = mongoc_uri_get_options(uri); 98 | MArgument_setUTF8String(Res, const_cast(mongoc_uri_get_string(uri))); 99 | return LIBRARY_NO_ERROR; 100 | } 101 | 102 | // put named option setters together 103 | EXTERN_C DLLEXPORT int WL_URISetPropEnum(WolframLibraryData libData, mint Argc, 104 | MArgument *Args, MArgument Res) { 105 | URI_GET(uri, 0) 106 | char *value = MArgument_getUTF8String(Args[1]); 107 | mint selector = MArgument_getInteger(Args[2]); 108 | bool res; 109 | switch (selector) { 110 | case 1: 111 | res = mongoc_uri_set_auth_mechanism(uri, value); 112 | break; 113 | case 2: 114 | res = mongoc_uri_set_auth_source(uri, value); 115 | break; 116 | case 3: 117 | res = mongoc_uri_set_compressors(uri, value); 118 | break; 119 | case 4: 120 | res = mongoc_uri_set_database(uri, value); 121 | break; 122 | case 5: 123 | res = mongoc_uri_set_password(uri, value); 124 | break; 125 | case 6: 126 | res = mongoc_uri_set_username(uri, value); 127 | break; 128 | } 129 | libData->UTF8String_disown(value); 130 | if (!res) 131 | return LIBRARY_FUNCTION_ERROR; 132 | return LIBRARY_NO_ERROR; 133 | } -------------------------------------------------------------------------------- /Libraries/MongoLink/wl_write_concern.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Write concern handler + functions 3 | // For API guide, see: 4 | // http://mongoc.org/libmongoc/current/mongoc_write_concern_t.html 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "wl_common.h" 8 | 9 | /*----------------------------------------------------------------------------*/ 10 | 11 | // Note: this creation was once done by manage_instance_mongowriteconcern. 12 | // However: you often need Null write concerns. This allows a key to be created 13 | // independently of initialization 14 | EXTERN_C DLLEXPORT int WL_WriteConcernNew(WolframLibraryData libData, mint Argc, 15 | MArgument *Args, MArgument Res) { 16 | int wc_handle_key = MArgument_getInteger(Args[0]); 17 | writeConcernHandleMap[wc_handle_key] = mongoc_write_concern_new(); 18 | return LIBRARY_NO_ERROR; 19 | } 20 | 21 | EXTERN_C DLLEXPORT int WL_WriteConcernSet(WolframLibraryData libData, mint Argc, 22 | MArgument *Args, MArgument Res) { 23 | WRITE_CONCERN_GET(wc, 0) 24 | int32_t w = MArgument_getInteger(Args[1]); 25 | mongoc_write_concern_set_w(wc, w); 26 | return LIBRARY_NO_ERROR; 27 | } 28 | 29 | EXTERN_C DLLEXPORT int WL_WriteConcernSetWtimeout(WolframLibraryData libData, 30 | mint Argc, MArgument *Args, 31 | MArgument Res) { 32 | WRITE_CONCERN_GET(wc, 0) 33 | int32_t wtimeout_msec = MArgument_getInteger(Args[1]); 34 | mongoc_write_concern_set_wtimeout(wc, wtimeout_msec); 35 | return LIBRARY_NO_ERROR; 36 | } 37 | 38 | EXTERN_C DLLEXPORT int WL_WriteConcernSetJournal(WolframLibraryData libData, 39 | mint Argc, MArgument *Args, 40 | MArgument Res) { 41 | WRITE_CONCERN_GET(wc, 0) 42 | bool journal = MArgument_getInteger(Args[1]); 43 | mongoc_write_concern_set_journal(wc, journal); 44 | return LIBRARY_NO_ERROR; 45 | } -------------------------------------------------------------------------------- /MongoLink/Documentation/English/ReferencePages/Symbols/$MongoDefaultCAFile.nb: -------------------------------------------------------------------------------- 1 | (* Content-type: application/vnd.wolfram.mathematica *) 2 | 3 | (*** Wolfram Notebook File ***) 4 | (* http://www.wolfram.com/nb *) 5 | 6 | (* CreatedBy='Mathematica 11.2' *) 7 | 8 | (*CacheID: 234*) 9 | (* Internal cache information: 10 | NotebookFileLineBreakTest 11 | NotebookFileLineBreakTest 12 | NotebookDataPosition[ 158, 7] 13 | NotebookDataLength[ 24023, 646] 14 | NotebookOptionsPosition[ 14461, 447] 15 | NotebookOutlinePosition[ 15665, 481] 16 | CellTagsIndexPosition[ 15586, 476] 17 | WindowFrame->Normal*) 18 | 19 | (* Beginning of Notebook Content *) 20 | Notebook[{ 21 | Cell[TextData[{ 22 | "New in: ", 23 | Cell["11.3", "HistoryData", 24 | CellTags->"New",ExpressionUUID->"76a595e1-e56c-4626-92cf-149d56297da7"], 25 | " | Modified in: ", 26 | Cell[" ", "HistoryData", 27 | CellTags->"Modified",ExpressionUUID->"a7bdea10-be01-4935-a52a-a3bb25334b6d"], 28 | " | Obsolete in: ", 29 | Cell[" ", "HistoryData", 30 | CellTags->"Obsolete",ExpressionUUID->"a6ad092f-e185-4473-b7d7-725d9cdbd6ba"], 31 | " | Excised in: ", 32 | Cell[" ", "HistoryData", 33 | CellTags->"Excised",ExpressionUUID->"c1c2912a-6d44-4194-9d78-5bd36e8a4c8e"] 34 | }], "History", 35 | CellID->341476719,ExpressionUUID->"4c39534f-12e3-425d-8358-c1165bd00135"], 36 | 37 | Cell["Created by: meghanr on 09-18-2017 12:43:04", "AuthorDate", 38 | CellID->986963868,ExpressionUUID->"b32fca3d-240f-4c37-a2ed-507a63b36058"], 39 | 40 | Cell[CellGroupData[{ 41 | 42 | Cell["Categorization", "CategorizationSection", 43 | CellID->1122911449,ExpressionUUID->"81bb45c3-7707-489b-bfeb-179be33578b6"], 44 | 45 | Cell["Symbol", "Categorization", 46 | CellLabel->"Entity Type", 47 | CellID->686433507,ExpressionUUID->"7d9a79dc-4c60-4c2a-be9c-8abe502256eb"], 48 | 49 | Cell["MongoLink", "Categorization", 50 | CellLabel->"Paclet Name", 51 | CellID->605800465,ExpressionUUID->"a546ccb5-bf87-4497-b638-38286add655a"], 52 | 53 | Cell["MongoLink`", "Categorization", 54 | CellLabel->"Context", 55 | CellID->468444828,ExpressionUUID->"b0b64563-1cf2-4741-bb60-835160078e25"], 56 | 57 | Cell["MongoLink/ref/$MongoDefaultCAFile", "Categorization", 58 | CellLabel->"URI",ExpressionUUID->"450c24d3-2908-4927-9ff9-b4b4949f0365"], 59 | 60 | Cell["XXXX", "Categorization", 61 | CellLabel->"Title Modifier", 62 | CellID->172747495,ExpressionUUID->"3b2c3dd8-e1d5-4868-a9da-c790628b3eff"] 63 | }, Open ]], 64 | 65 | Cell[CellGroupData[{ 66 | 67 | Cell["Synonyms", "SynonymsSection", 68 | CellID->1427418553,ExpressionUUID->"f2895175-386d-4f3e-8152-99b67d8d320e"], 69 | 70 | Cell["XXXX", "Synonyms", 71 | CellID->1251652828,ExpressionUUID->"f370f80d-a879-4c91-a2a6-e689caf40947"] 72 | }, Closed]], 73 | 74 | Cell[CellGroupData[{ 75 | 76 | Cell["Keywords", "KeywordsSection", 77 | CellID->477174294,ExpressionUUID->"93693360-26bc-4264-bef5-a1b6637f43ce"], 78 | 79 | Cell["XXXX", "Keywords", 80 | CellID->1164421360,ExpressionUUID->"3947d8a8-822a-4e0a-b56a-8778ca2bbe5b"] 81 | }, Closed]], 82 | 83 | Cell[CellGroupData[{ 84 | 85 | Cell["Syntax Templates", "TemplatesSection", 86 | CellID->1872225408,ExpressionUUID->"1ab58e59-4624-4134-8bba-61bb93eaf104"], 87 | 88 | Cell[BoxData[""], "Template", 89 | CellLabel->"Additional Function Template", 90 | CellID->1562036412,ExpressionUUID->"10a7f5d6-738f-4669-8145-4b29ee4366ba"], 91 | 92 | Cell[BoxData[""], "Template", 93 | CellLabel->"Arguments Pattern", 94 | CellID->158391909,ExpressionUUID->"bd656710-ec38-4ca5-9012-6edee69b005e"], 95 | 96 | Cell[BoxData[""], "Template", 97 | CellLabel->"Local Variables", 98 | CellID->1360575930,ExpressionUUID->"6eab3a02-fa39-4bf0-aafe-925b0643a2f0"], 99 | 100 | Cell[BoxData[""], "Template", 101 | CellLabel->"Color Equal Signs", 102 | CellID->793782254,ExpressionUUID->"531d5a60-00f7-4df5-9dca-326b3fd694fa"] 103 | }, Closed]], 104 | 105 | Cell[CellGroupData[{ 106 | 107 | Cell["Details", "DetailsSection", 108 | CellID->307771771,ExpressionUUID->"3b6713c4-d15d-4512-8a8b-1835a49f9985"], 109 | 110 | Cell["XXXX", "Details", 111 | CellLabel->"Lead", 112 | CellID->49458704,ExpressionUUID->"5f7dfdb3-6ae3-4af8-8df3-4ef5aa8f4273"], 113 | 114 | Cell["XXXX", "Details", 115 | CellLabel->"Developers", 116 | CellID->350963985,ExpressionUUID->"3fe21cc9-68b5-47ea-ae4b-60b381e37a47"], 117 | 118 | Cell["XXXX", "Details", 119 | CellLabel->"Authors", 120 | CellID->422270209,ExpressionUUID->"33909318-b334-462f-a9bb-57bb5fc024bf"], 121 | 122 | Cell["XXXX", "Details", 123 | CellLabel->"Feature Name", 124 | CellID->545239557,ExpressionUUID->"c3e28956-398d-47cd-95b8-bfb063334a49"], 125 | 126 | Cell["XXXX", "Details", 127 | CellLabel->"QA", 128 | CellID->121292707,ExpressionUUID->"78595dc0-6ca9-491d-b1bf-090e0e497e21"], 129 | 130 | Cell["XXXX", "Details", 131 | CellLabel->"DA", 132 | CellID->29314406,ExpressionUUID->"63368e38-43f1-435c-ac5f-ee5997becfb6"], 133 | 134 | Cell["XXXX", "Details", 135 | CellLabel->"Docs", 136 | CellID->96001539,ExpressionUUID->"29968311-b6cd-46c2-a2ef-53ff536d3377"], 137 | 138 | Cell["XXXX", "Details", 139 | CellLabel->"Features Page Notes", 140 | CellID->123278822,ExpressionUUID->"3f143d76-1a2f-43e5-8b64-96fbd19b2fb6"], 141 | 142 | Cell["XXXX", "Details", 143 | CellLabel->"Comments", 144 | CellID->240026365,ExpressionUUID->"c6553a77-bce7-4678-b6d4-b579c98bddf5"] 145 | }, Closed]], 146 | 147 | Cell[CellGroupData[{ 148 | 149 | Cell["Security Details", "SecuritySection", 150 | CellID->13551076,ExpressionUUID->"1739c236-b9b3-4b6f-b24e-11f17c92c21f"], 151 | 152 | Cell[BoxData[ 153 | TagBox[GridBox[{ 154 | { 155 | TemplateBox[{CheckboxBox[ 156 | Dynamic[ 157 | CurrentValue[ 158 | EvaluationNotebook[], {TaggingRules, "SecurityRisk"}, False]]], 159 | StyleBox[ 160 | "\" Potential security risk\"", FontFamily -> "Arial", FontSize -> 161 | 10, StripOnInput -> False]}, 162 | "RowDefault"]}, 163 | { 164 | DynamicBox[ToBoxes[ 165 | If[ 166 | TrueQ[ 167 | CurrentValue[ 168 | EvaluationNotebook[], {TaggingRules, "SecurityRisk"}]], 169 | InputField[ 170 | Dynamic[ 171 | CurrentValue[ 172 | EvaluationNotebook[], {TaggingRules, "SecurityExplanation"}, ""]], 173 | String, FieldHint -> "How so? (optional)", FieldSize -> {40, 5}, 174 | BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}], ""], 175 | StandardForm], 176 | ImageSizeCache->{0., {0., 5.}}]} 177 | }, 178 | DefaultBaseStyle->"Column", 179 | GridBoxAlignment->{"Columns" -> {{Left}}}, 180 | GridBoxItemSize->{"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}], 181 | "Column"]], "SecurityDetails", 182 | CellID->2488900,ExpressionUUID->"9ebf6961-82c7-4dd1-86d2-0ff6e90b5af2"] 183 | }, Closed]], 184 | 185 | Cell[CellGroupData[{ 186 | 187 | Cell["$MongoDefaultCAFile", "ObjectName", 188 | CellID->1224892054,ExpressionUUID->"cb1f3719-5099-454e-a903-56bbdc6d15d7"], 189 | 190 | Cell[TextData[{ 191 | Cell[" ", "ModInfo",ExpressionUUID->"3c044f71-7712-4131-9bdc-e945607df4e6"], 192 | Cell[BoxData[ 193 | ButtonBox["$MongoDefaultCAFile", 194 | BaseStyle->"Link", 195 | ButtonData->"paclet:MongoLink/ref/$MongoDefaultCAFile"]], "InlineFormula", 196 | ExpressionUUID->"aac06b63-7fba-441f-92bc-ce8ae41d1b34"], 197 | "\[LineSeparator]gives the default certificate authority file for use with \ 198 | MongoLink." 199 | }], "Usage", 200 | CellID->982511436,ExpressionUUID->"ef205339-dd32-4b2c-ba1e-f53ecb10eb6b"], 201 | 202 | Cell[TextData[{ 203 | "To use ", 204 | Cell[BoxData[ 205 | "$MongoDefaultCAFile"], "InlineFormula",ExpressionUUID-> 206 | "680e319f-27aa-442d-b1f0-fa33b55f7bad"], 207 | ", you first need to load ", 208 | StyleBox[ButtonBox["MongoLink", 209 | BaseStyle->"Link", 210 | ButtonData->"paclet:MongoLink/guide/MongoLinkOperations"], 211 | FontSlant->"Italic"], 212 | " using ", 213 | Cell[BoxData[ 214 | RowBox[{ 215 | ButtonBox["Needs", 216 | BaseStyle->"Link", 217 | ButtonData->"paclet:ref/Needs"], "[", "\"\\"", "]"}]], 218 | "InlineFormula",ExpressionUUID->"1c63d0ef-2bc2-41f9-8fd0-0d88150c1f2b"], 219 | "." 220 | }], "Notes", 221 | CellChangeTimes->{{3.723475765479208*^9, 3.723475794633397*^9}, { 222 | 3.723475886993636*^9, 3.723475899698312*^9}, 3.723475972858707*^9, { 223 | 3.723476009455484*^9, 3.7234760140215073`*^9}}, 224 | CellID->362132550,ExpressionUUID->"9c4f69b1-b3ec-4904-879d-e00e175e871f"], 225 | 226 | Cell[TextData[{ 227 | Cell[BoxData[ 228 | "$MongoDefaultCAFile"], "InlineFormula",ExpressionUUID-> 229 | "f219895c-927f-4004-a544-7e6ec438d851"], 230 | " is a ", 231 | Cell[BoxData[ 232 | RowBox[{ 233 | ButtonBox["File", 234 | BaseStyle->"Link"], "[", 235 | StyleBox["\[Ellipsis]", "TR"], "]"}]], "InlineFormula",ExpressionUUID-> 236 | "2926cd35-e44d-48c1-b8e4-a89983660e5f"], 237 | " object." 238 | }], "Notes", 239 | CellID->1067943069,ExpressionUUID->"139752cf-be2a-494b-8ad5-dbaa5e50ebf3"] 240 | }, Open ]], 241 | 242 | Cell[CellGroupData[{ 243 | 244 | Cell["Tutorials", "TutorialsSection", 245 | CellID->250839057,ExpressionUUID->"d1045354-c510-44f0-aa4f-e434df021ac7"], 246 | 247 | Cell[TextData[{ 248 | StyleBox[ButtonBox["MongoLink", 249 | BaseStyle->"Link", 250 | ButtonData->"paclet:MongoLink/tutorial/MongoLinkSimpleTutorial"], 251 | FontSlant->"Italic"], 252 | ButtonBox[" Introduction", 253 | BaseStyle->"Link", 254 | ButtonData->"paclet:MongoLink/tutorial/MongoLinkSimpleTutorial"] 255 | }], "Tutorials", 256 | CellChangeTimes->{{3.714756013832638*^9, 3.714756020359893*^9}, 257 | 3.7150013679246397`*^9, {3.723477029203116*^9, 3.7234770375897007`*^9}}, 258 | CellID->341631938,ExpressionUUID->"824ecf55-178a-4722-ae0a-01cd31def36e"] 259 | }, Open ]], 260 | 261 | Cell[CellGroupData[{ 262 | 263 | Cell["Related Demonstrations", "RelatedDemonstrationsSection", 264 | CellID->1268215905,ExpressionUUID->"bf2931ad-3669-4991-a340-5a3eb09d8a70"], 265 | 266 | Cell["XXXX", "RelatedDemonstrations", 267 | CellID->1129518860,ExpressionUUID->"91a812ee-86f9-4c16-8b90-78189b29cd4a"] 268 | }, Open ]], 269 | 270 | Cell[CellGroupData[{ 271 | 272 | Cell["Related Links", "RelatedLinksSection", 273 | CellID->1584193535,ExpressionUUID->"891576e2-ad80-42c4-badd-7e8df9547a58"], 274 | 275 | Cell["XXXX", "RelatedLinks", 276 | CellID->1038487239,ExpressionUUID->"fac4d1af-61c9-4d75-a1c1-93f85b557855"] 277 | }, Open ]], 278 | 279 | Cell[CellGroupData[{ 280 | 281 | Cell["See Also", "SeeAlsoSection", 282 | CellID->1255426704,ExpressionUUID->"059f51e2-c247-4ffd-ad6a-4f74e773090d"], 283 | 284 | Cell[TextData[Cell[BoxData[ 285 | ButtonBox["MongoConnect", 286 | BaseStyle->"Link", 287 | ButtonData-> 288 | "paclet:MongoLink/ref/MongoConnect"]], \ 289 | "InlineFormula",ExpressionUUID->"7d56b108-45c6-4153-9ef5-c6e04024518c"]], \ 290 | "SeeAlso", 291 | CellID->929782353,ExpressionUUID->"23f08ac2-50e1-465b-a46b-e9a90ef8c275"] 292 | }, Open ]], 293 | 294 | Cell[CellGroupData[{ 295 | 296 | Cell["More About", "MoreAboutSection", 297 | CellID->38303248,ExpressionUUID->"f8d8ecce-a16c-477d-bebb-5f158ec10d60"], 298 | 299 | Cell["Autogenerated", "MoreAbout", 300 | CellID->1665078683,ExpressionUUID->"b4e44f1f-32ff-4398-8e6a-c0fba8e05d1a"] 301 | }, Open ]], 302 | 303 | Cell[CellGroupData[{ 304 | 305 | Cell[BoxData[ 306 | InterpretationBox[GridBox[{ 307 | { 308 | StyleBox["Examples", "PrimaryExamplesSection"], 309 | ButtonBox[ 310 | RowBox[{ 311 | RowBox[{"More", " ", "Examples"}], " ", "\[RightTriangle]"}], 312 | BaseStyle->"ExtendedExamplesLink", 313 | ButtonData:>"ExtendedExamples"]} 314 | }], 315 | $Line = 0; Null]], "PrimaryExamplesSection", 316 | CellID->880084151,ExpressionUUID->"4a43eb50-bd07-4348-9e0b-877b5378dd07"], 317 | 318 | Cell[CellGroupData[{ 319 | 320 | Cell[BoxData[ 321 | InterpretationBox[Cell[ 322 | "\t", "ExampleDelimiter",ExpressionUUID-> 323 | "945926bd-ffa1-4d57-9332-fbf3d816027c"], 324 | $Line = 0; Null]], "ExampleDelimiter", 325 | CellID->18965431,ExpressionUUID->"ea2b29fe-5af5-46d9-b3a6-6e083f5fc0a0"], 326 | 327 | Cell[BoxData[ 328 | RowBox[{"Needs", "[", "\"\\"", "]"}]], "Input", 329 | CellLabel->"In[1]:=", 330 | CellID->886020810,ExpressionUUID->"78f1bfba-eb95-4ba0-b60d-ad4af1ee1852"], 331 | 332 | Cell["\<\ 333 | Return the default CA file included with the MongoLink paclet:\ 334 | \>", "ExampleText", 335 | CellID->2105064117,ExpressionUUID->"90bbbd00-beda-49b9-a01b-293ded23d636"], 336 | 337 | Cell[CellGroupData[{ 338 | 339 | Cell[BoxData["$MongoDefaultCAFile"], "Input", 340 | CellLabel->"In[2]:=", 341 | CellID->986325259,ExpressionUUID->"e66e2713-f8ac-49ae-927e-fb18883f1442"], 342 | 343 | Cell[BoxData[ 344 | RowBox[{"File", "[", 345 | TemplateBox[{ 346 | "\"/Applications/Mathematica.app/Contents/SystemFiles/Links/MongoLink/\ 347 | LibraryResources/MacOSX-x86-64/client.pem\""}, 348 | "FileArgument"], "]"}]], "Output", 349 | CellLabel->"Out[2]=", 350 | CellID->1948894761,ExpressionUUID->"c3c221de-693e-40fd-a0d4-4357d2213ece"] 351 | }, Open ]] 352 | }, Open ]] 353 | }, Open ]], 354 | 355 | Cell[CellGroupData[{ 356 | 357 | Cell["More Examples", "ExtendedExamplesSection", 358 | CellTags->"ExtendedExamples", 359 | CellID->1854448968,ExpressionUUID->"3214656e-7c6a-410b-96f4-283515690715"], 360 | 361 | Cell[BoxData[ 362 | InterpretationBox[Cell[ 363 | "Scope", "ExampleSection",ExpressionUUID-> 364 | "ed214b6e-6616-4cec-9322-676af2ce4b64"], 365 | $Line = 0; Null]], "ExampleSection", 366 | CellID->1293636265,ExpressionUUID->"3ee0fb02-f860-4e50-b69e-7463b49d4913"], 367 | 368 | Cell[BoxData[ 369 | InterpretationBox[Cell[ 370 | "Generalizations & Extensions", "ExampleSection",ExpressionUUID-> 371 | "1eb74540-735f-46a0-94b2-7de599785c84"], 372 | $Line = 0; Null]], "ExampleSection", 373 | CellID->1020263627,ExpressionUUID->"cf0b15a0-c3f5-4cc3-8614-f9b10e6a5bda"], 374 | 375 | Cell[BoxData[ 376 | InterpretationBox[Cell[ 377 | "Options", "ExampleSection",ExpressionUUID-> 378 | "406490ce-4803-46cb-a9e6-5207b1185dcb"], 379 | $Line = 0; Null]], "ExampleSection", 380 | CellID->2061341341,ExpressionUUID->"279ca1c7-992c-478f-96a6-878b4b9c0164"], 381 | 382 | Cell[BoxData[ 383 | InterpretationBox[Cell[ 384 | "Applications", "ExampleSection",ExpressionUUID-> 385 | "10a354bf-c84f-4fd9-b1c4-ab18bf5856b7"], 386 | $Line = 0; Null]], "ExampleSection", 387 | CellID->258228157,ExpressionUUID->"46d9b3b2-5095-422c-bcf7-fdbcc006b254"], 388 | 389 | Cell[BoxData[ 390 | InterpretationBox[Cell[ 391 | "Properties & Relations", "ExampleSection",ExpressionUUID-> 392 | "e0bbcfb9-61f8-4472-8f2d-4ea4d730ed84"], 393 | $Line = 0; Null]], "ExampleSection", 394 | CellID->2123667759,ExpressionUUID->"b27f3bb8-812a-4ac9-992f-f7aa228f4ef9"], 395 | 396 | Cell[BoxData[ 397 | InterpretationBox[Cell[ 398 | "Possible Issues", "ExampleSection",ExpressionUUID-> 399 | "f2be0cb8-ad3c-4362-b77a-29f249c19921"], 400 | $Line = 0; Null]], "ExampleSection", 401 | CellID->1305812373,ExpressionUUID->"8dc913f2-5ac9-4f64-8602-5419999e8e7d"], 402 | 403 | Cell[BoxData[ 404 | InterpretationBox[Cell[ 405 | "Interactive Examples", "ExampleSection",ExpressionUUID-> 406 | "9bd6b222-79d1-4cf3-8b7e-b68737521e36"], 407 | $Line = 0; Null]], "ExampleSection", 408 | CellID->1653164318,ExpressionUUID->"8cd4d9c5-92ea-46af-a759-a1c1c7af64f9"], 409 | 410 | Cell[BoxData[ 411 | InterpretationBox[Cell[ 412 | "Neat Examples", "ExampleSection",ExpressionUUID-> 413 | "ac84efcf-280d-464e-9bf6-38635341e01e"], 414 | $Line = 0; Null]], "ExampleSection", 415 | CellID->589267740,ExpressionUUID->"903c4c35-d297-4a8a-a595-57705492b670"] 416 | }, Open ]], 417 | 418 | Cell[CellGroupData[{ 419 | 420 | Cell["Design Discussion", "DesignDiscussionSection", 421 | CellID->1775809863,ExpressionUUID->"db46bf2e-cdab-4312-a8d2-e1a618ba80c6"], 422 | 423 | Cell["XXXX", "DesignDiscussion", 424 | CellID->308641435,ExpressionUUID->"c4ca42c8-e7b3-48b7-80c0-8f722dce446a"] 425 | }, Open ]], 426 | 427 | Cell[CellGroupData[{ 428 | 429 | Cell["Application Notes", "ApplicationNotesSection", 430 | CellID->1163590540,ExpressionUUID->"17b578bf-e8db-4ee6-b284-3f7997affae4"], 431 | 432 | Cell["XXXX", "ApplicationNotes", 433 | CellID->1480116198,ExpressionUUID->"ae59c15b-9b78-481b-89f3-7180b0743eed"] 434 | }, Open ]], 435 | 436 | Cell["Test Cases", "TestCasesSection", 437 | CellID->725748110,ExpressionUUID->"37b50f17-1a5f-48cb-b25c-b0706ea6823c"], 438 | 439 | Cell[CellGroupData[{ 440 | 441 | Cell["Function Essay", "FunctionEssaySection", 442 | CellID->37427227,ExpressionUUID->"1257ddcf-1c92-4e6c-aeb0-d59cf0e9e65f"], 443 | 444 | Cell["XXXX", "FunctionEssay", 445 | CellID->356990964,ExpressionUUID->"3bc1dcf4-6a8f-41fe-bafd-ed713c2b0a2c"] 446 | }, Open ]] 447 | }, 448 | ScreenStyleEnvironment->"ExperimentalObject", 449 | WindowSize->{1561, 998}, 450 | WindowMargins->{{Automatic, 313}, {Automatic, 73}}, 451 | TaggingRules->{ 452 | "DocuToolsSettingsInternal" -> { 453 | "$PacletVersion" -> "0.9.1871", "$MVersion" -> "11", "$FlaggedVersion" -> 454 | 10.4, "$ApplicationName" -> "Pubs", "$LinkBase" -> "Pubs", 455 | "$ApplicationDirectory" -> "C:\\Workspace\\Pubs\\", 456 | "$DocumentationDirectory" -> 457 | "C:\\Workspace\\Pubs\\Documentation\\English\\", "$UseNewPageDialog" -> 458 | ""}, "SecurityRisk" -> False, "SecurityExplanation" -> "", "Author" -> 459 | "meghanr", "CreationDate" -> "09-18-2017 12:43:04"}, 460 | FrontEndVersion->"11.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 24, \ 461 | 2017)", 462 | StyleDefinitions->FrontEnd`FileName[{"Wolfram"}, "FunctionPageStyles.nb", 463 | CharacterEncoding -> "UTF-8"] 464 | ] 465 | (* End of Notebook Content *) 466 | 467 | (* Internal cache information *) 468 | (*CellTagsOutline 469 | CellTagsIndex->{ 470 | "ExtendedExamples"->{ 471 | Cell[11319, 356, 155, 2, 56, "ExtendedExamplesSection",ExpressionUUID->"3214656e-7c6a-410b-96f4-283515690715", 472 | CellTags->"ExtendedExamples", 473 | CellID->1854448968]} 474 | } 475 | *) 476 | (*CellTagsIndex 477 | CellTagsIndex->{ 478 | {"ExtendedExamples", 15392, 469} 479 | } 480 | *) 481 | (*NotebookFileOutline 482 | Notebook[{ 483 | Cell[558, 20, 600, 14, 24, "History",ExpressionUUID->"4c39534f-12e3-425d-8358-c1165bd00135", 484 | CellID->341476719], 485 | Cell[1161, 36, 139, 1, 20, "AuthorDate",ExpressionUUID->"b32fca3d-240f-4c37-a2ed-507a63b36058", 486 | CellID->986963868], 487 | Cell[CellGroupData[{ 488 | Cell[1325, 41, 123, 1, 29, "CategorizationSection",ExpressionUUID->"81bb45c3-7707-489b-bfeb-179be33578b6", 489 | CellID->1122911449], 490 | Cell[1451, 44, 134, 2, 30, "Categorization",ExpressionUUID->"7d9a79dc-4c60-4c2a-be9c-8abe502256eb", 491 | CellID->686433507], 492 | Cell[1588, 48, 137, 2, 30, "Categorization",ExpressionUUID->"a546ccb5-bf87-4497-b638-38286add655a", 493 | CellID->605800465], 494 | Cell[1728, 52, 134, 2, 30, "Categorization",ExpressionUUID->"b0b64563-1cf2-4741-bb60-835160078e25", 495 | CellID->468444828], 496 | Cell[1865, 56, 133, 1, 30, "Categorization",ExpressionUUID->"450c24d3-2908-4927-9ff9-b4b4949f0365"], 497 | Cell[2001, 59, 135, 2, 30, "Categorization",ExpressionUUID->"3b2c3dd8-e1d5-4868-a9da-c790628b3eff", 498 | CellID->172747495] 499 | }, Open ]], 500 | Cell[CellGroupData[{ 501 | Cell[2173, 66, 111, 1, 29, "SynonymsSection",ExpressionUUID->"f2895175-386d-4f3e-8152-99b67d8d320e", 502 | CellID->1427418553], 503 | Cell[2287, 69, 100, 1, 70, "Synonyms",ExpressionUUID->"f370f80d-a879-4c91-a2a6-e689caf40947", 504 | CellID->1251652828] 505 | }, Closed]], 506 | Cell[CellGroupData[{ 507 | Cell[2424, 75, 110, 1, 19, "KeywordsSection",ExpressionUUID->"93693360-26bc-4264-bef5-a1b6637f43ce", 508 | CellID->477174294], 509 | Cell[2537, 78, 100, 1, 70, "Keywords",ExpressionUUID->"3947d8a8-822a-4e0a-b56a-8778ca2bbe5b", 510 | CellID->1164421360] 511 | }, Closed]], 512 | Cell[CellGroupData[{ 513 | Cell[2674, 84, 120, 1, 19, "TemplatesSection",ExpressionUUID->"1ab58e59-4624-4134-8bba-61bb93eaf104", 514 | CellID->1872225408], 515 | Cell[2797, 87, 149, 2, 70, "Template",ExpressionUUID->"10a7f5d6-738f-4669-8145-4b29ee4366ba", 516 | CellID->1562036412], 517 | Cell[2949, 91, 137, 2, 70, "Template",ExpressionUUID->"bd656710-ec38-4ca5-9012-6edee69b005e", 518 | CellID->158391909], 519 | Cell[3089, 95, 136, 2, 70, "Template",ExpressionUUID->"6eab3a02-fa39-4bf0-aafe-925b0643a2f0", 520 | CellID->1360575930], 521 | Cell[3228, 99, 137, 2, 70, "Template",ExpressionUUID->"531d5a60-00f7-4df5-9dca-326b3fd694fa", 522 | CellID->793782254] 523 | }, Closed]], 524 | Cell[CellGroupData[{ 525 | Cell[3402, 106, 108, 1, 19, "DetailsSection",ExpressionUUID->"3b6713c4-d15d-4512-8a8b-1835a49f9985", 526 | CellID->307771771], 527 | Cell[3513, 109, 117, 2, 70, "Details",ExpressionUUID->"5f7dfdb3-6ae3-4af8-8df3-4ef5aa8f4273", 528 | CellID->49458704], 529 | Cell[3633, 113, 124, 2, 70, "Details",ExpressionUUID->"3fe21cc9-68b5-47ea-ae4b-60b381e37a47", 530 | CellID->350963985], 531 | Cell[3760, 117, 121, 2, 70, "Details",ExpressionUUID->"33909318-b334-462f-a9bb-57bb5fc024bf", 532 | CellID->422270209], 533 | Cell[3884, 121, 126, 2, 70, "Details",ExpressionUUID->"c3e28956-398d-47cd-95b8-bfb063334a49", 534 | CellID->545239557], 535 | Cell[4013, 125, 116, 2, 70, "Details",ExpressionUUID->"78595dc0-6ca9-491d-b1bf-090e0e497e21", 536 | CellID->121292707], 537 | Cell[4132, 129, 115, 2, 70, "Details",ExpressionUUID->"63368e38-43f1-435c-ac5f-ee5997becfb6", 538 | CellID->29314406], 539 | Cell[4250, 133, 117, 2, 70, "Details",ExpressionUUID->"29968311-b6cd-46c2-a2ef-53ff536d3377", 540 | CellID->96001539], 541 | Cell[4370, 137, 133, 2, 70, "Details",ExpressionUUID->"3f143d76-1a2f-43e5-8b64-96fbd19b2fb6", 542 | CellID->123278822], 543 | Cell[4506, 141, 122, 2, 70, "Details",ExpressionUUID->"c6553a77-bce7-4678-b6d4-b579c98bddf5", 544 | CellID->240026365] 545 | }, Closed]], 546 | Cell[CellGroupData[{ 547 | Cell[4665, 148, 117, 1, 19, "SecuritySection",ExpressionUUID->"1739c236-b9b3-4b6f-b24e-11f17c92c21f", 548 | CellID->13551076], 549 | Cell[4785, 151, 1094, 30, 70, "SecurityDetails",ExpressionUUID->"9ebf6961-82c7-4dd1-86d2-0ff6e90b5af2", 550 | CellID->2488900] 551 | }, Closed]], 552 | Cell[CellGroupData[{ 553 | Cell[5916, 186, 117, 1, 63, "ObjectName",ExpressionUUID->"cb1f3719-5099-454e-a903-56bbdc6d15d7", 554 | CellID->1224892054], 555 | Cell[6036, 189, 482, 10, 78, "Usage",ExpressionUUID->"ef205339-dd32-4b2c-ba1e-f53ecb10eb6b", 556 | CellID->982511436], 557 | Cell[6521, 201, 826, 22, 28, "Notes",ExpressionUUID->"9c4f69b1-b3ec-4904-879d-e00e175e871f", 558 | CellID->362132550], 559 | Cell[7350, 225, 438, 13, 28, "Notes",ExpressionUUID->"139752cf-be2a-494b-8ad5-dbaa5e50ebf3", 560 | CellID->1067943069] 561 | }, Open ]], 562 | Cell[CellGroupData[{ 563 | Cell[7825, 243, 112, 1, 44, "TutorialsSection",ExpressionUUID->"d1045354-c510-44f0-aa4f-e434df021ac7", 564 | CellID->250839057], 565 | Cell[7940, 246, 511, 11, 16, "Tutorials",ExpressionUUID->"824ecf55-178a-4722-ae0a-01cd31def36e", 566 | CellID->341631938] 567 | }, Open ]], 568 | Cell[CellGroupData[{ 569 | Cell[8488, 262, 138, 1, 31, "RelatedDemonstrationsSection",ExpressionUUID->"bf2931ad-3669-4991-a340-5a3eb09d8a70", 570 | CellID->1268215905], 571 | Cell[8629, 265, 113, 1, 16, "RelatedDemonstrations",ExpressionUUID->"91a812ee-86f9-4c16-8b90-78189b29cd4a", 572 | CellID->1129518860] 573 | }, Open ]], 574 | Cell[CellGroupData[{ 575 | Cell[8779, 271, 120, 1, 31, "RelatedLinksSection",ExpressionUUID->"891576e2-ad80-42c4-badd-7e8df9547a58", 576 | CellID->1584193535], 577 | Cell[8902, 274, 104, 1, 16, "RelatedLinks",ExpressionUUID->"fac4d1af-61c9-4d75-a1c1-93f85b557855", 578 | CellID->1038487239] 579 | }, Open ]], 580 | Cell[CellGroupData[{ 581 | Cell[9043, 280, 110, 1, 31, "SeeAlsoSection",ExpressionUUID->"059f51e2-c247-4ffd-ad6a-4f74e773090d", 582 | CellID->1255426704], 583 | Cell[9156, 283, 296, 7, 22, "SeeAlso",ExpressionUUID->"23f08ac2-50e1-465b-a46b-e9a90ef8c275", 584 | CellID->929782353] 585 | }, Open ]], 586 | Cell[CellGroupData[{ 587 | Cell[9489, 295, 112, 1, 31, "MoreAboutSection",ExpressionUUID->"f8d8ecce-a16c-477d-bebb-5f158ec10d60", 588 | CellID->38303248], 589 | Cell[9604, 298, 110, 1, 16, "MoreAbout",ExpressionUUID->"b4e44f1f-32ff-4398-8e6a-c0fba8e05d1a", 590 | CellID->1665078683] 591 | }, Open ]], 592 | Cell[CellGroupData[{ 593 | Cell[9751, 304, 411, 11, 70, "PrimaryExamplesSection",ExpressionUUID->"4a43eb50-bd07-4348-9e0b-877b5378dd07", 594 | CellID->880084151], 595 | Cell[CellGroupData[{ 596 | Cell[10187, 319, 241, 5, 17, "ExampleDelimiter",ExpressionUUID->"ea2b29fe-5af5-46d9-b3a6-6e083f5fc0a0", 597 | CellID->18965431], 598 | Cell[10431, 326, 173, 3, 27, "Input",ExpressionUUID->"78f1bfba-eb95-4ba0-b60d-ad4af1ee1852", 599 | CellID->886020810], 600 | Cell[10607, 331, 169, 3, 22, "ExampleText",ExpressionUUID->"90bbbd00-beda-49b9-a01b-293ded23d636", 601 | CellID->2105064117], 602 | Cell[CellGroupData[{ 603 | Cell[10801, 338, 143, 2, 27, "Input",ExpressionUUID->"e66e2713-f8ac-49ae-927e-fb18883f1442", 604 | CellID->986325259], 605 | Cell[10947, 342, 311, 7, 48, "Output",ExpressionUUID->"c3c221de-693e-40fd-a0d4-4357d2213ece", 606 | CellID->1948894761] 607 | }, Open ]] 608 | }, Open ]] 609 | }, Open ]], 610 | Cell[CellGroupData[{ 611 | Cell[11319, 356, 155, 2, 56, "ExtendedExamplesSection",ExpressionUUID->"3214656e-7c6a-410b-96f4-283515690715", 612 | CellTags->"ExtendedExamples", 613 | CellID->1854448968], 614 | Cell[11477, 360, 242, 5, 33, "ExampleSection",ExpressionUUID->"3ee0fb02-f860-4e50-b69e-7463b49d4913", 615 | CellID->1293636265], 616 | Cell[11722, 367, 265, 5, 21, "ExampleSection",ExpressionUUID->"cf0b15a0-c3f5-4cc3-8614-f9b10e6a5bda", 617 | CellID->1020263627], 618 | Cell[11990, 374, 244, 5, 21, "ExampleSection",ExpressionUUID->"279ca1c7-992c-478f-96a6-878b4b9c0164", 619 | CellID->2061341341], 620 | Cell[12237, 381, 248, 5, 21, "ExampleSection",ExpressionUUID->"46d9b3b2-5095-422c-bcf7-fdbcc006b254", 621 | CellID->258228157], 622 | Cell[12488, 388, 259, 5, 21, "ExampleSection",ExpressionUUID->"b27f3bb8-812a-4ac9-992f-f7aa228f4ef9", 623 | CellID->2123667759], 624 | Cell[12750, 395, 252, 5, 21, "ExampleSection",ExpressionUUID->"8dc913f2-5ac9-4f64-8602-5419999e8e7d", 625 | CellID->1305812373], 626 | Cell[13005, 402, 257, 5, 21, "ExampleSection",ExpressionUUID->"8cd4d9c5-92ea-46af-a759-a1c1c7af64f9", 627 | CellID->1653164318], 628 | Cell[13265, 409, 249, 5, 21, "ExampleSection",ExpressionUUID->"903c4c35-d297-4a8a-a595-57705492b670", 629 | CellID->589267740] 630 | }, Open ]], 631 | Cell[CellGroupData[{ 632 | Cell[13551, 419, 128, 1, 79, "DesignDiscussionSection",ExpressionUUID->"db46bf2e-cdab-4312-a8d2-e1a618ba80c6", 633 | CellID->1775809863], 634 | Cell[13682, 422, 107, 1, 16, "DesignDiscussion",ExpressionUUID->"c4ca42c8-e7b3-48b7-80c0-8f722dce446a", 635 | CellID->308641435] 636 | }, Open ]], 637 | Cell[CellGroupData[{ 638 | Cell[13826, 428, 128, 1, 31, "ApplicationNotesSection",ExpressionUUID->"17b578bf-e8db-4ee6-b284-3f7997affae4", 639 | CellID->1163590540], 640 | Cell[13957, 431, 108, 1, 16, "ApplicationNotes",ExpressionUUID->"ae59c15b-9b78-481b-89f3-7180b0743eed", 641 | CellID->1480116198] 642 | }, Open ]], 643 | Cell[14080, 435, 113, 1, 31, "TestCasesSection",ExpressionUUID->"37b50f17-1a5f-48cb-b25c-b0706ea6823c", 644 | CellID->725748110], 645 | Cell[CellGroupData[{ 646 | Cell[14218, 440, 120, 1, 33, "FunctionEssaySection",ExpressionUUID->"1257ddcf-1c92-4e6c-aeb0-d59cf0e9e65f", 647 | CellID->37427227], 648 | Cell[14341, 443, 104, 1, 19, "FunctionEssay",ExpressionUUID->"3bc1dcf4-6a8f-41fe-bafd-ed713c2b0a2c", 649 | CellID->356990964] 650 | }, Open ]] 651 | } 652 | ] 653 | *) 654 | 655 | -------------------------------------------------------------------------------- /MongoLink/Kernel/ACommon.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Common: global variables plus common utility functions 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | (*----------------------------------------------------------------------------*) 12 | (* declare some common symbols, overloaded for different objects *) 13 | PackageScope["getMLE"] 14 | getMLE[___] := Panic["Invalid argument to getMLE"] 15 | 16 | PackageScope["getMLEID"] 17 | getMLEID[x_ /; ManagedLibraryExpressionQ[x]] := ManagedLibraryExpressionID[x] 18 | getMLEID[___] := Panic["Invalid argument to getMLEID"] 19 | 20 | PackageScope["getClient"] 21 | getClient[___] := Panic["Invalid argument to getClient"] 22 | 23 | (*----------------------------------------------------------------------------*) 24 | (****** Global Variables ******) 25 | 26 | $MongoLinkBaseDir = FileNameTake[$InputFileName, {1, -3}]; 27 | 28 | PackageScope["$LibraryResources"] 29 | $LibraryResources = FileNameJoin[{ 30 | ParentDirectory[DirectoryName @ $InputFileName], 31 | "LibraryResources", 32 | $SystemID 33 | }]; 34 | 35 | (* note: the build process puts the ca file into LibaryResources, but local paclet 36 | checkouts don't have this dir, and have the CA file in different place. Perhaps 37 | put in same place? *) 38 | PackageExport["$MongoDefaultCAFile"] 39 | $MongoDefaultCAFile := $MongoDefaultCAFile = Module[ 40 | {file1, file2}, 41 | file1 = FileNameJoin[{$MongoLinkBaseDir, "Kernel", "SSL", "client.pem"}]; 42 | file2 = FileNameJoin[{$LibraryResources, "client.pem"}]; 43 | If[FileExistsQ[file2], Return @ File[file2]]; 44 | If[FileExistsQ[file1], File[file1], $Failed] 45 | ] 46 | 47 | PackageScope["$MongoLinkLib"] 48 | 49 | $MongoLinkLib = Switch[$OperatingSystem, 50 | "MacOSX", 51 | FileNameJoin[{$LibraryResources, "MongoLink.dylib"}], 52 | "Windows", 53 | FileNameJoin[{$LibraryResources, "MongoLink.dll"}], 54 | "Unix", 55 | FileNameJoin[{$LibraryResources, "MongoLink.so"}] 56 | ] 57 | 58 | (* For windows: we need to explicitly load dependencies, not rely on autoloading *) 59 | If[$OperatingSystem === "Windows", 60 | LibraryLoad @ FileNameJoin[{$LibraryResources, "libbson-1.0.dll"}]; 61 | LibraryLoad @ FileNameJoin[{$LibraryResources, "libmongoc-1.0.dll"}]; 62 | ]; 63 | 64 | (***** Initialize Library *****) 65 | 66 | (* see http://mongoc.org/libmongoc/current/init-cleanup.html. We build with 67 | --disable-automatic-init-and-cleanup, as its deprecated, so we need to initialize 68 | ourselves. *) 69 | 70 | MongoInitialize = LibraryFunctionLoad[$MongoLinkLib, "WL_MongoInitialize", 71 | {}, 72 | "Void" 73 | ] 74 | 75 | (* this needs to be called precisely once in a session *) 76 | If[!ValueQ[$MongoInitialized], $MongoInitialized = False]; 77 | If[!TrueQ[$MongoInitialized], MongoInitialize[]; $MongoInitialized = True]; 78 | 79 | (*----------------------------------------------------------------------------*) 80 | PackageScope["MongoGetLastError"] 81 | 82 | MongoGetLastError = LibraryFunctionLoad[$MongoLinkLib, "WL_MongoGetLastError", 83 | {}, 84 | "UTF8String" 85 | ] 86 | 87 | PackageScope["MongoEraseLastError"] 88 | 89 | MongoEraseLastError = 90 | LibraryFunctionLoad[$MongoLinkLib, "WL_MongoEraseLastError", {}, Null] 91 | 92 | (*----------------------------------------------------------------------------*) 93 | PackageScope["LibraryFunctionFailureQ"] 94 | 95 | LibraryFunctionFailureQ[call_] := 96 | If[Head[call] === LibraryFunctionError, True, False] 97 | 98 | (*----------------------------------------------------------------------------*) 99 | General::mongolibuneval = "Library function `` with args `` did not evaluate."; 100 | 101 | PackageScope["safeLibraryInvoke"] 102 | 103 | safeLibraryInvoke[func_, args___] := 104 | Replace[ 105 | func[args], 106 | { 107 | _LibraryFunctionError :> MongoPanic[func], 108 | _LibraryFunction[___] :> ThrowFailure["mongolibuneval", func[[2]], {args}] 109 | } 110 | ]; 111 | 112 | General::mongoliberr = "C Function `` failed. Error from Mongo C Driver: \"``\""; 113 | 114 | MongoPanic[f_] := Module[ 115 | {lastError}, 116 | lastError = MongoGetLastError[]; 117 | MongoEraseLastError[]; 118 | If[TrueQ @ LibraryFunctionFailureQ[lastError], 119 | lastError = "Unknown Error"; 120 | ]; 121 | ThrowFailure["mongoliberr", f[[2]], lastError]; 122 | ] 123 | 124 | (*----------------------------------------------------------------------------*) 125 | (* Mongo Unix time is accurate to the millisecond *) 126 | 127 | PackageScope["FromMillisecondUnixTime"] 128 | 129 | FromMillisecondUnixTime[time_] := Module[ 130 | {dateList} 131 | , 132 | (* mongo servers use UTC format. TimeZone ensures this *) 133 | dateList = DateList @ FromUnixTime[time / 1000., TimeZone -> 0]; 134 | DateObject[dateList, DateFormat -> {"DateTime", ":", "Millisecond"}] 135 | ] 136 | 137 | PackageScope["ToMillisecondUnixTime"] 138 | 139 | ToMillisecondUnixTime[date_DateObject] := Module[ 140 | {sec}, 141 | sec = date["Second"]; 142 | If[MissingQ[sec], sec = 0]; 143 | 1000 * (UnixTime[date] + FractionalPart[sec]) 144 | ] 145 | 146 | (*----------------------------------------------------------------------------*) 147 | PackageScope["fileConform"] 148 | 149 | General::mongonff = "The file `` doesn't exist."; 150 | fileConform[file_String] := ( 151 | If[!FileExistsQ[file], 152 | ThrowFailure["mongonff", file]; 153 | ]; 154 | file 155 | ) 156 | 157 | fileConform[File[file_]] := fileConform[file] 158 | fileConform[None] := ""; 159 | 160 | General::mongoinvfile = "Object `` is not a String, File[...] or None." 161 | fileConform[file_] := ThrowFailure["mongonff", file]; 162 | 163 | (*----------------------------------------------------------------------------*) 164 | PackageScope["popAssociation"] 165 | 166 | SetAttributes[popAssociation, HoldFirst] 167 | popAssociation[assoc_, keys_] := Module[ 168 | {out}, 169 | out = Lookup[assoc, keys]; 170 | KeyDropFrom[assoc, keys]; 171 | out 172 | ] 173 | 174 | popAssociation[assoc_, keys_, default_] := Module[ 175 | {out}, 176 | out = Lookup[assoc, keys, default]; 177 | KeyDropFrom[assoc, keys]; 178 | out 179 | ] 180 | 181 | 182 | (*----------------------------------------------------------------------------*) 183 | (* opts process: will eventually do something more complicated, like lower-case 184 | first character to allow camel case opts 185 | *) 186 | 187 | PackageScope["processOpts"] 188 | 189 | processOpts[opts_Association, defaults_Association, changeRules_List] := Module[ 190 | {opts2}, 191 | opts2 = replaceAssociationKeys[opts, changeRules]; 192 | opts2 = KeyMap[Decapitalize, opts2]; 193 | Join[defaults, opts2] 194 | ] 195 | 196 | processOpts[opts_Association, defaults_Association] := 197 | processOpts[opts, defaults, {}] 198 | 199 | (* this can probably be done better *) 200 | replaceAssociationKeys[assoc_, rules_] := Module[ 201 | {old, new, look, keyPos}, 202 | If[Length[rules] === 0, Return[assoc]]; 203 | 204 | old = Keys[rules]; 205 | new = Values[rules]; 206 | look = Lookup[assoc, old]; 207 | keyPos = Flatten @ Position[look, Except[_Missing], 1, Heads->False]; 208 | KeyDrop[old] @ Join[assoc, AssociationThread[new[[keyPos]] -> look[[keyPos]]]] 209 | ] 210 | 211 | PackageScope["optsToBSON"] 212 | optsToBSON[opts_Association, defaults_Association, changeRules_List] := Module[ 213 | {opts2}, 214 | opts2 = processOpts[opts, defaults, changeRules]; 215 | iToBSON[opts2] 216 | ] 217 | 218 | optsToBSON[opts_Association, defaults_Association] := 219 | optsToBSON[opts, defaults, {}] 220 | 221 | optsToBSON[opts_Association] := 222 | optsToBSON[opts, <||>, {}] 223 | 224 | (*----------------------------------------------------------------------------*) 225 | (* This function converts a number of WL inputs to a Mongo millisecond time format 226 | Note: there cannot be a 0 time in mongo, so 0 is infinity 227 | *) 228 | 229 | PackageScope["timeToMilliseconds"] 230 | timeToMilliseconds[x_Integer] := x 231 | timeToMilliseconds[Infinity] := 0 232 | timeToMilliseconds[x_Quantity] := QuantityMagnitude @ UnitConvert[x, "Milliseconds"] 233 | timeToMilliseconds[x_] := x 234 | 235 | -------------------------------------------------------------------------------- /MongoLink/Kernel/BSON.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | BSON: create BSON objects from either JSON or associations 4 | 5 | Note: BSON is independent of MongoDB, so don't prepend name MongoBSON. Rather, 6 | use name BSONObject. 7 | 8 | *******************************************************************************) 9 | 10 | Package["MongoLink`"] 11 | 12 | PackageImport["GeneralUtilities`"] 13 | 14 | PackageScope["bsonMLE"] (* bson ManagedLibraryExpression *) 15 | 16 | (*----------------------------------------------------------------------------*) 17 | (****** Load Library Functions ******) 18 | 19 | createBSONfromJSON = LibraryFunctionLoad[$MongoLinkLib, "WL_CreateBSONfromJSON", 20 | { 21 | Integer, (* bson handle *) 22 | "UTF8String" (* json *) 23 | }, 24 | "Void" 25 | ] 26 | 27 | bsonAsJSON = LibraryFunctionLoad[$MongoLinkLib, "WL_bsonAsJSON", 28 | { 29 | Integer, (* bson handle *) 30 | True|False (* relaxed json true/false *) 31 | 32 | }, 33 | "UTF8String" (* json *) 34 | ] 35 | 36 | rawarrayToBSON = LibraryFunctionLoad[$MongoLinkLib, "WL_raw_array_to_bson", 37 | { 38 | Integer, (* bson handle *) 39 | {"RawArray", "Constant"} (* raw array *) 40 | 41 | }, 42 | "Void" 43 | ] 44 | 45 | bsonAsRawArray = LibraryFunctionLoad[$MongoLinkLib, "WL_bson_to_rawarray", 46 | { 47 | Integer (* bson handle *) 48 | 49 | }, 50 | "RawArray" 51 | ] 52 | 53 | parseBSON = LibraryFunctionLoad[$MongoLinkLib, "WL_ParseBSON", 54 | Automatic, 55 | LinkObject 56 | ] 57 | 58 | bsonGetBSONKey = LibraryFunctionLoad[$MongoLinkLib, "WL_get_bson_key", 59 | { 60 | Integer, (* bson handle *) 61 | Integer, (* return bson *) 62 | "UTF8String" (* key *) 63 | 64 | }, 65 | Integer 66 | ] 67 | 68 | (*----------------------------------------------------------------------------*) 69 | PackageExport["BSONObject"] 70 | 71 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 72 | formatted display box *) 73 | DefineCustomBoxes[BSONObject, 74 | e:BSONObject[bsonMLE_] :> Block[{}, 75 | BoxForm`ArrangeSummaryBox[ 76 | BSONObject, e, None, 77 | { 78 | BoxForm`SummaryItem[{"ID: ", getMLEID[bsonMLE]}] 79 | }, 80 | {}, 81 | StandardForm 82 | ] 83 | ]]; 84 | 85 | getMLE[BSONObject[bsonMLE_]] := bsonMLE; 86 | getMLEID[BSONObject[bsonMLE_]] := ManagedLibraryExpressionID[bsonMLE]; 87 | 88 | BSONObject /: ByteArray[bson_BSONObject] := BSONToByteArray[bson] 89 | BSONObject /: Normal[bson_BSONObject] := BSONToAssociation[bson] 90 | 91 | (*----------------------------------------------------------------------------*) 92 | (* conversion funcs *) 93 | 94 | PackageExport["BSONToRawArray"] 95 | BSONToRawArray[BSONObject[id_]] := 96 | safeLibraryInvoke[bsonAsRawArray, getMLEID[id]] 97 | 98 | PackageExport["BSONToByteArray"] 99 | BSONToByteArray[bson_BSONObject] := 100 | ByteArray[Normal @ BSONToRawArray[bson]] 101 | 102 | (*----------------------------------------------------------------------------*) 103 | PackageExport["BSONToJSON"] 104 | 105 | Options[BSONToJSON] = { 106 | "Relaxed" -> False 107 | }; 108 | 109 | BSONToJSON::invrelaxed = "Value for option \"Relaxed\" must be boolean, but `` was given."; 110 | 111 | BSONToJSON[BSONObject[id_], opts:OptionsPattern[]] := CatchFailureAsMessage @ Module[ 112 | {relaxed = OptionValue["Relaxed"]}, 113 | If[!BooleanQ[relaxed], ThrowFailure[BSONToJSON::invrelaxed, relaxed]]; 114 | safeLibraryInvoke[bsonAsJSON, getMLEID[id], relaxed] 115 | ] 116 | 117 | (*----------------------------------------------------------------------------*) 118 | PackageExport["BSONToAssociation"] 119 | 120 | BSONToAssociation[x_BSONObject] := CatchFailureAsMessage @ iBSONToAssociation[x] 121 | 122 | iBSONToAssociation[bson_BSONObject] := safeLibraryInvoke[parseBSON, getMLEID[bson]] 123 | iBSONToAssociation[x:{__BSONObject}] := iBSONToAssociation /@ x 124 | 125 | iBSONToAssociation::invarg = "Invalid argument." 126 | iBSONToAssociation[___] := ThrowFailure[iBSONToAssociation::invarg] 127 | 128 | (*----------------------------------------------------------------------------*) 129 | PackageExport["ToBSON"] 130 | PackageScope["iToBSON"] 131 | 132 | General::tobsoninvjson = "iToBSON failed: Expression `` cannot be exported as JSON."; 133 | General::tobsoninvtype = 134 | "iToBSON failed: Argument must be a String, Association, List, or NumericArray."; 135 | General::tobsoninvnatype = 136 | "iToBSON failed: NumericArray has type ``, but must have type UnsignedInteger8."; 137 | 138 | iToBSON[doc_Association] := Module[ 139 | {json}, 140 | 141 | (* capture message *) 142 | myMessageList = {}; 143 | Internal`InheritedBlock[{Message, $InMsg = False}, 144 | Unprotect[Message]; 145 | Message[msg_, vars___] /; ! $InMsg := 146 | Block[{$InMsg = True}, 147 | AppendTo[myMessageList, {HoldForm[msg], vars}]; 148 | Message[msg, vars] 149 | ]; 150 | (*code to run*) 151 | json = Quiet @ Developer`WriteRawJSONString[doc, 152 | "Compact" -> True, 153 | "ConversionRules" -> $EncodingRules 154 | ]; 155 | ]; 156 | If[FailureQ[json], 157 | ThrowFailure["tobsoninvjson", myMessageList[[1, 2]]]; 158 | ]; 159 | iToBSON[json] 160 | ] 161 | 162 | (* assumes doc is json *) 163 | iToBSON[doc_String] := Module[ 164 | {bsonHandle}, 165 | bsonHandle = CreateManagedLibraryExpression["BSON", bsonMLE]; 166 | safeLibraryInvoke[createBSONfromJSON, getMLEID[bsonHandle], doc]; 167 | BSONObject[bsonHandle] 168 | ] 169 | 170 | iToBSON[doc: (_RawArray | _NumericArray)] := Module[ 171 | {bsonHandle, type}, 172 | type = Developer`RawArrayType[doc]; 173 | If[type =!= "UnsignedInteger8", 174 | ThrowFailure["tobsoninvnatype", type] 175 | ]; 176 | bsonHandle = CreateManagedLibraryExpression["BSON", bsonMLE]; 177 | safeLibraryInvoke[rawarrayToBSON, getMLEID[bsonHandle], doc]; 178 | BSONObject[bsonHandle] 179 | ] 180 | 181 | iToBSON[doc_ByteArray] := iToBSON[RawArray["UnsignedInteger8", Normal[doc]]] 182 | 183 | iToBSON[doc_] := ThrowFailure["tobsoninvtype"] 184 | 185 | iToBSON[doc_BSONObject] := doc (* idempotency *) 186 | 187 | ToBSON[doc_] := CatchFailureAsMessage @ iToBSON[doc]; 188 | 189 | (*----------------------------------------------------------------------------*) 190 | PackageScope["bsonLookup"] 191 | 192 | bsonLookup[bson_BSONObject, key_String] := Module[ 193 | {bsonOut, res}, 194 | bsonOut = CreateManagedLibraryExpression["BSON", bsonMLE]; 195 | res = safeLibraryInvoke[bsonGetBSONKey, getMLEID[bson], getMLEID[bsonOut], key]; 196 | If[res === 0, Return @ Missing["KeyAbsent", key]]; 197 | Lookup[BSONToAssociation[BSONObject[bsonOut]], key] 198 | ] 199 | 200 | (*----------------------------------------------------------------------------*) 201 | (*********** BSON Types *************) 202 | (* see https://docs.mongodb.com/manual/reference/mongodb-extended-json/ *) 203 | (* This is also useful: 204 | https://github.com/mongodb/specifications/blob/master/source/extended-json.rst 205 | *) 206 | (* Many of these types are not supported yet. *) 207 | 208 | (* Note: json converter already handles True, False, Null *) 209 | 210 | $EncodingRules = { 211 | DirectedInfinity[1] :> <|"$maxKey" -> 1|>, 212 | DirectedInfinity[-1] :> <|"$minKey" -> 1|>, 213 | (* for binary data 00 is the recommended default type for drivers, 214 | see http://bsonspec.org/spec.html *) 215 | x_ByteArray :> <|"$binary" -> <| 216 | "base64" -> Developer`EncodeBase64[x], 217 | "subType" -> "00" 218 | |>|>, 219 | x_DateObject :> <|"$date" -> Round @ ToMillisecondUnixTime[x]|>, 220 | BSONObjectID[x_] :> <|"$oid" -> x|>, 221 | BSONTimestamp[time_, inc_] :> <|"$timestamp" -> <|"t" -> time, "i" -> inc|>|>, 222 | BSONDBReference[coll_, id_] :> <|"$ref" -> coll, "$id" -> First[id]|>, 223 | BSONDecimal128[x_] :> <|"$numberDecimal" -> x|> 224 | }; 225 | 226 | (*----- ObjectID -------*) 227 | PackageExport["BSONObjectID"] 228 | 229 | BSONObjectID /: Normal[BSONObjectID[hex_String]] := Dataset @ <| 230 | "GenerationTime" -> 231 | FromUnixTime @ Interpreter["HexInteger"][StringTake[hex, {1, 8}]], 232 | "MachineID" -> Interpreter["HexInteger"][StringTake[hex, {9, 14}]], 233 | "ProcessID" -> Interpreter["HexInteger"][StringTake[hex, {15, 18}]], 234 | "Counter" -> Interpreter["HexInteger"][StringTake[hex, {19, -1}]] 235 | |>; 236 | 237 | DefineCustomBoxes[BSONObjectID, 238 | e:BSONObjectID[id_] :> Block[{}, 239 | BoxForm`ArrangeSummaryBox[ 240 | BSONObjectID, e, None, 241 | { 242 | BoxForm`SummaryItem[{"OID: ", id}] 243 | }, 244 | {}, 245 | StandardForm 246 | ] 247 | ]]; 248 | 249 | (*----- Timestamp -------*) 250 | PackageExport["BSONTimestamp"] 251 | 252 | DefineCustomBoxes[BSONTimestamp, 253 | e:BSONTimestamp[time_, inc_] :> Block[{}, 254 | BoxForm`ArrangeSummaryBox[ 255 | BSONObjectID, e, None, 256 | { 257 | BoxForm`SummaryItem[{"Time: ", time}], 258 | BoxForm`SummaryItem[{"Increment: ", inc}] 259 | }, 260 | {}, 261 | StandardForm 262 | ] 263 | ]]; 264 | 265 | (*----- Decimal128 -------*) 266 | PackageExport["BSONDecimal128"] 267 | 268 | (* check that number is not more precise than Decimal128 can handle *) 269 | BSONDecimal128::invnum = "Number is too `` for Decimal128."; 270 | 271 | (* There is probably a faster way to do this *) 272 | safeDecimal128[num_] := Module[ 273 | { 274 | str = RealDigitsString[num, 34], 275 | val 276 | }, 277 | val = If[Positive[num], "large", "small"]; 278 | If[Last[MantissaExponent[num, 10]] > 34, ThrowFailure[BSONDecimal128::invnum, val]]; 279 | BSONDecimal128[str] 280 | ] 281 | 282 | BSONDecimal128 /: Normal[BSONDecimal128[num_String]] := ToExpression[num] 283 | 284 | DefineCustomBoxes[BSONDecimal128, 285 | e:BSONDecimal128[num_String] :> Block[{}, 286 | BoxForm`ArrangeSummaryBox[ 287 | BSONDecimal128, e, None, 288 | { 289 | BoxForm`SummaryItem[{"Value: ", num}] 290 | }, 291 | {}, 292 | StandardForm 293 | ] 294 | ]]; 295 | 296 | BSONDecimal128[num_Real] := CatchFailureAsMessage @ safeDecimal128[num] 297 | BSONDecimal128[num_Integer] := BSONDecimal128[N[num]] 298 | 299 | (*----- DB Reference -------*) 300 | (* 301 | Strict: { "$oid": "" } 302 | Shell: ObjectId( "" ) 303 | *) 304 | PackageExport["BSONDBReference"] 305 | 306 | BSONDBReference /: Normal[BSONDBReference[coll_, oid_]] := <| 307 | "Collection" -> coll, 308 | "ObjectID" -> oid 309 | |>; 310 | 311 | (* display form *) 312 | DefineCustomBoxes[BSONDBReference, 313 | e:BSONDBReference[coll_, id_] :> Block[{}, 314 | BoxForm`ArrangeSummaryBox[ 315 | BSONDBReference, e, None, 316 | { 317 | BoxForm`SummaryItem[{"OID: ", id}], 318 | BoxForm`SummaryItem[{"Collection: ", coll}] 319 | }, 320 | {}, 321 | StandardForm 322 | ] 323 | ]]; 324 | 325 | -------------------------------------------------------------------------------- /MongoLink/Kernel/BulkOp.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Database level functions 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | PackageScope["bulkopMLE"] (* bulkop ManagedLibraryExpression *) 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | createBulkOpFromCollection = LibraryFunctionLoad[$MongoLinkLib, "WL_CreateBulkOpFromCollection", 17 | { 18 | Integer, (* bulkop handle *) 19 | Integer, (* collection handle *) 20 | Integer, (* write concern handle *) 21 | True|False (* ordered *) 22 | 23 | }, 24 | True|False (* authenticated *) 25 | ] 26 | 27 | bulkOpExecuteLL = LibraryFunctionLoad[$MongoLinkLib, "WL_BulkOpExecute", 28 | { 29 | Integer, (* bulkop handle *) 30 | Integer (* reply bson handle *) 31 | 32 | }, 33 | "Void" 34 | ] 35 | 36 | bulkOpUpdate = LibraryFunctionLoad[$MongoLinkLib, "WL_mongoc_bulk_operation_update", 37 | { 38 | Integer, (* bulkop handle *) 39 | Integer, (* selector bson handle *) 40 | Integer, (* doc bson handle *) 41 | Integer, (* opts bson handle *) 42 | True|False (* many or one *) 43 | }, 44 | "Void" 45 | ] 46 | 47 | bulkOpInsert = LibraryFunctionLoad[$MongoLinkLib, "WL_mongoc_bulk_operation_insert", 48 | { 49 | Integer, (* bulkop handle *) 50 | Integer, (* opts bson handle *) 51 | {Integer, 1, "Constant"} (* doc bson handles *) 52 | }, 53 | "Void" 54 | ] 55 | 56 | bulkOpRemove = LibraryFunctionLoad[$MongoLinkLib, "WL_mongoc_bulk_operation_remove", 57 | { 58 | Integer, (* bulkop handle *) 59 | Integer, (* selector bson handle *) 60 | Integer, (* opts bson handle *) 61 | True|False (* many or one *) 62 | }, 63 | "Void" 64 | ] 65 | 66 | bulkOpReplaceOne = LibraryFunctionLoad[$MongoLinkLib, "WL_mongoc_bulk_operation_replace_one", 67 | { 68 | Integer, (* bulkop handle *) 69 | Integer, (* selector bson handle *) 70 | Integer, (* doc bson handle *) 71 | Integer (* opts bson handle *) 72 | }, 73 | "Void" 74 | ] 75 | 76 | (*----------------------------------------------------------------------------*) 77 | General::mongoinvordered = 78 | "The option \"Ordered\" was ``, but must be either True or False."; 79 | General::mongoinvwriteconcern = 80 | "The option \"WriteConcern\" was ``, but must be a MongoWriteConcern or Automatic."; 81 | General::mongoinvupsert = 82 | "The option \"Upsert\" was ``, but must be either True or False."; 83 | 84 | (*----------------------------------------------------------------------------*) 85 | createBulkOperation[coll_MongoCollection, wc_, ordered_] := Module[ 86 | {wcNew, bulkOp, res}, 87 | If[!BooleanQ[ordered], 88 | ThrowFailure["mongoinvordered", ordered] 89 | ]; 90 | If[Not[(Head[wc] === MongoWriteConcern) || (wc === Automatic)], 91 | ThrowFailure["mongoinvwriteconcern", wc]; 92 | ]; 93 | wcNew = Replace[wc, 94 | Automatic :> CreateManagedLibraryExpression["WriteConcern", writeConcernMLE]]; 95 | 96 | bulkOp = CreateManagedLibraryExpression["BulkOp", bulkopMLE]; 97 | res = safeLibraryInvoke[createBulkOpFromCollection, 98 | getMLEID[bulkOp], 99 | getMLEID[coll], 100 | getMLEID[wcNew], 101 | ordered 102 | ]; 103 | {res, bulkOp} 104 | ] 105 | 106 | (*----------------------------------------------------------------------------*) 107 | 108 | bulkOpExecute[bulk_bulkopMLE] := Module[ 109 | {reply}, 110 | reply = CreateManagedLibraryExpression["BSON", bsonMLE]; 111 | safeLibraryInvoke[bulkOpExecuteLL, getMLEID[bulk], getMLEID[reply]]; 112 | Normal[BSONObject[reply]] 113 | ] 114 | 115 | (*----------------------------------------------------------------------------*) 116 | PackageExport["MongoInsertResult"] 117 | 118 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 119 | formatted display box *) 120 | DefineCustomBoxes[MongoInsertResult, 121 | e:MongoInsertResult[res_Association] :> Block[{}, 122 | BoxForm`ArrangeSummaryBox[ 123 | MongoInsertResult, e, None, 124 | { 125 | BoxForm`SummaryItem[{"InsertedCount: ", Lookup[res, "InsertedCount"]}], 126 | BoxForm`SummaryItem[{"Acknowledged: ", Lookup[res, "Acknowledged"]}] 127 | }, 128 | {}, 129 | StandardForm 130 | ] 131 | ]]; 132 | 133 | MongoInsertResult[res_]["InsertedCount"] := Lookup[res, "InsertedCount"] 134 | MongoInsertResult[res_]["InsertedCount"] := Lookup[res, "InsertedCount"] 135 | MongoInsertResult[res_]["Acknowledged"] := Lookup[res, "Acknowledged"] 136 | MongoInsertResult[res_]["InsertedIDs"] := Lookup[res, "InsertedIDs"] 137 | MongoInsertResult[res_][___] := $Failed 138 | 139 | MongoInsertResult /: Normal[MongoInsertResult[x_Association]] := x 140 | 141 | (*----------------------------------------------------------------------------*) 142 | (* Insertion: Note that the Mongo spec supports three different insert ops: 143 | insert, insertOne, insertMany. PyMongo deprecated insert, and recommends 144 | only insertOne and insertMany. We will follow the API of insertMany, 145 | and call it MongoCollectionInsert. 146 | *) 147 | 148 | PackageExport["MongoCollectionInsert"] 149 | 150 | Options[MongoCollectionInsert] = { 151 | "WriteConcern" -> Automatic, 152 | "Ordered" -> True 153 | }; 154 | 155 | MongoCollectionInsert[coll_MongoCollection, doc_, opts:OptionsPattern[]] := 156 | CatchFailureAsMessage @ Module[ 157 | {wc, ordered}, 158 | (** parse options **) 159 | {wc, ordered} = OptionValue[{"WriteConcern", "Ordered"}]; 160 | iMongoCollectionInsert[coll, doc, wc, ordered] 161 | ] 162 | 163 | iMongoCollectionInsert[ 164 | collection_MongoCollection, docs:{__BSONObject}, wc_, ordered_] := Module[ 165 | {keyNames, auth, bulk, optsBSON}, 166 | {auth, bulk} = createBulkOperation[collection, wc, ordered]; 167 | (* no opts yet *) 168 | optsBSON = ToBSON[<||>]; 169 | (* insert docs into bulk executor. Mutates docs to have _id field!! *) 170 | safeLibraryInvoke[bulkOpInsert, 171 | getMLEID[bulk], 172 | getMLEID[optsBSON], 173 | getMLEID /@ docs 174 | ]; 175 | (* execute bulk. reply not used in insert *) 176 | bulkOpExecute[bulk]; 177 | keyNames = bsonLookup[#, "_id"]& /@ docs; 178 | System`Private`SetNoEntry @ MongoInsertResult @ <| 179 | "Acknowledged" -> auth, 180 | "InsertedIDs" -> keyNames, 181 | "InsertedCount" -> Length[keyNames] 182 | |> 183 | ] 184 | 185 | iMongoCollectionInsert[coll_MongoCollection, doc_BSONObject, wc_, ordered_] := 186 | iMongoCollectionInsert[coll, {doc}, wc, ordered] 187 | 188 | iMongoCollectionInsert[coll_MongoCollection, doc_Association|doc_String, wc_, ordered_] := 189 | iMongoCollectionInsert[coll, {iToBSON[doc]}, wc, ordered] 190 | 191 | iMongoCollectionInsert[coll_MongoCollection, doc_List, wc_, ordered_] := 192 | iMongoCollectionInsert[coll, iToBSON /@ doc, wc, ordered] 193 | 194 | MongoCollectionInsert::invtype = 195 | "Document to be inserted must be an Association, JSON String or BSONObject, or a list of these."; 196 | iMongoCollectionInsert[coll_MongoCollection, doc_, wc_, ordered_] := 197 | ThrowFailure[MongoCollectionInsert::invtype]; 198 | 199 | (*----------------------------------------------------------------------------*) 200 | PackageExport["MongoCollectionReplaceOne"] 201 | 202 | Options[MongoCollectionReplaceOne] = { 203 | "WriteConcern" -> Automatic, 204 | "Upsert" -> False 205 | }; 206 | 207 | MongoCollectionReplaceOne[coll_MongoCollection, filter_Association, replacement_Association, opts:OptionsPattern[]] := 208 | CatchFailureAsMessage @ Module[ 209 | { 210 | wc, upsert, auth, bulk, optsBSON, 211 | filterBSON = iToBSON[filter], 212 | replacementBSON = iToBSON[replacement], 213 | reply 214 | }, 215 | (** parse options **) 216 | {wc, upsert} = OptionValue[{"WriteConcern", "Upsert"}]; 217 | If[!BooleanQ[upsert], ThrowFailure["mongoinvupsert", upsert]]; 218 | (* create bulk op *) 219 | {auth, bulk} = createBulkOperation[coll, wc, True]; 220 | optsBSON = ToBSON[<|"upsert" -> upsert|>]; 221 | safeLibraryInvoke[bulkOpReplaceOne, 222 | getMLEID[bulk], 223 | getMLEID[filterBSON], 224 | getMLEID[replacementBSON], 225 | getMLEID[optsBSON] 226 | ]; 227 | (* execute the bulk op *) 228 | reply = bulkOpExecute[bulk]; 229 | <| 230 | "Acknowledged" -> auth, 231 | "MatchedCount" -> reply["nMatched"], 232 | "ModifiedCount" -> reply["nModified"] 233 | |> 234 | ] 235 | 236 | (*----------------------------------------------------------------------------*) 237 | PackageExport["MongoCollectionUpdateOne"] 238 | PackageExport["MongoCollectionUpdateMany"] 239 | 240 | (*** update one ***) 241 | Options[MongoCollectionUpdateOne] = { 242 | "WriteConcern" -> Automatic, 243 | "Upsert" -> False 244 | }; 245 | 246 | MongoCollectionUpdateOne[coll_MongoCollection, filter_Association, update_Association, opts:OptionsPattern[]] := 247 | CatchFailureAsMessage[ 248 | iMongoCollectionUpdate[coll, filter, update, OptionValue["WriteConcern"], OptionValue["Upsert"], False] 249 | ] 250 | 251 | (*** update many ***) 252 | Options[MongoCollectionUpdateMany] = { 253 | "WriteConcern" -> Automatic, 254 | "Upsert" -> False 255 | }; 256 | 257 | MongoCollectionUpdateMany[coll_MongoCollection, filter_Association, update_Association, opts:OptionsPattern[]] := 258 | CatchFailureAsMessage[ 259 | iMongoCollectionUpdate[coll, filter, update, OptionValue["WriteConcern"], OptionValue["Upsert"], True] 260 | ] 261 | 262 | (*** dual implementation ***) 263 | iMongoCollectionUpdate[coll_, filter_, update_, wc_, upsert_, many_] := Module[ 264 | { 265 | auth, bulk, optsBSON, 266 | filterBSON = iToBSON[filter], 267 | updateBSON = iToBSON[update], 268 | reply 269 | }, 270 | If[!BooleanQ[upsert], ThrowFailure["mongoinvupsert", upsert]]; 271 | (* create bulk op *) 272 | {auth, bulk} = createBulkOperation[coll, wc, True]; 273 | optsBSON = ToBSON[<|"upsert" -> upsert|>]; 274 | safeLibraryInvoke[bulkOpUpdate, 275 | getMLEID[bulk], 276 | getMLEID[filterBSON], 277 | getMLEID[updateBSON], 278 | getMLEID[optsBSON], 279 | many 280 | ]; 281 | (* execute the bulk op *) 282 | reply = bulkOpExecute[bulk]; 283 | <| 284 | "Acknowledged" -> auth, 285 | "MatchedCount" -> reply["nMatched"], 286 | "ModifiedCount" -> reply["nModified"] 287 | |> 288 | ] 289 | 290 | (*----------------------------------------------------------------------------*) 291 | PackageExport["MongoCollectionDeleteOne"] 292 | PackageExport["MongoCollectionDeleteMany"] 293 | 294 | (*** update one ***) 295 | Options[MongoCollectionDeleteOne] = { 296 | "WriteConcern" -> Automatic 297 | }; 298 | 299 | MongoCollectionDeleteOne[coll_MongoCollection, filter_Association, opts:OptionsPattern[]] := 300 | CatchFailureAsMessage[ 301 | iMongoCollectionDelete[coll, filter, OptionValue["WriteConcern"], False] 302 | ] 303 | 304 | (*** update many ***) 305 | Options[MongoCollectionDeleteMany] = { 306 | "WriteConcern" -> Automatic 307 | }; 308 | 309 | MongoCollectionDeleteMany[coll_MongoCollection, filter_Association, opts:OptionsPattern[]] := 310 | CatchFailureAsMessage[ 311 | iMongoCollectionDelete[coll, filter, OptionValue["WriteConcern"], True] 312 | ] 313 | 314 | (*** dual implementation ***) 315 | iMongoCollectionDelete[coll_, filter_, wc_, many_] := Module[ 316 | { 317 | auth, bulk, optsBSON, 318 | filterBSON = iToBSON[filter], 319 | reply 320 | }, 321 | (* create bulk op *) 322 | {auth, bulk} = createBulkOperation[coll, wc, True]; 323 | optsBSON = ToBSON[<||>]; 324 | safeLibraryInvoke[bulkOpRemove, 325 | getMLEID[bulk], 326 | getMLEID[filterBSON], 327 | getMLEID[optsBSON], 328 | many 329 | ]; 330 | (* execute the bulk op *) 331 | reply = bulkOpExecute[bulk]; 332 | <| 333 | "Acknowledged" -> auth, 334 | "DeletedCount" -> reply["nRemoved"] 335 | |> 336 | ] 337 | -------------------------------------------------------------------------------- /MongoLink/Kernel/Client.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Client level functions 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | PackageScope["clientMLE"] (* client ManagedLibraryExpression *) 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | clientHandleCreate = LibraryFunctionLoad[$MongoLinkLib, "WL_ClientHandleCreate", 17 | { 18 | Integer, (* client handle *) 19 | Integer (* uri handle *) 20 | }, 21 | "Void" 22 | ] 23 | 24 | clientSetSSL = LibraryFunctionLoad[$MongoLinkLib, "WL_ClientSetSSL", 25 | { 26 | Integer, (* handle key *) 27 | "UTF8String", (* pem_file *) 28 | "UTF8String", (* pem_pwd *) 29 | "UTF8String", (* ca_file *) 30 | "UTF8String", (* ca_dir *) 31 | "UTF8String", (* crl_file *) 32 | True|False, (* weak cert validation *) 33 | True|False (* inv hostname *) 34 | }, 35 | "Void" 36 | ] 37 | 38 | getDatabaseNames = LibraryFunctionLoad[$MongoLinkLib, "WL_GetDatabaseNames", 39 | Automatic, LinkObject 40 | ] 41 | 42 | clientSimpleCommand = LibraryFunctionLoad[$MongoLinkLib, "WL_ClientSimpleCommand", 43 | { 44 | Integer, (* client handle *) 45 | Integer, (* command bson *) 46 | "UTF8String", (* json *) 47 | Integer (* out bson *) 48 | }, 49 | "Void" 50 | ] 51 | 52 | (*----------------------------------------------------------------------------*) 53 | PackageExport["MongoClient"] 54 | 55 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 56 | formatted display box *) 57 | DefineCustomBoxes[MongoClient, 58 | e:MongoClient[clientMLE_] :> Block[{}, 59 | BoxForm`ArrangeSummaryBox[ 60 | MongoClient, e, None, 61 | {BoxForm`SummaryItem[{"ID: ", getMLEID[clientMLE]}]}, 62 | {}, 63 | StandardForm 64 | ] 65 | ]]; 66 | 67 | getMLE[MongoClient[clientMLE_]] := clientMLE; 68 | getMLEID[MongoClient[clientMLE_]] := ManagedLibraryExpressionID[clientMLE]; 69 | 70 | MongoClient[clientMLE_][db_String] := 71 | MongoGetDatabase[MongoClient[clientMLE], db] 72 | 73 | MongoClient[clientMLE_][db_String, coll_String] := 74 | CatchFailureAsMessage @ 75 | MongoGetCollection[iMongoGetDatabase[MongoClient[clientMLE], db], coll] 76 | 77 | MongoClient /: Length[c_MongoClient] := Module[ 78 | {names = MongoGetDatabaseNames[c]}, 79 | If[FailureQ[names], Return[names]]; 80 | Length[names] 81 | ] 82 | 83 | MongoClient /: Keys[c_MongoClient] := MongoGetDatabaseNames[c] 84 | 85 | (*----------------------------------------------------------------------------*) 86 | PackageExport["MongoConnect"] 87 | 88 | (* Note: we over-ride the default values of the C driver for socketTimeoutMS, 89 | which is around 5 minutes. This can cause problems for long operations. 90 | We follow the official default of no timeout, which is also PyMongo defualt: 91 | https://docs.mongodb.com/manual/reference/connection-string/#connection-options 92 | *) 93 | 94 | $DefaultConnection = <| 95 | "port" -> 27017, 96 | "host" -> "localhost", 97 | "sockettimeoutms" -> -1, (* follow pymongo, never timeout *) 98 | "connecttimeoutms" -> 20000, (* follow pymongo *) 99 | "journal" -> True (* this is NOT default in pymongo. Seems safer though... *) 100 | |>; 101 | 102 | DeclareArgumentCount[MongoConnect, {0, 1}]; 103 | MongoConnect[connection_Association] := CatchFailureAsMessage @ Module[ 104 | { 105 | replaceRules, con, uri, clientID, result, 106 | clientHandle = CreateManagedLibraryExpression["Client", clientMLE], 107 | password, username, cred, 108 | ssl, pemFile, caFile, crList, pemFilePassword, verifyCert, test 109 | }, 110 | (* conform WL names to native mongo names *) 111 | replaceRules = { 112 | VerifySecurityCertificates -> "sslallowinvalidcertificates", 113 | "AllowInvalidHostname" -> "sslallowinvalidhostnames", 114 | "CAFile" -> "sslcertificateauthorityfile", 115 | "PEMFile" -> "sslclientcertificatekeyfile", 116 | "PEMFilePassword" -> "sslclientcertificatekeypassword" 117 | }; 118 | con = processOpts[connection, $DefaultConnection, replaceRules]; 119 | 120 | (* special handling for passwords *) 121 | {password, username} = Lookup[con, {"password", "username"}, None]; 122 | If[password === "$Prompt", 123 | cred = AuthenticationDialog["UsernamePassword" -> {"Username" -> username}]; 124 | If[Head[cred] =!= Association, 125 | Message[OpenMongoConnection::authcancel]; 126 | Return[$Failed] 127 | ]; 128 | {username, password} = Lookup[cred, {"Username", "Password"}]; 129 | con = Join[con, <|"password" -> password, "username" -> username|>]; 130 | ]; 131 | 132 | (* pop ssl opts: handle separately *) 133 | ssl = popAssociation[con, "ssl", Automatic]; 134 | verifyCert = popAssociation[con, "sslallowinvalidcertificates", True]; 135 | invHost = popAssociation[con, "sslallowinvalidhostnames", False]; 136 | {pemFile, caFile, crList} = fileConform /@ 137 | popAssociation[con, 138 | {"sslclientcertificatekeyfile", "sslcertificateauthorityfile", "certificaterevocationlist"}, 139 | None 140 | ]; 141 | pemFilePassword = popAssociation[con, "sslclientcertificatekeypassword", ""]; 142 | 143 | (* construct URI *) 144 | uri = uriConstruct[con]; 145 | 146 | clientID = getMLEID[clientHandle]; 147 | result = safeLibraryInvoke[clientHandleCreate, clientID, getMLEID[uri]]; 148 | 149 | (***** SSL Opts ******) 150 | (* See http://mongoc.org/libmongoc/current/mongoc_ssl_opt_t.html for 151 | this issue *) 152 | If[($OperatingSystem === "Windows") && (pemFilePassword =!= ""), 153 | Message[MongoConnect::winpem]; 154 | Return[$Failed] 155 | ]; 156 | If[(ssl =!= False) && ((pemFile =!= "") || (caFile =!= "") || (crList =!= "")), 157 | safeLibraryInvoke[clientSetSSL, 158 | clientID, 159 | pemFile, 160 | pemFilePassword, 161 | caFile, 162 | "", (* ca_dir: not going to support *) 163 | crList, 164 | verifyCert, 165 | invHost 166 | ] 167 | ]; 168 | 169 | (* check whether connected *) 170 | test = 171 | mongoClientCommandSimple[MongoClient[clientHandle], <|"ping" -> 1|>, "admin"]; 172 | If[!AssociationQ[test], Return@$Failed]; 173 | If[Round@Lookup[test, "ok", Return[$Failed]] =!= 1, Return[$Failed]]; 174 | 175 | (* return client object *) 176 | System`Private`SetNoEntry @ MongoClient[clientHandle] 177 | 178 | ] 179 | 180 | (* conformization *) 181 | MongoConnect[] := MongoConnect[<||>] 182 | MongoConnect[uri_String] := MongoConnect[<|"host" -> uri|>] 183 | MongoConnect[MongoURI[uri_, _]] := MongoConnect[<|"host" -> uri|>] 184 | 185 | MongoConnect::invargs = "MongoConnect expects either a String or an Association, `` was given." 186 | MongoConnect[x_] := (Message[MongoConnect::invargs, x]; $Failed) 187 | 188 | 189 | (*----------------------------------------------------------------------------*) 190 | PackageExport["MongoGetDatabaseNames"] 191 | 192 | SetUsage[MongoGetDatabaseNames, 193 | "MongoGetDatabaseNames[MongoClient[$$]] returns a list of databases on the \ 194 | connected server. 195 | " 196 | ] 197 | 198 | MongoGetDatabaseNames[client_MongoClient] := 199 | CatchFailureAsMessage @ safeLibraryInvoke[getDatabaseNames, getMLEID[client]] 200 | 201 | DeclareArgumentCount[MongoGetDatabaseNames, 1]; 202 | MongoGetDatabaseNames::invargs = 203 | "MongoGetDatabaseNames expects a MongoClient object, but `` was given." 204 | MongoGetDatabaseNames[x_] := (Message[MongoGetDatabaseNames::invargs, x]; $Failed) 205 | 206 | (*----------------------------------------------------------------------------*) 207 | PackageScope["mongoClientCommandSimple"] 208 | 209 | mongoClientCommandSimple[client_MongoClient, command_, database_] := Module[ 210 | {comBSON = iToBSON[command], outBSON}, 211 | outBSON = CreateManagedLibraryExpression["BSON", bsonMLE]; 212 | safeLibraryInvoke[ 213 | clientSimpleCommand, 214 | getMLEID[client], 215 | getMLEID[comBSON], 216 | database, 217 | getMLEID[outBSON] 218 | ]; 219 | BSONToAssociation @ BSONObject[outBSON] 220 | ] 221 | -------------------------------------------------------------------------------- /MongoLink/Kernel/Collection.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | Collection level-functions 3 | 4 | *******************************************************************************) 5 | 6 | Package["MongoLink`"] 7 | 8 | PackageImport["GeneralUtilities`"] 9 | 10 | PackageScope["collectionMLE"] (* collection ManagedLibraryExpression *) 11 | 12 | (*----------------------------------------------------------------------------*) 13 | (****** Load Library Functions ******) 14 | 15 | clientGetCollection = LibraryFunctionLoad[$MongoLinkLib, 16 | "WL_ClientGetCollection", 17 | { 18 | Integer, (* client handle *) 19 | Integer, (* collection handle *) 20 | "UTF8String", (* database name *) 21 | "UTF8String" (* collection name *) 22 | 23 | }, 24 | "Void" 25 | ] 26 | 27 | databaseGetCollection = LibraryFunctionLoad[$MongoLinkLib, 28 | "WL_DatabaseGetCollection", 29 | { 30 | Integer, (* database handle *) 31 | Integer, (* collection handle *) 32 | "UTF8String" (* collection name *) 33 | 34 | }, 35 | "Void" 36 | ] 37 | 38 | mongoCollectionCount = LibraryFunctionLoad[$MongoLinkLib, 39 | "WL_MongoCollectionCount", 40 | { 41 | Integer, (* connection handle *) 42 | Integer, (* bson handle *) 43 | Integer (* opts handle *) 44 | }, 45 | Integer (* count *) 46 | ] 47 | 48 | mongoCollectionFind = LibraryFunctionLoad[$MongoLinkLib, 49 | "WL_MongoCollectionFind", 50 | { 51 | Integer, (* connection handle *) 52 | Integer, (* query *) 53 | Integer, (* opts *) 54 | Integer (* output cursor handle *) 55 | }, 56 | "Void" 57 | ] 58 | 59 | mongoCollectionName = LibraryFunctionLoad[$MongoLinkLib, 60 | "WL_CollectionGetName", 61 | { 62 | Integer (* collection handle *) 63 | }, 64 | "UTF8String" (* name *) 65 | ] 66 | 67 | mongoCollectionAggregate = LibraryFunctionLoad[$MongoLinkLib, 68 | "WL_MongoCollectionAggregation", 69 | { 70 | Integer, (* collection handle *) 71 | Integer, (* pipeline bson *) 72 | Integer, (* opts bson *) 73 | Integer (* cursor *) 74 | 75 | }, 76 | "Void" 77 | ] 78 | 79 | mongoCollectionStats = LibraryFunctionLoad[$MongoLinkLib, 80 | "WL_MongoCollectionStats", 81 | { 82 | Integer, (* collection handle *) 83 | Integer, (* opts bson *) 84 | Integer (* reply bson *) 85 | 86 | }, 87 | "Void" 88 | ] 89 | 90 | mongoCollectionValidate = LibraryFunctionLoad[$MongoLinkLib, 91 | "WL_MongoCollectionValidate", 92 | { 93 | Integer, (* collection handle *) 94 | Integer, (* opts bson *) 95 | Integer (* reply bson *) 96 | 97 | }, 98 | "Void" 99 | ] 100 | 101 | mongoCollectionDrop = LibraryFunctionLoad[$MongoLinkLib, 102 | "WL_MongoCollectionDrop", 103 | { 104 | Integer, (* collection handle *) 105 | Integer (* opts bson *) 106 | 107 | }, 108 | "Void" 109 | ] 110 | 111 | mongoCollectionCommandSimple = LibraryFunctionLoad[$MongoLinkLib, 112 | "WL_MongoCollectionCommandSimple", 113 | { 114 | Integer, (* collection handle *) 115 | Integer, (* command bson *) 116 | Integer (* reply bson *) 117 | }, 118 | "Void" 119 | ] 120 | 121 | (*----------------------------------------------------------------------------*) 122 | PackageExport["MongoCollection"] 123 | 124 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 125 | formatted display box *) 126 | DefineCustomBoxes[MongoCollection, 127 | e:MongoCollection[collMLE_, dbasename_, collname_, client_] :> Block[{}, 128 | BoxForm`ArrangeSummaryBox[ 129 | MongoCollection, e, None, 130 | { 131 | BoxForm`SummaryItem[{"ID: ", getMLEID[collMLE]}], 132 | BoxForm`SummaryItem[{"Collection: ", collname}], 133 | BoxForm`SummaryItem[{"Database: ", dbasename}] 134 | }, 135 | {}, 136 | StandardForm 137 | ] 138 | ]]; 139 | 140 | (* internal MongoCollection object accessors *) 141 | getClient[MongoCollection[__, client_]] := client 142 | getMLE[MongoCollection[collMLE_, __]] := collMLE; 143 | 144 | getMLEID[MongoCollection[collMLE_, __]] := ManagedLibraryExpressionID[collMLE]; 145 | 146 | (* Overload RandomSample for collections *) 147 | MongoCollection /: RandomSample[coll_MongoCollection, n_] := Module[ 148 | {pipeline}, 149 | pipeline = {<|"$sample" -> <|"size" -> n|>|>}; 150 | ReadList @ MongoCollectionAggregate[coll, pipeline] 151 | ] 152 | 153 | MongoCollection /: Length[coll_MongoCollection] := 154 | MongoCollectionCount[coll] 155 | 156 | (*----------------------------------------------------------------------------*) 157 | PackageExport["MongoCollectionName"] 158 | 159 | MongoCollectionName[MongoCollection[__, collname_, _]] := collname; 160 | 161 | DeclareArgumentCount[MongoCollectionName, 1]; 162 | MongoCollectionName::invargs = "A MongoCollection object was expected, but `` was given." 163 | MongoCollectionName[x_] := (Message[MongoCollectionName::invargs, x]; $Failed) 164 | 165 | 166 | (*----------------------------------------------------------------------------*) 167 | PackageExport["MongoGetCollection"] 168 | 169 | (* MongoGetCollection can either operate on Client or Database objects, so 170 | its name is not MongoDatabaseGetCollection etc. 171 | *) 172 | 173 | MongoGetCollection[db_MongoDatabase, collectionName_String] := 174 | CatchFailureAsMessage @ Module[ 175 | {collHandle}, 176 | (* Check that collectionName is in database *) 177 | collHandle = CreateManagedLibraryExpression["Collection", collectionMLE]; 178 | safeLibraryInvoke[databaseGetCollection, 179 | getMLEID[db], 180 | getMLEID[collHandle], 181 | collectionName 182 | ]; 183 | System`Private`SetNoEntry @ MongoCollection[ 184 | collHandle, 185 | MongoDatabaseName[db], 186 | collectionName, 187 | getClient[db] 188 | ] 189 | ] 190 | 191 | MongoGetCollection[client_MongoClient, 192 | databaseName_String, collectionName_String] := CatchFailureAsMessage @ Module[ 193 | {collHandle}, 194 | collHandle = CreateManagedLibraryExpression["Collection", collectionMLE]; 195 | safeLibraryInvoke[clientGetCollection, 196 | getMLEID[client], 197 | getMLEID[collHandle], 198 | databaseName, 199 | collectionName 200 | ]; 201 | System`Private`SetNoEntry @ MongoCollection[ 202 | collHandle, 203 | databaseName, 204 | collectionName, 205 | client 206 | ] 207 | ] 208 | 209 | (*----------------------------------------------------------------------------*) 210 | PackageExport["MongoCollectionName"] 211 | 212 | MongoCollectionName[coll_MongoCollection] := CatchFailureAsMessage @ 213 | safeLibraryInvoke[mongoCollectionName, getMLEID[coll]]; 214 | 215 | (*----------------------------------------------------------------------------*) 216 | PackageExport["MongoCollectionCount"] 217 | 218 | DeclareArgumentCount[MongoCollectionCount, {1, 2}]; 219 | MongoCollectionCount[coll_MongoCollection, query_Association] := 220 | CatchFailureAsMessage @ Module[ 221 | {bsonQuery, opts = <||>, optsBSON}, 222 | bsonQuery = iToBSON[query]; 223 | optsBSON = iToBSON[opts]; (* support opts in future *) 224 | safeLibraryInvoke[mongoCollectionCount, 225 | getMLEID[coll], 226 | getMLEID[bsonQuery], 227 | getMLEID[optsBSON] 228 | ] 229 | ] 230 | 231 | MongoCollectionCount[coll_MongoCollection] := 232 | MongoCollectionCount[coll, <||>] 233 | 234 | (*----------------------------------------------------------------------------*) 235 | PackageExport["MongoCollectionFindOne"] 236 | 237 | DeclareArgumentCount[MongoCollectionFindOne, {1, 3}]; 238 | MongoCollectionFindOne[coll_MongoCollection, query_Association, projection_Association] := Module[ 239 | {res}, 240 | res = MongoCollectionFind[coll, query, projection]; 241 | If[FailureQ[res], Return[$Failed]]; 242 | Read[res] 243 | ] 244 | 245 | MongoCollectionFindOne[coll_MongoCollection, query_Association] := 246 | MongoCollectionFindOne[coll, query, <||>] 247 | 248 | MongoCollectionFindOne[coll_MongoCollection] := 249 | MongoCollectionFindOne[coll, <||>, <||>] 250 | 251 | (*----------------------------------------------------------------------------*) 252 | PackageExport["MongoCollectionFind"] 253 | 254 | (* don't support all opts yet. See 255 | http://mongoc.org/libmongoc/current/mongoc_collection_find_with_opts.html 256 | for full opts list 257 | *) 258 | 259 | Options[MongoCollectionFind] = { 260 | "Limit" -> None, 261 | BatchSize -> Automatic 262 | }; 263 | 264 | MongoCollectionFind::invLimit = 265 | "The Option \"Limit\" must have value None or a non-negative integer, but `` was given."; 266 | MongoCollectionFind::invBatchSize = 267 | "The Option BatchSize must have value Automatic or a non-negative integer, but `` was given."; 268 | 269 | DeclareArgumentCount[MongoCollectionFind, {1, 3}]; 270 | 271 | MongoCollectionFind[coll_MongoCollection, 272 | query_Association, projection_Association, opts:OptionsPattern[]] := 273 | CatchFailureAsMessage @ Module[ 274 | { 275 | queryBSON, optsBSON, cursorHandle, optsAssoc, 276 | batchSize = OptionValue[BatchSize] 277 | }, 278 | (** parse opts **) 279 | optsAssoc = <| 280 | "limit" -> Replace[OptionValue["Limit"], None -> 0], 281 | "projection" -> projection 282 | |>; 283 | If[!IntegerQ[optsAssoc["limit"]] || Negative[optsAssoc["limit"]], 284 | ThrowFailure[MongoCollectionFind::invLimit, optsAssoc["limit"]] 285 | ]; 286 | 287 | If[batchSize =!= Automatic, 288 | optsAssoc["batchSize"] = batchSize; 289 | If[!IntegerQ[batchSize] || Negative[batchSize], 290 | ThrowFailure[MongoCollectionFind::invBatchSize, batchSize] 291 | ] 292 | ]; 293 | 294 | (* Create BSON query + field docs *) 295 | queryBSON = iToBSON[query]; 296 | optsBSON = iToBSON[optsAssoc]; 297 | 298 | cursorHandle = CreateManagedLibraryExpression["Cursor", cursorMLE]; 299 | safeLibraryInvoke[mongoCollectionFind, 300 | getMLEID[coll], 301 | getMLEID[queryBSON], 302 | getMLEID[optsBSON], 303 | getMLEID[cursorHandle] 304 | ]; 305 | System`Private`SetNoEntry @ 306 | MongoCursor[cursorHandle, getClient[coll]] 307 | ] 308 | 309 | MongoCollectionFind[coll_MongoCollection, opts:OptionsPattern[]] := 310 | MongoCollectionFind[coll, <||>, <||>, opts] 311 | 312 | MongoCollectionFind[coll_MongoCollection, query_, opts:OptionsPattern[]] := 313 | MongoCollectionFind[coll, query, <||>, opts] 314 | 315 | (*----------------------------------------------------------------------------*) 316 | PackageExport["MongoCollectionAggregate"] 317 | 318 | DeclareArgumentCount[MongoCollectionAggregate, {1, 2}]; 319 | 320 | MongoCollectionAggregate[coll_MongoCollection, pipeline_, opts_Association] := Module[ 321 | {cursorHandle, pipelineBSON, optsBSON}, 322 | cursorHandle = CreateManagedLibraryExpression["Cursor", cursorMLE]; 323 | pipelineBSON = iToBSON[<|"pipeline" -> pipeline|>]; 324 | optsBSON = optsToBSON[opts]; 325 | safeLibraryInvoke[mongoCollectionAggregate, 326 | getMLEID[coll], 327 | getMLEID[pipelineBSON], 328 | getMLEID[optsBSON], 329 | getMLEID[cursorHandle] 330 | ]; 331 | 332 | System`Private`SetNoEntry @ MongoCursor[ 333 | cursorHandle, getClient[coll] 334 | ] 335 | ] 336 | 337 | MongoCollectionAggregate[coll_MongoCollection, pipeline_] := 338 | MongoCollectionAggregate[coll, pipeline, <||>] 339 | 340 | (*----------------------------------------------------------------------------*) 341 | PackageExport["MongoCollectionStats"] 342 | 343 | DeclareArgumentCount[MongoCollectionStats, 1]; 344 | 345 | MongoCollectionStats[coll_MongoCollection] := CatchFailureAsMessage @ Module[ 346 | {optsBSON, replyBSON}, 347 | (* don't support opts yet *) 348 | optsBSON = ToBSON[<||>]; 349 | replyBSON = CreateManagedLibraryExpression["BSON", bsonMLE]; 350 | safeLibraryInvoke[mongoCollectionStats, 351 | getMLEID[coll], 352 | getMLEID[optsBSON], 353 | getMLEID[replyBSON] 354 | ]; 355 | Dataset @ BSONToAssociation[BSONObject[replyBSON]] 356 | ] 357 | 358 | (*----------------------------------------------------------------------------*) 359 | PackageExport["MongoCollectionDrop"] 360 | 361 | DeclareArgumentCount[MongoCollectionDrop, 1]; 362 | 363 | MongoCollectionDrop[coll_MongoCollection] := CatchFailureAsMessage @ Module[ 364 | {optsBSON}, 365 | (* don't support opts yet *) 366 | optsBSON = ToBSON[<||>]; 367 | safeLibraryInvoke[mongoCollectionDrop, 368 | getMLEID[coll], 369 | getMLEID[optsBSON] 370 | ]; 371 | ] 372 | 373 | (*----------------------------------------------------------------------------*) 374 | PackageExport["MongoCollectionValidate"] 375 | 376 | DeclareArgumentCount[MongoCollectionValidate, 1]; 377 | 378 | MongoCollectionValidate[coll_MongoCollection] := CatchFailureAsMessage @ Module[ 379 | {optsBSON, replyBSON}, 380 | (* don't support opts yet *) 381 | optsBSON = ToBSON[<||>]; 382 | replyBSON = CreateManagedLibraryExpression["BSON", bsonMLE]; 383 | safeLibraryInvoke[mongoCollectionValidate, 384 | getMLEID[coll], 385 | getMLEID[optsBSON], 386 | getMLEID[replyBSON] 387 | ]; 388 | Dataset @ BSONToAssociation[BSONObject[replyBSON]] 389 | ] 390 | 391 | (*----------------------------------------------------------------------------*) 392 | PackageExport["MongoReferenceGet"] 393 | 394 | MongoReferenceGet[database_MongoDatabase, mong_MongoDBReference] := 395 | CatchFailureAsMessage @ Module[ 396 | {coll, docIter}, 397 | coll = MongoGetCollection[database, First[mong]]; 398 | docIter = MongoCollectionFind[coll, <|"_id" -> <|"$oid" -> Last[mong]|>|>]; 399 | If[FailureQ[docIter], Return[$Failed]]; 400 | Read[docIter] 401 | ] 402 | 403 | (*----------------------------------------------------------------------------*) 404 | PackageScope["mongoCollectionCommand"] 405 | 406 | mongoCollectionCommand[coll_MongoCollection, command_] := Module[ 407 | {commandBSON, docIter}, 408 | commandBSON = ToBSON[command]; 409 | replyBSON = CreateManagedLibraryExpression["BSON", bsonMLE]; 410 | safeLibraryInvoke[mongoCollectionCommandSimple, 411 | getMLEID[coll], 412 | getMLEID[commandBSON], 413 | getMLEID[replyBSON] 414 | ]; 415 | BSONToAssociation[BSONObject[replyBSON]] 416 | ] 417 | 418 | (*----------------------------------------------------------------------------*) 419 | PackageExport["MongoCollectionDistinct"] 420 | 421 | DeclareArgumentCount[MongoCollectionDistinct, {2, 3}]; 422 | 423 | MongoCollectionDistinct[coll_MongoCollection, key_String, query_Association] := 424 | CatchFailureAsMessage @ Module[ 425 | {cmd = <||>, res}, 426 | cmd["distinct"] = MongoCollectionName[coll]; 427 | cmd["key"] = key; 428 | cmd["query"] = query; 429 | res = mongoCollectionCommand[coll, cmd]; 430 | Lookup[res, "values"] 431 | ] 432 | 433 | MongoCollectionDistinct[coll_MongoCollection, key_String] := 434 | MongoCollectionDistinct[coll, key, <||>] 435 | 436 | -------------------------------------------------------------------------------- /MongoLink/Kernel/Cursor.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Mongo Document Cursor Interface 4 | 5 | See: https://docs.mongodb.com/manual/reference/method/js-cursor/ 6 | 7 | *******************************************************************************) 8 | 9 | Package["MongoLink`"] 10 | 11 | PackageImport["GeneralUtilities`"] 12 | 13 | PackageScope["cursorMLE"] (* cursor ManagedLibraryExpression *) 14 | 15 | (******************************************************************************) 16 | (****** Load Library Functions ******) 17 | 18 | cursorNext = LibraryFunctionLoad[$MongoLinkLib, "WL_CursorNext", 19 | { 20 | Integer, (* cursor handle *) 21 | Integer (* bson handle *) 22 | 23 | }, 24 | Integer 25 | ] 26 | 27 | cursorSetBatchSize = LibraryFunctionLoad[$MongoLinkLib, "WL_CursorSetBatchSize", 28 | { 29 | Integer, (* cursor handle *) 30 | Integer (* batch size *) 31 | 32 | }, 33 | "Void" 34 | ] 35 | 36 | cursorGetInfo = LibraryFunctionLoad[$MongoLinkLib, "WL_CursorInfo", 37 | { 38 | Integer, (* cursor handle *) 39 | Integer (* type switch *) 40 | 41 | }, 42 | Integer 43 | ] 44 | 45 | (*----------------------------------------------------------------------------*) 46 | PackageExport["MongoCursor"] 47 | 48 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 49 | formatted display box *) 50 | DefineCustomBoxes[MongoCursor, 51 | e:MongoCursor[cursorMLE_, client_] :> Block[{}, 52 | BoxForm`ArrangeSummaryBox[ 53 | MongoCursor, e, None, 54 | { 55 | BoxForm`SummaryItem[{"ID: ", getMLEID[cursorMLE]}] 56 | }, 57 | {}, 58 | StandardForm 59 | ] 60 | ]]; 61 | 62 | getClient[MongoCursor[__, client_]] := client 63 | 64 | getMLE[MongoCursor[cursorMLE_, __]] := cursorMLE; 65 | getMLEID[MongoCursor[cursorMLE_, __]] := ManagedLibraryExpressionID[cursorMLE]; 66 | 67 | MongoCursor /: Read[cursor_MongoCursor] := MongoCursorNext[cursor] 68 | MongoCursor /: ReadList[cursor_MongoCursor] := MongoCursorToArray[cursor] 69 | 70 | MongoCursor /: Dataset[cursor_MongoCursor] := Dataset @ MongoCursorToArray[cursor] 71 | 72 | (*----------------------------------------------------------------------------*) 73 | PackageExport["MongoCursorNext"] 74 | 75 | MongoCursorNext[cursor_MongoCursor] := CatchFailureAsMessage @ iMongoCursorNext[cursor] 76 | 77 | iMongoCursorNext[cursor_MongoCursor] := Module[ 78 | {bson, hasNext}, 79 | bson = CreateManagedLibraryExpression["BSON", bsonMLE]; 80 | hasNext = safeLibraryInvoke[cursorNext, getMLEID[cursor], getMLEID[bson]]; 81 | (* return Null if iterator is exhausted *) 82 | If[hasNext === 0, 83 | Null, 84 | BSONToAssociation @ BSONObject[bson] 85 | ] 86 | ] 87 | 88 | (*----------------------------------------------------------------------------*) 89 | PackageExport["MongoCursorToArray"] 90 | 91 | Options[MongoCursorToArray] = { 92 | MaxItems -> Infinity 93 | } 94 | 95 | MongoCursorToArray[cursor_MongoCursor, OptionsPattern[]] := 96 | CatchFailureAsMessage @ Module[ 97 | {max, bag, current, count}, 98 | max = OptionValue[MaxItems]; 99 | bag = Internal`Bag[]; 100 | count = 1; 101 | While[count <= max, 102 | current = iMongoCursorNext[cursor]; 103 | If[current === Null, Break[]]; 104 | Internal`StuffBag[bag, current]; 105 | count += 1; 106 | ]; 107 | Internal`BagPart[bag, All] 108 | ] 109 | 110 | (*----------------------------------------------------------------------------*) 111 | PackageExport["MongoCursorSetBatchSize"] 112 | 113 | MongoCursorSetBatchSize[cursor_MongoCursor, size_Integer] := CatchFailureAsMessage @ 114 | safeLibraryInvoke[cursorSetBatchSize, getMLEID[cursor], size]; 115 | 116 | MongoCursorBatchSize[cursor_MongoCursor, Automatic] := CatchFailureAsMessage @ 117 | safeLibraryInvoke[cursorSetBatchSize, getMLEID[cursor], 0]; 118 | 119 | (*----------------------------------------------------------------------------*) 120 | PackageExport["MongoCursorGetBatchSize"] 121 | 122 | MongoCursorGetBatchSize[cursor_MongoCursor] := CatchFailureAsMessage @ 123 | Replace[safeLibraryInvoke[cursorGetInfo, getMLEID[cursor], 1], 0 -> Automatic] 124 | 125 | (*----------------------------------------------------------------------------*) 126 | PackageExport["MongoCursorInformation"] 127 | 128 | MongoCursorInformation[cursor_MongoCursor] := CatchFailureAsMessage @ Module[ 129 | {info = getMLEID[cursor]}, 130 | info = safeLibraryInvoke[cursorGetInfo, getMLEID[cursor], #]& /@ Range[5]; 131 | <| 132 | "BatchSize" -> Replace[info[[1]], 0 -> Automatic], 133 | "AliveQ" -> Replace[info[[2]], {0 -> False, 1 -> True}], 134 | "ServerID" -> info[[3]], 135 | "MaxWaitTime" -> timeconv @ info[[4]], 136 | "Limit" -> Replace[info[[5]], 0 -> Infinity] 137 | |> 138 | ] 139 | 140 | timeconv[x_] := If[x == 0, Automatic, Quantity[8, "Milliseconds"]] -------------------------------------------------------------------------------- /MongoLink/Kernel/Database.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Database level functions 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | PackageScope["databaseMLE"] (* database ManagedLibraryExpression *) 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | databaseHandleCreate = LibraryFunctionLoad[$MongoLinkLib, "WL_DatabaseHandleCreate", 17 | { 18 | Integer, (* client handle *) 19 | Integer, (* database handle *) 20 | "UTF8String" (* database name *) 21 | 22 | }, 23 | "Void" 24 | ] 25 | 26 | getCollectionNames = LibraryFunctionLoad[$MongoLinkLib, "WL_GetCollectionNames", 27 | Automatic, LinkObject 28 | ] 29 | 30 | mongoDatabaseName = LibraryFunctionLoad[$MongoLinkLib, "WL_DatabaseGetName", 31 | { 32 | Integer (* collection handle *) 33 | }, 34 | "UTF8String" (* name *) 35 | ] 36 | 37 | mongoDatabaseDrop = LibraryFunctionLoad[$MongoLinkLib, "WL_mongoc_database_drop", 38 | { 39 | Integer (* database handle *) 40 | }, 41 | "Void" 42 | ] 43 | 44 | (*----------------------------------------------------------------------------*) 45 | PackageExport["MongoDatabase"] 46 | 47 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 48 | formatted display box *) 49 | DefineCustomBoxes[MongoDatabase, 50 | e:MongoDatabase[dbMLE_, name_, client_] :> Block[{}, 51 | BoxForm`ArrangeSummaryBox[ 52 | MongoDatabase, e, None, 53 | { 54 | BoxForm`SummaryItem[{"ID: ", ManagedLibraryExpressionID[dbMLE]}], 55 | BoxForm`SummaryItem[{"Database: ", name}] 56 | }, 57 | {}, 58 | StandardForm 59 | ] 60 | ]]; 61 | 62 | getClient[MongoDatabase[__, client_]] := client 63 | getMLE[MongoDatabase[dbMLE_, __]] := dbMLE; 64 | getMLEID[MongoDatabase[dbMLE_, __]] := ManagedLibraryExpressionID[dbMLE]; 65 | 66 | (* connect to collection syntactic sugar *) 67 | MongoDatabase[dbMLE_, name_, clientMLE_][collname_String] := 68 | MongoGetCollection[MongoDatabase[dbMLE, name, clientMLE], collname] 69 | 70 | PackageExport["MongoDatabaseName"] 71 | MongoDatabaseName[MongoDatabase[_, name_, _]] := name; 72 | MongoDatabaseName[___] := $Failed 73 | 74 | MongoDatabase /: Length[d_MongoDatabase] := Module[ 75 | {names = MongoGetCollectionNames[d]}, 76 | If[FailureQ[names], Return[names]]; 77 | Length[names] 78 | ] 79 | 80 | MongoDatabase /: Keys[d_MongoDatabase] := 81 | MongoGetCollectionNames[d] 82 | 83 | (*----------------------------------------------------------------------------*) 84 | PackageExport["MongoGetDatabase"] 85 | PackageScope["iMongoGetDatabase"] 86 | 87 | MongoGetDatabase[client_MongoClient, databaseName_String] := 88 | CatchFailureAsMessage @ iMongoGetDatabase[client, databaseName] 89 | 90 | iMongoGetDatabase[client_MongoClient, databaseName_String] := Module[ 91 | {dbMLE, result}, 92 | dbMLE = CreateManagedLibraryExpression["Database", databaseMLE]; 93 | result = safeLibraryInvoke[databaseHandleCreate, 94 | getMLEID[client], 95 | ManagedLibraryExpressionID[dbMLE], 96 | databaseName 97 | ]; 98 | System`Private`SetNoEntry @ 99 | MongoDatabase[dbMLE, databaseName, client] 100 | ] 101 | 102 | DeclareArgumentCount[MongoGetDatabase, 2]; 103 | MongoGetDatabase[args___] := (Message[MongoGetDatabase::mongoinvarg, List@args]; $Failed) 104 | 105 | (*----------------------------------------------------------------------------*) 106 | PackageExport["MongoGetCollectionNames"] 107 | 108 | MongoGetCollectionNames[db_MongoDatabase] := CatchFailureAsMessage @ 109 | safeLibraryInvoke[getCollectionNames, getMLEID @ db] 110 | 111 | DeclareArgumentCount[MongoGetCollectionNames, 1]; 112 | MongoGetCollectionNames::invargs = "A MongoDatabase object was expected, but `` was given." 113 | MongoGetCollectionNames[db_] := (Message[MongoGetCollectionNames::invargs, db]; $Failed) 114 | 115 | (*----------------------------------------------------------------------------*) 116 | PackageExport["MongoDatabaseDrop"] 117 | 118 | MongoDatabaseDrop[db_MongoDatabase] := CatchFailureAsMessage @ 119 | safeLibraryInvoke[mongoDatabaseDrop, getMLEID[db]]; 120 | 121 | DeclareArgumentCount[MongoDatabaseDrop, 1]; 122 | MongoDatabaseDrop::invargs = "A MongoDatabase object was expected, but `` was given." 123 | MongoDatabaseDrop[db_] := (Message[MongoDatabaseDrop::invargs, db]; $Failed) 124 | -------------------------------------------------------------------------------- /MongoLink/Kernel/SSL/client.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 7 (0x7) 5 | Signature Algorithm: sha1WithRSAEncryption 6 | Issuer: C=US, ST=New York, L=New York City, O=10Gen, OU=Kernel, CN=My Cert Authority/emailAddress=root@lazarus 7 | Validity 8 | Not Before: Aug 23 14:55:32 2013 GMT 9 | Not After : Jan 7 14:55:32 2041 GMT 10 | Subject: C=US, ST=New York, L=New York City, O=10Gen, OU=kerneluser, CN=client 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:ba:16:42:d4:8b:3d:5e:8a:67:9e:a7:c0:cd:4a: 16 | 9c:9c:fd:95:b9:83:bf:f4:cf:03:8c:2e:db:a9:c1: 17 | 35:58:80:f6:e2:e9:87:28:84:e3:d0:9b:68:60:51: 18 | 0e:42:84:d8:6f:e8:34:cc:18:97:79:d3:8d:d8:2f: 19 | 23:11:25:6f:69:7a:38:bb:8c:b2:29:e9:91:be:79: 20 | 8c:cc:1b:56:98:98:d3:83:2a:c5:f9:9c:86:0c:2c: 21 | 24:0e:5c:46:3b:a9:95:44:6c:c5:e0:7c:9d:03:ae: 22 | 0d:23:99:49:a4:48:dd:0e:35:a2:e5:b4:8b:86:bd: 23 | c0:c8:ce:d5:ac:c4:36:f3:9e:5f:17:00:23:8d:53: 24 | a1:43:1b:a3:61:96:36:80:4d:35:50:b5:8b:69:31: 25 | 39:b4:63:8b:96:59:5c:d1:ea:92:eb:eb:fa:1b:35: 26 | 64:44:b3:f6:f3:a6:9d:49:3a:59:e5:e1:c2:cb:98: 27 | be:29:b3:22:dd:33:97:d7:50:4f:db:c2:58:64:18: 28 | b5:8c:3c:6b:2d:21:f6:bd:8d:e5:d2:da:8d:79:fe: 29 | a7:80:75:a8:15:b9:ee:79:7f:01:31:1d:e5:e7:15: 30 | 76:53:65:f6:fe:f0:93:7d:20:3d:cc:ff:9b:ca:b2: 31 | 50:2c:1b:3a:69:d5:e6:70:cf:ac:be:7e:5c:33:c4: 32 | 6e:a7 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Basic Constraints: 36 | CA:FALSE 37 | Netscape Comment: 38 | OpenSSL Generated Certificate 39 | X509v3 Subject Key Identifier: 40 | 4A:8B:EE:22:42:E6:F8:62:4C:86:38:8D:C5:78:95:98:C1:10:05:7C 41 | X509v3 Authority Key Identifier: 42 | keyid:07:41:19:3A:9F:7E:C5:B7:22:4E:B7:BC:D5:DF:E4:FC:09:B8:64:16 43 | 44 | Signature Algorithm: sha1WithRSAEncryption 45 | 13:13:a8:f0:de:78:c6:b1:e0:85:cc:27:e6:04:28:44:93:1d: 46 | f1:ff:5e:81:69:33:1f:f3:76:e0:49:ca:d9:ad:aa:db:f5:a5: 47 | f8:a6:50:bb:a1:a7:40:14:e4:2f:8d:b8:21:7f:35:04:60:db: 48 | af:f0:9e:dd:a1:ca:0b:7f:03:2e:2f:19:1e:32:6e:1e:2d:87: 49 | 68:e3:37:47:a8:5b:93:d1:88:41:73:da:88:21:59:27:d4:35: 50 | 1c:6a:27:b5:c0:c6:17:ba:f3:87:c8:e1:f4:8f:43:12:bc:fa: 51 | 8d:90:d5:86:83:df:51:a5:c9:e0:92:f0:66:d0:37:61:6f:85: 52 | 24:18 53 | -----BEGIN CERTIFICATE----- 54 | MIIDdjCCAt+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCVVMx 55 | ETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYD 56 | VQQKDAUxMEdlbjEPMA0GA1UECwwGS2VybmVsMRowGAYDVQQDDBFNeSBDZXJ0IEF1 57 | dGhvcml0eTEbMBkGCSqGSIb3DQEJARYMcm9vdEBsYXphcnVzMB4XDTEzMDgyMzE0 58 | NTUzMloXDTQxMDEwNzE0NTUzMlowbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l 59 | dyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYDVQQKDAUxMEdlbjET 60 | MBEGA1UECwwKa2VybmVsdXNlcjEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG 61 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuhZC1Is9XopnnqfAzUqcnP2VuYO/9M8DjC7b 62 | qcE1WID24umHKITj0JtoYFEOQoTYb+g0zBiXedON2C8jESVvaXo4u4yyKemRvnmM 63 | zBtWmJjTgyrF+ZyGDCwkDlxGO6mVRGzF4HydA64NI5lJpEjdDjWi5bSLhr3AyM7V 64 | rMQ2855fFwAjjVOhQxujYZY2gE01ULWLaTE5tGOLlllc0eqS6+v6GzVkRLP286ad 65 | STpZ5eHCy5i+KbMi3TOX11BP28JYZBi1jDxrLSH2vY3l0tqNef6ngHWoFbnueX8B 66 | MR3l5xV2U2X2/vCTfSA9zP+byrJQLBs6adXmcM+svn5cM8RupwIDAQABo3sweTAJ 67 | BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0 68 | aWZpY2F0ZTAdBgNVHQ4EFgQUSovuIkLm+GJMhjiNxXiVmMEQBXwwHwYDVR0jBBgw 69 | FoAUB0EZOp9+xbciTre81d/k/Am4ZBYwDQYJKoZIhvcNAQEFBQADgYEAExOo8N54 70 | xrHghcwn5gQoRJMd8f9egWkzH/N24EnK2a2q2/Wl+KZQu6GnQBTkL424IX81BGDb 71 | r/Ce3aHKC38DLi8ZHjJuHi2HaOM3R6hbk9GIQXPaiCFZJ9Q1HGontcDGF7rzh8jh 72 | 9I9DErz6jZDVhoPfUaXJ4JLwZtA3YW+FJBg= 73 | -----END CERTIFICATE----- 74 | -----BEGIN PRIVATE KEY----- 75 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6FkLUiz1eimee 76 | p8DNSpyc/ZW5g7/0zwOMLtupwTVYgPbi6YcohOPQm2hgUQ5ChNhv6DTMGJd5043Y 77 | LyMRJW9peji7jLIp6ZG+eYzMG1aYmNODKsX5nIYMLCQOXEY7qZVEbMXgfJ0Drg0j 78 | mUmkSN0ONaLltIuGvcDIztWsxDbznl8XACONU6FDG6NhljaATTVQtYtpMTm0Y4uW 79 | WVzR6pLr6/obNWREs/bzpp1JOlnl4cLLmL4psyLdM5fXUE/bwlhkGLWMPGstIfa9 80 | jeXS2o15/qeAdagVue55fwExHeXnFXZTZfb+8JN9ID3M/5vKslAsGzpp1eZwz6y+ 81 | flwzxG6nAgMBAAECggEBALYw92urjAFVFxCiA8W7aEzYhtAkaztft4R3mD/C19z4 82 | H0CZDeig+3+RuIactY5xDIu8WHz/EseHVlg0BmxSL5ugu4z8uq8IbNaFoVFw7r7m 83 | 2ieRKFY0ZpXiXcbllynw5iEhMjeRKhWhQmH5Qb2kTTINV5j4xKa+f9Lblx7Y2Uh4 84 | tsaOtlMwb98D2/KYJdTv5Nj1nyuSqRVhECsd00Cb6JUBGQBx8Ja0wFy9gEygq6kU 85 | w3s1XNOSnYNEo4FaVZwp5KZyCyBENcKpNUq4nXt/7ncEfVYdJck0Li3wN4Jr2J9S 86 | eHqRzh8QkHxc1Ro8ktcXaUSs9kFuwvVvb4rcGUpOMWkCgYEA9xxp8yDtFVgzMtc/ 87 | vS8xgM1Wj4SrgKKYhE2wS05BJh/41oFMzfH1FpZ1GCM983r4QgYWoT71XsBgiOMC 88 | yN2p2IbV4V44bMGKJqaVMkB91CVCUWI6piaCQb/1CJTwaXE7zPim6dlUSxxBBnRn 89 | LP50NTscRLFcCZELD3Yl7jR8XFUCgYEAwMfkNFmGtBKAwlHZ3Y3XOwPWg+jCll7s 90 | 9nhv8TU2IB9pcCRGqyOT7k1YymvYkDT2Je4JUPWEBs4cW7yD61LrQ8w8+DrE9dGo 91 | czzGPyjOAANSX0asG74UjkNIQThmyEOltVHIxYMaSqowjHRSPdA+R4Od9EdcDdfS 92 | q5SfSVFxmwsCgYBtl1thqUOcCL7EGHQ7KdfxgJ+YDMWmyfWMD4xVCYKZLurD7xop 93 | 59nDR7zslIygE/RQC7Uzk+FsQTNO4ibVAIGX9syaI5gwm3DyjURzwehMEq4ju8W4 94 | 9DEmicRZJvysNrzHvasA4RKiMQihnTQ43yyYgvuZd3MTBxF5rPNLfll89QKBgQC9 95 | SsmiOZIR+OUjaTmS2bbQBNm7Fm8TNcxZyzKn1wb5jb57VbNqUfnskVgxEqpIFyjn 96 | X48YRqtH/1RLI5UpGXdXUBFB8Hr7oM1VsgQ7ejakPp7AXOWcLA2FDz3AhMAvvnTU 97 | 0KRihHPpgqk/EOy8M2Ej2XHcrcEO+q+quLmbRXRWtwKBgHacQiwci/2J+v0e9i52 98 | re/2AJHKP5MwNHFe1e01iNc5EEN0G+/Ut8XW19DWf6bsxqie0ChC+xN8TUst8alT 99 | F+tXTsHHmt/lRcjTROjT5XVuoqjtU2Q0QeVeGLgvObso+fZy3ZNeQuSJjWukdMZ3 100 | 57rGT6p0OuM8qbrTzpv3JMrm 101 | -----END PRIVATE KEY----- 102 | -------------------------------------------------------------------------------- /MongoLink/Kernel/URI.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | URI level functions 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | PackageScope["uriMLE"] (* URI ManagedLibraryExpression *) 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | uriCreate = LibraryFunctionLoad[$MongoLinkLib, "WL_URICreate", 17 | { 18 | Integer, (* uri handle *) 19 | "UTF8String" (* uri *) 20 | }, 21 | "Void" 22 | ] 23 | 24 | uriSetOptionInt32 = LibraryFunctionLoad[$MongoLinkLib, "WL_URISetOptionInt32", 25 | { 26 | Integer, (* uri handle *) 27 | "UTF8String", (* name *) 28 | Integer (* value *) 29 | }, 30 | "Void" 31 | ] 32 | 33 | uriSetOptionBool = LibraryFunctionLoad[$MongoLinkLib, "WL_URISetOptionBool", 34 | { 35 | Integer, (* uri handle *) 36 | "UTF8String", (* name *) 37 | True|False (* value *) 38 | }, 39 | "Void" 40 | ] 41 | 42 | uriSetOptionUFT8 = LibraryFunctionLoad[$MongoLinkLib, "WL_URISetOptionUTF8", 43 | { 44 | Integer, (* uri handle *) 45 | "UTF8String", (* name *) 46 | "UTF8String" (* value *) 47 | }, 48 | "Void" 49 | ] 50 | 51 | uriGetString = LibraryFunctionLoad[$MongoLinkLib, "WL_URIGetString", 52 | { 53 | Integer (* uri handle *) 54 | }, 55 | "UTF8String" 56 | ] 57 | 58 | uriSetPropEnum = LibraryFunctionLoad[$MongoLinkLib, "WL_URISetPropEnum", 59 | { 60 | Integer, (* uri handle *) 61 | "UTF8String", (* value *) 62 | Integer (* selector *) 63 | }, 64 | "Void" 65 | ] 66 | 67 | (*----------------------------------------------------------------------------*) 68 | PackageExport["MongoURI"] 69 | 70 | MongoURI /: ToString[MongoURI[uriMLE_, uri_String]] := URLDecode[uri] 71 | 72 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 73 | formatted display box *) 74 | DefineCustomBoxes[MongoURI, 75 | e:MongoURI[uriMLE_, uri_String] :> Block[{}, 76 | BoxForm`ArrangeSummaryBox[ 77 | MongoURI, e, None, 78 | {BoxForm`SummaryItem[{"ID: ", ManagedLibraryExpressionID[uriMLE]}]}, 79 | {}, 80 | StandardForm 81 | ] 82 | ]]; 83 | 84 | getMLE[MongoURI[uriMLE_, __]] := uriMLE; 85 | getMLEID[MongoURI[uriMLE_, __]] := ManagedLibraryExpressionID[uriMLE]; 86 | 87 | MongoURI /: ToString[x_MongoURI] := 88 | CatchFailureAsMessage @ safeLibraryInvoke[uriGetString, getMLEID @ x] 89 | 90 | (*----------------------------------------------------------------------------*) 91 | PackageScope["uriFromString"] 92 | 93 | uriFromString[uri_String] := Module[ 94 | { 95 | handle = CreateManagedLibraryExpression["URI", uriMLE], 96 | res 97 | }, 98 | res = safeLibraryInvoke[uriCreate, getMLEID[handle], uri]; 99 | System`Private`SetNoEntry @ MongoURI[handle, uri] 100 | ] 101 | 102 | (*----------------------------------------------------------------------------*) 103 | PackageScope["uriConstruct"] 104 | 105 | setprop[func_, uri_, opts_, val1_, val2_] := 106 | If[KeyExistsQ[opts, val1], safeLibraryInvoke[func, getMLEID@uri, opts[val1], val2]]; 107 | 108 | uriConstruct[opts_Association] := Module[ 109 | {uri, opts2 = opts, host, port}, 110 | 111 | {host, port} = Lookup[opts2, {"host", "port"}]; 112 | KeyDropFrom[opts2, {"host", "port"}]; 113 | 114 | (* assume host is URI string *) 115 | uri = CatchFailure @ uriFromString[host]; 116 | If[FailureQ[uri], 117 | uri = uriFromString["mongodb://" <> host <> ":" <> ToString[port]] 118 | ]; 119 | 120 | (** Authentication **) 121 | setprop[uriSetPropEnum, uri, opts2, "authmechanism", 1]; 122 | setprop[uriSetPropEnum, uri, opts2, "authsource", 2]; 123 | setprop[uriSetPropEnum, uri, opts2, "password", 5]; 124 | setprop[uriSetPropEnum, uri, opts2, "username", 6]; 125 | 126 | (** Compress **) 127 | setprop[uriSetPropEnum, uri, opts, "compressors", 3]; 128 | 129 | (** Other **) 130 | KeyDropFrom[opts2, 131 | {"authmechanism", "authsource", "password", "username", "compressors"} 132 | ]; 133 | KeyValueMap[uriSetOption[uri, #1, #2]&, opts2]; 134 | uri 135 | ] 136 | 137 | (*----------------------------------------------------------------------------*) 138 | PackageScope["uriSetOption"] 139 | 140 | uriSetOption::invtype = "Invalid type. Only String, Integer or boolean types supported." 141 | 142 | uriSetOption[uri_MongoURI, name_String, val_Integer] := 143 | safeLibraryInvoke[uriSetOptionInt32, getMLEID @ uri, name, val] 144 | 145 | uriSetOption[uri_MongoURI, name_String, val_String] := 146 | safeLibraryInvoke[uriSetOptionUFT8, getMLEID @ uri, name, val] 147 | 148 | uriSetOption[uri_MongoURI, name_String, val_ /; BooleanQ[val]] := 149 | safeLibraryInvoke[uriSetOptionBool, getMLEID @ uri, name, val] 150 | 151 | uriSetOption[___] := ThrowFailure[uriSetOption::invtype] 152 | -------------------------------------------------------------------------------- /MongoLink/Kernel/Version.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Version level functions 4 | 5 | *******************************************************************************) 6 | 7 | 8 | Package["MongoLink`"] 9 | 10 | PackageImport["GeneralUtilities`"] 11 | 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | mongoGetVersion = LibraryFunctionLoad[$MongoLinkLib, "WL_MongoGetVersion", 17 | { 18 | }, 19 | "UTF8String" 20 | ] 21 | 22 | (*----------------------------------------------------------------------------*) 23 | PackageExport["MongoDriverVersion"] 24 | 25 | MongoDriverVersion::usage = 26 | "MongoDriverVersion[] returns a string of the Mongo C Driver used by MongoLink. 27 | " 28 | 29 | MongoDriverVersion[] := mongoGetVersion[] -------------------------------------------------------------------------------- /MongoLink/Kernel/WriteConcern.m: -------------------------------------------------------------------------------- 1 | (******************************************************************************* 2 | 3 | Write Concern object. 4 | 5 | *******************************************************************************) 6 | 7 | Package["MongoLink`"] 8 | 9 | PackageImport["GeneralUtilities`"] 10 | 11 | PackageScope["writeConcernMLE"] (* write concern ManagedLibraryExpression *) 12 | 13 | (*----------------------------------------------------------------------------*) 14 | (****** Load Library Functions ******) 15 | 16 | writeConcernNew = LibraryFunctionLoad[$MongoLinkLib, "WL_WriteConcernNew", 17 | { 18 | Integer (* write concern handle key *) 19 | }, 20 | "Void" 21 | ] 22 | 23 | WriteConcernSet = LibraryFunctionLoad[$MongoLinkLib, "WL_WriteConcernSet", 24 | { 25 | Integer, (* write concern handle key *) 26 | Integer (* parameter *) 27 | }, 28 | "Void" 29 | ] 30 | 31 | WriteConcernSetWtimeout = LibraryFunctionLoad[$MongoLinkLib, "WL_WriteConcernSetWtimeout", 32 | { 33 | Integer, (* write concern handle key *) 34 | Integer (* timeout time in milliseconds *) 35 | }, 36 | "Void" 37 | ] 38 | 39 | WriteConcernSetJournal = LibraryFunctionLoad[$MongoLinkLib, "WL_WriteConcernSetJournal", 40 | { 41 | Integer, (* write concern handle key *) 42 | Integer (* boole *) 43 | }, 44 | "Void" 45 | ] 46 | 47 | (*----------------------------------------------------------------------------*) 48 | PackageExport["MongoWriteConcern"] 49 | 50 | (* This is a utility function defined in GeneralUtilities, which makes a nicely 51 | formatted display box *) 52 | DefineCustomBoxes[MongoWriteConcern, 53 | e:MongoWriteConcern[wcMLE_] :> Block[{}, 54 | BoxForm`ArrangeSummaryBox[ 55 | MongoWriteConcern, e, None, 56 | { 57 | BoxForm`SummaryItem[{"ID: ", getMLEID[wcMLE]}] 58 | }, 59 | {}, 60 | StandardForm 61 | ] 62 | ]]; 63 | 64 | getMLE[MongoWriteConcern[wcMLE_]] := wcMLE; 65 | getMLEID[MongoWriteConcern[wcMLE_]] := ManagedLibraryExpressionID[wcMLE]; 66 | 67 | (*----------------------------------------------------------------------------*) 68 | PackageExport["MongoWriteConcernCreate"] 69 | 70 | MongoWriteConcernCreate::journal = 71 | "The Option \"Journal\" must have value True or False, but value `` was given."; 72 | MongoWriteConcernCreate::timeout = 73 | "The Option \"Timeout\" must have value None or a non-negative integer, but value `` was given."; 74 | MongoWriteConcernCreate::concern = 75 | "The first argument must be a positive integer or 0, but `` was given."; 76 | 77 | Options[MongoWriteConcernCreate] = 78 | { 79 | "Journal" -> True, 80 | "Timeout" -> None 81 | }; 82 | 83 | MongoWriteConcernCreate[concern_Integer:1, opts:OptionsPattern[]] := 84 | CatchFailureAsMessage @ Module[ 85 | {handle, journal, timeout} 86 | , 87 | (** Options Parsing **) 88 | {journal, timeout} = OptionValue[{"Journal", "Timeout"}]; 89 | If[!BooleanQ[journal], 90 | ThrowFailure[MongoWriteConcernCreate::journal, journal]; 91 | ]; 92 | If[Not @ ((timeout === None) || (IntegerQ[timeout] && Positive[timeout])), 93 | ThrowFailure[MongoWriteConcernCreate::timeout, timeout]; 94 | ]; 95 | If[!IntegerQ[concern] || (concern < 0), 96 | ThrowFailure[MongoWriteConcernCreate::concern, concern]; 97 | ]; 98 | 99 | handle = CreateManagedLibraryExpression["WriteConcern", writeConcernMLE]; 100 | safeLibraryInvoke[writeConcernNew, getMLEID[handle]]; 101 | safeLibraryInvoke[WriteConcernSet, getMLEID[handle], concern]; 102 | safeLibraryInvoke[ 103 | WriteConcernSetJournal, 104 | getMLEID[handle], 105 | Boole[journal] 106 | ]; 107 | 108 | If[timeout =!= None, 109 | safeLibraryInvoke[WriteConcernSetWtimeout, getMLEID[handle], timeout] 110 | ]; 111 | (* Return handle to write concern *) 112 | MongoWriteConcern[handle] 113 | ] 114 | -------------------------------------------------------------------------------- /MongoLink/Kernel/init.m: -------------------------------------------------------------------------------- 1 | Package["MongoLink`"] -------------------------------------------------------------------------------- /MongoLink/PacletInfo.m: -------------------------------------------------------------------------------- 1 | Paclet[ 2 | Name -> "MongoLink", 3 | Version -> "12.1", 4 | MathematicaVersion -> "11.1+", 5 | Description -> "Link to MongoDB C driver.", 6 | Loading -> Automatic, 7 | Creator -> 8 | "Meghan Rieu-Werden , Sebastian Bodenstein ", 9 | Extensions -> { 10 | {"Kernel", Context -> "MongoLink`"}, 11 | {"Documentation", Resources -> {}, 12 | Language -> All 13 | }, 14 | {"LibraryLink"} 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /Notes/DeveloperNotes.md: -------------------------------------------------------------------------------- 1 | # MongoLink Developer Notes 2 | 3 | ## Objects 4 | There are lots of objects, `MongoClient`, `MongoCollection`, etc. 5 | 6 | - The first element of the object is always the ManagedLibraryExpression object: `MongoClient[MLE Object, ...]`, etc. 7 | 8 | ### Lifetimes and Objects 9 | 10 | -------------------------------------------------------------------------------- /Notes/LocalBuild.nb: -------------------------------------------------------------------------------- 1 | (* Content-type: application/vnd.wolfram.mathematica *) 2 | 3 | (*** Wolfram Notebook File ***) 4 | (* http://www.wolfram.com/nb *) 5 | 6 | (* CreatedBy='Mathematica 11.3' *) 7 | 8 | (*CacheID: 234*) 9 | (* Internal cache information: 10 | NotebookFileLineBreakTest 11 | NotebookFileLineBreakTest 12 | NotebookDataPosition[ 158, 7] 13 | NotebookDataLength[ 3591, 109] 14 | NotebookOptionsPosition[ 2436, 78] 15 | NotebookOutlinePosition[ 2861, 96] 16 | CellTagsIndexPosition[ 2818, 93] 17 | WindowFrame->Normal*) 18 | 19 | (* Beginning of Notebook Content *) 20 | Notebook[{ 21 | Cell[BoxData[" "], "Input",ExpressionUUID->"c05194cd-3b69-47ec-8374-1fc16048b6e9"], 22 | 23 | Cell[CellGroupData[{ 24 | 25 | Cell["MongoLink Local Build", "Title",ExpressionUUID->"d2dc8c5f-0a1b-434f-85cf-bfdce52a8646"], 26 | 27 | Cell["This is a build script for MongoLink.", "Text",ExpressionUUID->"3b6c8047-89c7-496c-8c6f-5bd5b618214f"], 28 | 29 | Cell[CellGroupData[{ 30 | 31 | Cell[BoxData[{ 32 | RowBox[{"Get", " ", "@", " ", 33 | RowBox[{"FileNameJoin", "[", 34 | RowBox[{"{", 35 | RowBox[{ 36 | RowBox[{"ParentDirectory", " ", "@", " ", 37 | RowBox[{"NotebookDirectory", "[", "]"}]}], ",", " ", 38 | "\"\\"", ",", " ", "\"\\""}], "}"}], 39 | "]"}]}], "\n", 40 | RowBox[{"BuildMongoLink", "[", 41 | RowBox[{"\"\\"", " ", "\[Rule]", " ", "True"}], "]"}]}], "Code",Expr\ 42 | essionUUID->"23c9956c-17f5-43be-8bdf-a2bbd57e3966"], 43 | 44 | Cell[BoxData[ 45 | RowBox[{"{", 46 | RowBox[{"\<\"/Users/sebastianb/Library/Mathematica/SystemFiles/\ 47 | LibraryResources/MacOSX-x86-64/MongoLink.dylib\"\>", ",", "None"}], 48 | "}"}]], "Output",ExpressionUUID->"e9020994-a115-4ac8-b13d-658fafaebbf2"] 49 | }, Open ]], 50 | 51 | Cell[CellGroupData[{ 52 | 53 | Cell["Test", "Subsection",ExpressionUUID->"de3db07e-9885-4c59-858e-b2bf322ec41d"], 54 | 55 | Cell[CellGroupData[{ 56 | 57 | Cell[BoxData[{ 58 | RowBox[{ 59 | RowBox[{"PacletDirectoryAdd", "[", 60 | RowBox[{"{", 61 | RowBox[{"ParentDirectory", " ", "@", " ", 62 | RowBox[{"NotebookDirectory", "[", "]"}]}], "}"}], "]"}], 63 | ";"}], "\[IndentingNewLine]", 64 | RowBox[{"<<", "MongoLink`"}], "\[IndentingNewLine]", 65 | RowBox[{"Normal", "@", 66 | RowBox[{"ToBSON", "@", 67 | RowBox[{"<|", 68 | RowBox[{"\"\\"", "\[Rule]", "3"}], "|>"}]}]}]}], "Input",ExpressionUUI\ 69 | D->"a55772c2-6b6a-4696-b371-2dc2fc6f493c"], 70 | 71 | Cell[BoxData[ 72 | RowBox[{"\[LeftAssociation]", 73 | RowBox[{"\<\"a\"\>", "\[Rule]", "3"}], "\[RightAssociation]"}]], "Output",Ex\ 74 | pressionUUID->"e9d3d2ed-a143-4456-b238-37c366cd0247"] 75 | }, Open ]] 76 | }, Open ]] 77 | }, Open ]] 78 | }, 79 | InitializationCellEvaluation->False, 80 | WindowSize->{1285, 788}, 81 | WindowMargins->{{122, Automatic}, {Automatic, 81}}, 82 | Magnification:>1.5 Inherited, 83 | FrontEndVersion->"11.2 for Mac OS X x86 (32-bit, 64-bit Kernel) (August 26, \ 84 | 2017)", 85 | StyleDefinitions->"Default.nb" 86 | ] 87 | (* End of Notebook Content *) 88 | 89 | (* Internal cache information *) 90 | (*CellTagsOutline 91 | CellTagsIndex->{} 92 | *) 93 | (*CellTagsIndex 94 | CellTagsIndex->{} 95 | *) 96 | (*NotebookFileOutline 97 | Notebook[{ 98 | Cell[558, 20, 82, 0, 46, "Input",ExpressionUUID->"c05194cd-3b69-47ec-8374-1fc16048b6e9"], 99 | Cell[CellGroupData[{ 100 | Cell[665, 24, 93, 0, 146, "Title",ExpressionUUID->"d2dc8c5f-0a1b-434f-85cf-bfdce52a8646"], 101 | Cell[761, 26, 108, 0, 53, "Text",ExpressionUUID->"3b6c8047-89c7-496c-8c6f-5bd5b618214f"], 102 | Cell[CellGroupData[{ 103 | Cell[894, 30, 466, 11, 108, "Code",ExpressionUUID->"23c9956c-17f5-43be-8bdf-a2bbd57e3966"], 104 | Cell[1363, 43, 239, 4, 84, "Output",ExpressionUUID->"e9020994-a115-4ac8-b13d-658fafaebbf2"] 105 | }, Open ]], 106 | Cell[CellGroupData[{ 107 | Cell[1639, 52, 81, 0, 81, "Subsection",ExpressionUUID->"de3db07e-9885-4c59-858e-b2bf322ec41d"], 108 | Cell[CellGroupData[{ 109 | Cell[1745, 56, 469, 12, 109, "Input",ExpressionUUID->"a55772c2-6b6a-4696-b371-2dc2fc6f493c"], 110 | Cell[2217, 70, 179, 3, 52, "Output",ExpressionUUID->"e9d3d2ed-a143-4456-b238-37c366cd0247"] 111 | }, Open ]] 112 | }, Open ]] 113 | }, Open ]] 114 | } 115 | ] 116 | *) 117 | 118 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MongoDB Link for the Wolfram Language 2 | 3 | MongoLink is a package for interacting with MongoDB inside the [Wolfram Language](https://www.wolfram.com/language/). It interfaces to the [MongoDB C driver.](https://docs.mongodb.org/ecosystem/drivers/c/) via LibraryLink. 4 | 5 | The design aims to follow the official Mongo API reference (https://docs.mongodb.com/manual/reference/), along with trying to use standard Wolfram Language conventions and options. 6 | 7 | Not all functionality in MongoDB is exposed in MongoLink. If you want something that is missing, please request it in the Github Issues. Or better yet, make a PR! 8 | 9 | ### Installing the MongoLink release 10 | 11 | The MongoLink release comes in the form of a `.paclet` file, which contains the entire package and its documentation. Download the latest release from the [Github repo's releases page](https://github.com/WolframResearch/MongoLink/releases). To install, run the following command in the Wolfram Language: 12 | ``` 13 | PacletInstall["/full/path/to/MongoLink.paclet"] 14 | ``` 15 | This will permanently install the MongoLink paclet. The Wolfram Language will always use the latest installed version of MongoLink. Installed versions can be enumerated using the command: 16 | ``` 17 | PacletFind["MongoLink"] 18 | ``` 19 | And all versions can be uninstalled using the command: 20 | ``` 21 | PacletUninstall["MongoLink"] 22 | ``` 23 | 24 | ### Using MongoLink 25 | 26 | To access the documentation, open the notebook interface help viewer, and search for `MongoLink`. 27 | 28 | ### Where did this come from? 29 | 30 | MongoLink is a paclet started and maintained by Sebastian Bodenstein of Wolfram Research. It is used within Wolfram Research by the Machine Learning Group to manage large machine learning datasets. 31 | 32 | ### Acknowledgements 33 | 34 | Much of the documentation was adapted and/or copied from the excellent [PyMongo](https://api.mongodb.com/python/current/) and [MongoDB C Driver](http://mongoc.org/libmongoc/current/index.html) documentation. 35 | 36 | ### More... 37 | 38 | See the following files for more information: 39 | 40 | * [COPYING.md](COPYING.md) - MongoLink license 41 | * [CONTRIBUTING.md](CONTRIBUTING.md) - Guidelines for contributing to MongoLink 42 | * [HowToBuild.md](HowToBuild.md) - Instructions for building MongoLink -------------------------------------------------------------------------------- /Tests/BSON.wlt: -------------------------------------------------------------------------------- 1 | BeginTestSection["BSON"] 2 | 3 | assoc = <|"hello" -> {1, 2.5, 3.}|>; 4 | json = "{ \"hello\" : [ 1, 2.5, 3.0 ] }"; 5 | bson1 = ToBSON[<|"hello" -> {1, 2.5, 3.}|>]; 6 | 7 | (*----------------------------------------------------------------------------*) 8 | (* Conversion Functions *) 9 | 10 | (* raw array conversion *) 11 | 12 | VerificationTest[ 13 | BSONToRawArray[bson1], 14 | (_NumericArray | _RawArray), 15 | TestID -> "BSON to raw array", 16 | SameTest -> MatchQ 17 | ] 18 | 19 | VerificationTest[ 20 | BSONToJSON @ ToBSON[BSONToRawArray[bson1]], 21 | BSONToJSON @ bson1, 22 | TestID -> "BSON to RawArray to JSON" 23 | ] 24 | 25 | (* byte array conversion 1 *) 26 | 27 | VerificationTest[ 28 | BSONToByteArray[bson1], 29 | _ByteArray, 30 | TestID -> "BSON to byte array", 31 | SameTest -> MatchQ 32 | ] 33 | 34 | VerificationTest[ 35 | BSONToJSON @ ToBSON[BSONToByteArray[bson1]], 36 | BSONToJSON @ bson1, 37 | TestID -> "BSON to ByteArray to JSON v1" 38 | ] 39 | 40 | (* byte array conversion 2 *) 41 | 42 | VerificationTest[ 43 | ByteArray[bson1], 44 | BSONToByteArray[bson1], 45 | TestID -> "ByteArray same as BSONToByteArray" 46 | ] 47 | 48 | VerificationTest[ 49 | BSONToJSON @ ToBSON[ByteArray[bson1]], 50 | BSONToJSON @ bson1, 51 | TestID -> "BSON to ByteArray to JSON v2" 52 | ] 53 | 54 | (* byte array association *) 55 | 56 | VerificationTest[ 57 | BSONToAssociation[bson1], 58 | _Association, 59 | TestID -> "BSON to assoc", 60 | SameTest -> MatchQ 61 | ] 62 | 63 | VerificationTest[ 64 | BSONToJSON @ ToBSON[BSONToAssociation[bson1]], 65 | BSONToJSON @ bson1, 66 | TestID -> "BSON to expression to JSON" 67 | ] 68 | 69 | (*----------------------------------------------------------------------------*) 70 | (* ToBSON *) 71 | 72 | (*ToBSON for associations*) 73 | VerificationTest[ 74 | ToBSON[assoc], 75 | _BSONObject, 76 | TestID -> "Assocation to BSON", 77 | SameTest -> MatchQ 78 | ] 79 | 80 | (*ToBSON for JSON*) 81 | 82 | VerificationTest[ 83 | ToBSON[json], 84 | _BSONObject, 85 | TestID -> "JSON to BSON", 86 | SameTest -> MatchQ 87 | ] 88 | 89 | (*----------------------------------------------------------------------------*) 90 | (* BSONObjectID *) 91 | 92 | VerificationTest[ 93 | Normal@BSONObjectID["666f6f2d6261722d71757578"], 94 | _Dataset, 95 | TestID -> "BSONObjectID returns association", 96 | SameTest -> MatchQ 97 | ] 98 | 99 | (*----------------------------------------------------------------------------*) 100 | (* BSONObject *) 101 | 102 | VerificationTest[ 103 | Normal@ToBSON[assoc], 104 | BSONToAssociation[ToBSON[assoc]], 105 | TestID -> "BSONObject//Normal returns same as BSONtoExpression" 106 | ] 107 | 108 | (*----------------------------------------------------------------------------*) 109 | (* Round Trip *) 110 | 111 | VerificationTest[ 112 | assoc, 113 | BSONToAssociation@ToBSON@BSONToJSON@ToBSON@BSONToByteArray@ToBSON@BSONToRawArray@ToBSON@assoc, 114 | TestID -> "Association round trip" 115 | ] 116 | 117 | (*----------------------------------------------------------------------------*) 118 | (* BSON Extended Types: 119 | https://docs.mongodb.com/manual/reference/mongodb-extended-json/ 120 | *) 121 | 122 | 123 | 124 | 125 | (*----------------------------------------------------------------------------*) 126 | 127 | EndTestSection[] 128 | -------------------------------------------------------------------------------- /Tests/Certificates/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC9DCCAl2gAwIBAgIJAJeYVdtunBOmMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD 3 | VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp 4 | dHkxDjAMBgNVBAoMBTEwR2VuMQ8wDQYDVQQLDAZLZXJuZWwxGjAYBgNVBAMMEU15 5 | IENlcnQgQXV0aG9yaXR5MRswGQYJKoZIhvcNAQkBFgxyb290QGxhemFydXMwHhcN 6 | MTIxMTI3MTkwMzM5WhcNMTMxMTI3MTkwMzM5WjCBkjELMAkGA1UEBhMCVVMxETAP 7 | BgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYDVQQK 8 | DAUxMEdlbjEPMA0GA1UECwwGS2VybmVsMRowGAYDVQQDDBFNeSBDZXJ0IEF1dGhv 9 | cml0eTEbMBkGCSqGSIb3DQEJARYMcm9vdEBsYXphcnVzMIGfMA0GCSqGSIb3DQEB 10 | AQUAA4GNADCBiQKBgQDXHKZ5j5T969S5C/Gm6f2ah7gaik3zRzWm2ZoAcz/U6fBq 11 | rnha3bueXXBRWZ7d2HgN1a+JhjuYnffcdUSen9CFVxPiRCEgJmp2A8o90Kx5Bbcf 12 | 7zHobDOGs1EF3PQ2RKgXEOUjKZ/LZDbGhClsIYCD4SdFhRMqUcxc2lQMsWEaNwID 13 | AQABo1AwTjAdBgNVHQ4EFgQUB0EZOp9+xbciTre81d/k/Am4ZBYwHwYDVR0jBBgw 14 | FoAUB0EZOp9+xbciTre81d/k/Am4ZBYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B 15 | AQUFAAOBgQB6aSQNTmD4gIQEcZiOXHJVpGOHeHBOxWteMFhcBpWvt0Cv8sqLZIVq 16 | x0eAC/tQFkAVEjT+T4S4UdtxgZ44RKCZPYI00qZsyz5bNoTE8kN/bmYNjyKMVFaG 17 | 1tU+elCdOstzBLjY1aHG1oQzbyqgoiSIDpfzjlyK/tBpckFGCz6c6A== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /Tests/Certificates/client.pem: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 7 (0x7) 5 | Signature Algorithm: sha1WithRSAEncryption 6 | Issuer: C=US, ST=New York, L=New York City, O=10Gen, OU=Kernel, CN=My Cert Authority/emailAddress=root@lazarus 7 | Validity 8 | Not Before: Aug 23 14:55:32 2013 GMT 9 | Not After : Jan 7 14:55:32 2041 GMT 10 | Subject: C=US, ST=New York, L=New York City, O=10Gen, OU=kerneluser, CN=client 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:ba:16:42:d4:8b:3d:5e:8a:67:9e:a7:c0:cd:4a: 16 | 9c:9c:fd:95:b9:83:bf:f4:cf:03:8c:2e:db:a9:c1: 17 | 35:58:80:f6:e2:e9:87:28:84:e3:d0:9b:68:60:51: 18 | 0e:42:84:d8:6f:e8:34:cc:18:97:79:d3:8d:d8:2f: 19 | 23:11:25:6f:69:7a:38:bb:8c:b2:29:e9:91:be:79: 20 | 8c:cc:1b:56:98:98:d3:83:2a:c5:f9:9c:86:0c:2c: 21 | 24:0e:5c:46:3b:a9:95:44:6c:c5:e0:7c:9d:03:ae: 22 | 0d:23:99:49:a4:48:dd:0e:35:a2:e5:b4:8b:86:bd: 23 | c0:c8:ce:d5:ac:c4:36:f3:9e:5f:17:00:23:8d:53: 24 | a1:43:1b:a3:61:96:36:80:4d:35:50:b5:8b:69:31: 25 | 39:b4:63:8b:96:59:5c:d1:ea:92:eb:eb:fa:1b:35: 26 | 64:44:b3:f6:f3:a6:9d:49:3a:59:e5:e1:c2:cb:98: 27 | be:29:b3:22:dd:33:97:d7:50:4f:db:c2:58:64:18: 28 | b5:8c:3c:6b:2d:21:f6:bd:8d:e5:d2:da:8d:79:fe: 29 | a7:80:75:a8:15:b9:ee:79:7f:01:31:1d:e5:e7:15: 30 | 76:53:65:f6:fe:f0:93:7d:20:3d:cc:ff:9b:ca:b2: 31 | 50:2c:1b:3a:69:d5:e6:70:cf:ac:be:7e:5c:33:c4: 32 | 6e:a7 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Basic Constraints: 36 | CA:FALSE 37 | Netscape Comment: 38 | OpenSSL Generated Certificate 39 | X509v3 Subject Key Identifier: 40 | 4A:8B:EE:22:42:E6:F8:62:4C:86:38:8D:C5:78:95:98:C1:10:05:7C 41 | X509v3 Authority Key Identifier: 42 | keyid:07:41:19:3A:9F:7E:C5:B7:22:4E:B7:BC:D5:DF:E4:FC:09:B8:64:16 43 | 44 | Signature Algorithm: sha1WithRSAEncryption 45 | 13:13:a8:f0:de:78:c6:b1:e0:85:cc:27:e6:04:28:44:93:1d: 46 | f1:ff:5e:81:69:33:1f:f3:76:e0:49:ca:d9:ad:aa:db:f5:a5: 47 | f8:a6:50:bb:a1:a7:40:14:e4:2f:8d:b8:21:7f:35:04:60:db: 48 | af:f0:9e:dd:a1:ca:0b:7f:03:2e:2f:19:1e:32:6e:1e:2d:87: 49 | 68:e3:37:47:a8:5b:93:d1:88:41:73:da:88:21:59:27:d4:35: 50 | 1c:6a:27:b5:c0:c6:17:ba:f3:87:c8:e1:f4:8f:43:12:bc:fa: 51 | 8d:90:d5:86:83:df:51:a5:c9:e0:92:f0:66:d0:37:61:6f:85: 52 | 24:18 53 | -----BEGIN CERTIFICATE----- 54 | MIIDdjCCAt+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCVVMx 55 | ETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYD 56 | VQQKDAUxMEdlbjEPMA0GA1UECwwGS2VybmVsMRowGAYDVQQDDBFNeSBDZXJ0IEF1 57 | dGhvcml0eTEbMBkGCSqGSIb3DQEJARYMcm9vdEBsYXphcnVzMB4XDTEzMDgyMzE0 58 | NTUzMloXDTQxMDEwNzE0NTUzMlowbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5l 59 | dyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MQ4wDAYDVQQKDAUxMEdlbjET 60 | MBEGA1UECwwKa2VybmVsdXNlcjEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG 61 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuhZC1Is9XopnnqfAzUqcnP2VuYO/9M8DjC7b 62 | qcE1WID24umHKITj0JtoYFEOQoTYb+g0zBiXedON2C8jESVvaXo4u4yyKemRvnmM 63 | zBtWmJjTgyrF+ZyGDCwkDlxGO6mVRGzF4HydA64NI5lJpEjdDjWi5bSLhr3AyM7V 64 | rMQ2855fFwAjjVOhQxujYZY2gE01ULWLaTE5tGOLlllc0eqS6+v6GzVkRLP286ad 65 | STpZ5eHCy5i+KbMi3TOX11BP28JYZBi1jDxrLSH2vY3l0tqNef6ngHWoFbnueX8B 66 | MR3l5xV2U2X2/vCTfSA9zP+byrJQLBs6adXmcM+svn5cM8RupwIDAQABo3sweTAJ 67 | BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0 68 | aWZpY2F0ZTAdBgNVHQ4EFgQUSovuIkLm+GJMhjiNxXiVmMEQBXwwHwYDVR0jBBgw 69 | FoAUB0EZOp9+xbciTre81d/k/Am4ZBYwDQYJKoZIhvcNAQEFBQADgYEAExOo8N54 70 | xrHghcwn5gQoRJMd8f9egWkzH/N24EnK2a2q2/Wl+KZQu6GnQBTkL424IX81BGDb 71 | r/Ce3aHKC38DLi8ZHjJuHi2HaOM3R6hbk9GIQXPaiCFZJ9Q1HGontcDGF7rzh8jh 72 | 9I9DErz6jZDVhoPfUaXJ4JLwZtA3YW+FJBg= 73 | -----END CERTIFICATE----- 74 | -----BEGIN PRIVATE KEY----- 75 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6FkLUiz1eimee 76 | p8DNSpyc/ZW5g7/0zwOMLtupwTVYgPbi6YcohOPQm2hgUQ5ChNhv6DTMGJd5043Y 77 | LyMRJW9peji7jLIp6ZG+eYzMG1aYmNODKsX5nIYMLCQOXEY7qZVEbMXgfJ0Drg0j 78 | mUmkSN0ONaLltIuGvcDIztWsxDbznl8XACONU6FDG6NhljaATTVQtYtpMTm0Y4uW 79 | WVzR6pLr6/obNWREs/bzpp1JOlnl4cLLmL4psyLdM5fXUE/bwlhkGLWMPGstIfa9 80 | jeXS2o15/qeAdagVue55fwExHeXnFXZTZfb+8JN9ID3M/5vKslAsGzpp1eZwz6y+ 81 | flwzxG6nAgMBAAECggEBALYw92urjAFVFxCiA8W7aEzYhtAkaztft4R3mD/C19z4 82 | H0CZDeig+3+RuIactY5xDIu8WHz/EseHVlg0BmxSL5ugu4z8uq8IbNaFoVFw7r7m 83 | 2ieRKFY0ZpXiXcbllynw5iEhMjeRKhWhQmH5Qb2kTTINV5j4xKa+f9Lblx7Y2Uh4 84 | tsaOtlMwb98D2/KYJdTv5Nj1nyuSqRVhECsd00Cb6JUBGQBx8Ja0wFy9gEygq6kU 85 | w3s1XNOSnYNEo4FaVZwp5KZyCyBENcKpNUq4nXt/7ncEfVYdJck0Li3wN4Jr2J9S 86 | eHqRzh8QkHxc1Ro8ktcXaUSs9kFuwvVvb4rcGUpOMWkCgYEA9xxp8yDtFVgzMtc/ 87 | vS8xgM1Wj4SrgKKYhE2wS05BJh/41oFMzfH1FpZ1GCM983r4QgYWoT71XsBgiOMC 88 | yN2p2IbV4V44bMGKJqaVMkB91CVCUWI6piaCQb/1CJTwaXE7zPim6dlUSxxBBnRn 89 | LP50NTscRLFcCZELD3Yl7jR8XFUCgYEAwMfkNFmGtBKAwlHZ3Y3XOwPWg+jCll7s 90 | 9nhv8TU2IB9pcCRGqyOT7k1YymvYkDT2Je4JUPWEBs4cW7yD61LrQ8w8+DrE9dGo 91 | czzGPyjOAANSX0asG74UjkNIQThmyEOltVHIxYMaSqowjHRSPdA+R4Od9EdcDdfS 92 | q5SfSVFxmwsCgYBtl1thqUOcCL7EGHQ7KdfxgJ+YDMWmyfWMD4xVCYKZLurD7xop 93 | 59nDR7zslIygE/RQC7Uzk+FsQTNO4ibVAIGX9syaI5gwm3DyjURzwehMEq4ju8W4 94 | 9DEmicRZJvysNrzHvasA4RKiMQihnTQ43yyYgvuZd3MTBxF5rPNLfll89QKBgQC9 95 | SsmiOZIR+OUjaTmS2bbQBNm7Fm8TNcxZyzKn1wb5jb57VbNqUfnskVgxEqpIFyjn 96 | X48YRqtH/1RLI5UpGXdXUBFB8Hr7oM1VsgQ7ejakPp7AXOWcLA2FDz3AhMAvvnTU 97 | 0KRihHPpgqk/EOy8M2Ej2XHcrcEO+q+quLmbRXRWtwKBgHacQiwci/2J+v0e9i52 98 | re/2AJHKP5MwNHFe1e01iNc5EEN0G+/Ut8XW19DWf6bsxqie0ChC+xN8TUst8alT 99 | F+tXTsHHmt/lRcjTROjT5XVuoqjtU2Q0QeVeGLgvObso+fZy3ZNeQuSJjWukdMZ3 100 | 57rGT6p0OuM8qbrTzpv3JMrm 101 | -----END PRIVATE KEY----- 102 | -------------------------------------------------------------------------------- /Tests/RunTests.nb: -------------------------------------------------------------------------------- 1 | Notebook[{ 2 | 3 | Cell[CellGroupData[{ 4 | Cell["RunTests", \ 5 | "Title",ExpressionUUID->"d769145f-c440-4a77-b886-4d6ad721b9ee"], 6 | 7 | Cell[BoxData[{ 8 | RowBox[{ 9 | RowBox[{"PacletDirectoryAdd", "[", 10 | RowBox[{"{", 11 | RowBox[{"ParentDirectory", "[", 12 | RowBox[{"NotebookDirectory", "[", "]"}], "]"}], "}"}], "]"}], 13 | ";"}], "\[IndentingNewLine]", 14 | RowBox[{"<<", "MongoLink`"}], "\[IndentingNewLine]", 15 | RowBox[{"Get", "[", 16 | RowBox[{"FileNameJoin", "[", 17 | RowBox[{"{", 18 | RowBox[{ 19 | RowBox[{"NotebookDirectory", "[", "]"}], ",", 20 | "\"\\""}], "}"}], "]"}], 21 | "]"}]}], "Input",ExpressionUUID->"4fda19a9-2056-42fc-9758-43720ed701af"], 22 | 23 | Cell["\<\ 24 | Run one test for a specific file and print only failed tests:\ 25 | \>", "Item",ExpressionUUID->"b8d925e6-93f0-484b-9281-105b3fd87463"], 26 | 27 | Cell[CellGroupData[{ 28 | 29 | Cell[BoxData[ 30 | RowBox[{"runOneTest", "[", 31 | RowBox[{"\"\\"", ",", 32 | RowBox[{"NotebookDirectory", "[", "]"}]}], 33 | "]"}]], "Input",ExpressionUUID->"cf478c91-be70-478d-abbb-a30732a4f4cc"], 34 | 35 | Cell[BoxData["\<\"Success!\"\>"], \ 36 | "Output",ExpressionUUID->"1131cf31-03ff-47c6-8208-3f29c1006b95"] 37 | }, Open ]], 38 | 39 | Cell["Run all tests, and print only failed tests:", \ 40 | "Item",ExpressionUUID->"d0000433-65a4-4aaa-98c7-cf179be3f2e7"], 41 | 42 | Cell[CellGroupData[{ 43 | 44 | Cell[BoxData[ 45 | RowBox[{"runAllTests", "[", 46 | "]"}]], "Input",ExpressionUUID->"6993456a-003b-4fee-b68b-93f720c7dffa"], 47 | 48 | Cell[BoxData["\<\"BSON.wlt\"\>"], \ 49 | "Print",ExpressionUUID->"f69e5ab2-c63d-42fe-ab59-c3b5c4e55c79"], 50 | 51 | Cell[BoxData["\<\"Success!\"\>"], \ 52 | "Output",ExpressionUUID->"7cc04c80-db38-425a-99ab-2375273ded11"] 53 | }, Open ]] 54 | }, Open ]] 55 | }, 56 | WindowSize->{1720, 1328}, 57 | WindowMargins->{{Automatic, 0}, {Automatic, 0}}, 58 | FrontEndVersion->"11.1 for Mac OS X x86 (32-bit, 64-bit Kernel) (April 18, \ 59 | 2017)", 60 | StyleDefinitions->"Default.nb" 61 | ] 62 | 63 | -------------------------------------------------------------------------------- /Tests/RunTestsCommon.m: -------------------------------------------------------------------------------- 1 | (* auxiliary test functions *) 2 | 3 | runOneTestTF[file_String, dir_String] := Module[ 4 | {success = True, report, failed, ffile = FileNameJoin[{dir, file}]} 5 | , 6 | If[Not@FileExistsQ[ffile], 7 | Print[">>> Test file ", ffile, " does not exist"]; 8 | Return[False] 9 | ]; 10 | report = TestReport[ffile]; 11 | If[Not@report["AllTestsSucceeded"], 12 | success = False; 13 | Print[">>> Tests failed: ", report["TestsFailedIndices"]]; 14 | failed = report["TestsFailedWrongResults"]; 15 | Print[Map[#[{"ExpectedOutput", "ActualOutput"}] &, failed]]; 16 | ]; 17 | success 18 | ]; 19 | 20 | runOneTest[file_String, dir_String] := 21 | If[runOneTestTF[file, dir], "Success!", "Failures!"]; 22 | 23 | runAllTests[] := Module[ 24 | {success, files, i} 25 | , 26 | files = FileNames["*.wlt", NotebookDirectory[], Infinity]; 27 | success = True; 28 | Do[ 29 | Print[FileNameTake@files[[i]]]; 30 | success = And[success, runOneTestTF[files[[i]], ""]]; 31 | , 32 | {i, Length@files} 33 | ]; 34 | If[success, "Success!", "Failures!"] 35 | ]; 36 | 37 | -------------------------------------------------------------------------------- /scripts/re_build_MongoLink.wl: -------------------------------------------------------------------------------- 1 | Needs["CCompilerDriver`"]; 2 | 3 | $MongoLink = FileNameJoin[{DirectoryName[$InputFileName], "..", "Libraries", "MongoLink"}]; 4 | 5 | $MathLink = FileNameJoin[{AntProperty["checkout_directory"], "MathLink", "CompilerAdditions"}]; 6 | $MongoC = FileNameJoin[{AntProperty["checkout_directory"], "MongoC"}]; 7 | $RuntimeLibrary = FileNameJoin[{AntProperty["checkout_directory"], "RuntimeLibrary", AntProperty["system_id"]}]; 8 | 9 | $MongoLinkLib = CreateLibrary[ 10 | 11 | FileNames["*.cpp", {$MongoLink}], 12 | "MongoLink", 13 | 14 | "CleanIntermediate" -> True, 15 | 16 | "CompileOptions" -> 17 | Switch[$OperatingSystem, 18 | "MacOSX", "-std=c++11 -O0", 19 | "Unix", "-std=c++11 -fvisibility=hidden", 20 | "Windows", "/EHsc" 21 | ], 22 | 23 | "CompilerInstallation" -> 24 | Switch[$OperatingSystem, 25 | "MacOSX", Automatic, 26 | _, Environment["COMPILER_INSTALLATION"] 27 | ], 28 | 29 | "IncludeDirectories"-> { 30 | $MongoLink, 31 | FileNameJoin[{$MongoC, "include", "libmongoc-1.0"}], 32 | FileNameJoin[{$MongoC, "include", "libbson-1.0"}] 33 | }, 34 | 35 | "Language" -> "C++", 36 | 37 | "Libraries" -> Switch[$OperatingSystem, 38 | "MacOSX", 39 | {"mongoc-1.0.0", "bson-1.0.0"}, 40 | "Unix" /; $ProcessorType == "ARM", 41 | {"mongoc-1.0", "bson-1.0"}, 42 | "Unix", 43 | {"mongoc-1.0", "bson-1.0", "stdc++_nonshared"}, 44 | "Windows", 45 | {"mongoc-1.0", "bson-1.0"} 46 | ], 47 | 48 | "LibraryDirectories" -> { 49 | FileNameJoin[{$MongoC, "lib"}] 50 | }, 51 | 52 | "LinkerOptions" -> 53 | Switch[$OperatingSystem, 54 | "MacOSX", {"-install_name", "@rpath/MongoLink.dylib", "-rpath", "@loader_path/"}, 55 | "Unix", {"--enable-new-dtags", "-rpath='$ORIGIN'"}, 56 | _, {} 57 | ], 58 | 59 | "ShellCommandFunction" -> Global`AntLog, 60 | "ShellOutputFunction" -> Global`AntLog, 61 | 62 | "SystemIncludeDirectories" -> { 63 | FileNameJoin[{$MathLink}], 64 | $RuntimeLibrary 65 | }, 66 | 67 | "SystemLibraryDirectories" -> Switch[$OperatingSystem, 68 | "MacOSX", 69 | { 70 | "-F" <> $MathLink, 71 | $RuntimeLibrary 72 | }, 73 | _, 74 | { 75 | $MathLink, 76 | $RuntimeLibrary 77 | } 78 | ], 79 | 80 | "TargetDirectory" -> FileNameJoin[{AntProperty["files_directory"], AntProperty["component"], "LibraryResources", AntProperty["system_id"]}], 81 | "TargetSystemID" -> AntProperty["system_id"], 82 | 83 | "WorkingDirectory" -> AntProperty["scratch_directory"] 84 | ]; 85 | 86 | If[FailureQ[$MongoLinkLib], AntFail["Library was not generated."]]; 87 | -------------------------------------------------------------------------------- /scripts/re_build_MongoLink.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | paclet version == "${v}" 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 108 | 109 | 110 | 111 | 112 | --------------------------------------------------------------------------------