11use std:: time:: Duration ;
22
3- use bson:: { Bson , Document } ;
3+ use bson:: { Bson , Document , RawDocumentBuf } ;
44
55use crate :: {
66 client:: session:: TransactionState ,
@@ -9,19 +9,11 @@ use crate::{
99 error:: { ErrorKind , Result } ,
1010 operation:: { run_command, run_cursor_command} ,
1111 selection_criteria:: SelectionCriteria ,
12- ClientSession ,
13- Cursor ,
14- Database ,
15- SessionCursor ,
12+ ClientSession , Cursor , Database , SessionCursor ,
1613} ;
1714
1815use super :: {
19- action_impl,
20- deeplink,
21- export_doc,
22- option_setters,
23- options_doc,
24- ExplicitSession ,
16+ action_impl, deeplink, export_doc, option_setters, options_doc, ExplicitSession ,
2517 ImplicitSession ,
2618} ;
2719
@@ -46,6 +38,26 @@ impl Database {
4638 }
4739 }
4840
41+ /// Runs a database-level command.
42+ ///
43+ /// Note that no inspection is done on `doc`, so the command will not use the database's default
44+ /// read concern or write concern. If specific read concern or write concern is desired, it must
45+ /// be specified manually.
46+ /// Please note that run_command doesn't validate WriteConcerns passed into the body of the
47+ /// command document.
48+ ///
49+ /// `await` will return d[`Result<Document>`].
50+ #[ deeplink]
51+ #[ options_doc( run_command) ]
52+ pub fn raw_run_command ( & self , command : RawDocumentBuf ) -> RawRunCommand {
53+ RawRunCommand {
54+ db : self ,
55+ command,
56+ options : None ,
57+ session : None ,
58+ }
59+ }
60+
4961 /// Runs a database-level command and returns a cursor to the response.
5062 ///
5163 /// `await` will return d[`Result<Cursor<Document>>`] or a
@@ -152,6 +164,68 @@ impl<'a> Action for RunCommand<'a> {
152164 }
153165}
154166
167+ /// Run a database-level command. Create with [`Database::run_command`].
168+ #[ must_use]
169+ pub struct RawRunCommand < ' a > {
170+ db : & ' a Database ,
171+ command : RawDocumentBuf ,
172+ options : Option < RunCommandOptions > ,
173+ session : Option < & ' a mut ClientSession > ,
174+ }
175+
176+ #[ option_setters( crate :: db:: options:: RunCommandOptions ) ]
177+ #[ export_doc( run_raw_command) ]
178+ impl < ' a > RawRunCommand < ' a > {
179+ /// Run the command using the provided [`ClientSession`].
180+ pub fn session ( mut self , value : impl Into < & ' a mut ClientSession > ) -> Self {
181+ self . session = Some ( value. into ( ) ) ;
182+ self
183+ }
184+ }
185+
186+ #[ action_impl]
187+ impl < ' a > Action for RawRunCommand < ' a > {
188+ type Future = RunRawCommandFuture ;
189+
190+ async fn execute ( self ) -> Result < Document > {
191+ let mut selection_criteria = self . options . and_then ( |o| o. selection_criteria ) ;
192+ if let Some ( session) = & self . session {
193+ match session. transaction . state {
194+ TransactionState :: Starting | TransactionState :: InProgress => {
195+ if self . command . get ( "readConcern" ) . is_ok ( ) {
196+ return Err ( ErrorKind :: InvalidArgument {
197+ message : "Cannot set read concern after starting a transaction" . into ( ) ,
198+ }
199+ . into ( ) ) ;
200+ }
201+ selection_criteria = match selection_criteria {
202+ Some ( selection_criteria) => Some ( selection_criteria) ,
203+ None => {
204+ if let Some ( ref options) = session. transaction . options {
205+ options. selection_criteria . clone ( )
206+ } else {
207+ None
208+ }
209+ }
210+ } ;
211+ }
212+ _ => { }
213+ }
214+ }
215+
216+ let operation = run_command:: RunCommand :: new_raw (
217+ self . db . name ( ) . into ( ) ,
218+ self . command ,
219+ selection_criteria,
220+ None ,
221+ ) ?;
222+ self . db
223+ . client ( )
224+ . execute_operation ( operation, self . session )
225+ . await
226+ }
227+ }
228+
155229/// Runs a database-level command and returns a cursor to the response. Create with
156230/// [`Database::run_cursor_command`].
157231#[ must_use]
0 commit comments