1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

use std::cell::RefCell;
use std::rc::Rc;

use serde::de::DeserializeOwned;
use tokio_core::reactor::Core;

use rincon_client::aql::methods::{ExplainQuery, ParseQuery};
use rincon_client::aql::types::{ExplainedQuery, ExplainOptions, ParsedQuery};
use rincon_client::collection::methods::{CreateCollection, DropCollection,
    ListCollections};
use rincon_client::collection::types::Collection;
use rincon_client::cursor::methods::CreateCursor;
use rincon_client::cursor::types::NewCursor;
use rincon_client::database::methods::DropDatabase;
use rincon_client::document::methods::GetDocument;
use rincon_client::document::types::{Document, DocumentId};
use rincon_client::graph::methods::{CreateGraph, DropGraph, ListGraphs};
use rincon_client::graph::types::{Graph, NewGraph};
use rincon_core::api::connector::{Connector, Execute};
use rincon_core::api::method::{Method, Prepare};
use rincon_core::api::query::Query;
use rincon_core::api::types::Entity;

use collection_session::CollectionSession;
use cursor_session::CursorSession;
use graph_session::GraphSession;
use super::Result;

/// A session for operating with a specific database.
#[derive(Debug)]
pub struct DatabaseSession<C> {
    database_name: String,
    connector: Rc<C>,
    core: Rc<RefCell<Core>>,
}

impl<C> DatabaseSession<C>
    where C: 'static + Connector
{
    /// Instantiates a new `DatabaseSession` for the database with the given
    /// name.
    pub(crate) fn new(
        database_name: String,
        connector: Rc<C>,
        core: Rc<RefCell<Core>>,
    ) -> Self {
        DatabaseSession {
            database_name,
            connector,
            core,
        }
    }

    /// Executes an API method applied to the database of this session.
    pub fn execute<M>(&self, method: M) -> Result<<M as Method>::Result>
        where M: 'static + Method + Prepare
    {
        self.core.borrow_mut().run(
            self.connector.connection(&self.database_name)
                .execute(method)
        )
    }

    /// Returns the name of the database this `DatabaseSession` operates with.
    pub fn name(&self) -> &str {
        &self.database_name
    }

    /// Unwraps the database name out of this session.
    pub fn unwrap(self) -> String {
        self.database_name
    }

    /// Drops the database that is used in this session.
    ///
    /// Returns true if the database has been dropped successfully.
    ///
    /// After calling this function the associated `DatabaseSession` is no
    /// longer valid.
    pub fn drop(self) -> Result<bool> {
        let database_name = self.database_name.to_owned();
        self.core.borrow_mut().run(self.connector.system_connection()
            .execute(DropDatabase::new(database_name))
        )
    }

    /// Executes a query and returns a cursor with the first result set.
    ///
    /// All cursor options and query execution options are left to their default
    /// settings.
    ///
    /// To specify cursor options and/or query execution options use the
    /// `query_opt(&self, NewCursor)` function.
    pub fn query<T>(&self, query: Query) -> Result<CursorSession<T, C>>
        where T: 'static + DeserializeOwned
    {
        self.execute(CreateCursor::from_query(query))
            .map(|cursor| CursorSession::new(
                cursor,
                self.database_name.clone(),
                self.connector.clone(),
                self.core.clone(),
            ))
    }

    /// Executes a query and returns a cursor with the first result set.
    ///
    /// It requires a `NewCursor` struct as a parameter which allows full
    /// control over all supported cursor options and query execution options.
    ///
    /// To execute a query with all options left at their defaults the
    /// `query(&self, Query)` function might be more suitable.
    pub fn query_opt<T>(&self, new_cursor: NewCursor) -> Result<CursorSession<T, C>>
        where T: 'static + DeserializeOwned
    {
        self.execute(CreateCursor::new(new_cursor))
            .map(|cursor| CursorSession::new(
                cursor,
                self.database_name.clone(),
                self.connector.clone(),
                self.core.clone(),
            ))
    }

    /// Generates an execution plan for a query but does not execute it.
    pub fn explain_query(&self, query: Query) -> Result<ExplainedQuery> {
        self.execute(ExplainQuery::with_defaults(query))
    }

    /// Generates an execution plan for a query but does not execute it.
    ///
    /// Some options about how many execution plans are generated and the
    /// configuration options for the query optimizer can be provided.
    pub fn explain_query_opt(&self, query: Query, options: ExplainOptions) -> Result<ExplainedQuery> {
        self.execute(ExplainQuery::with_options(query, options))
    }

    /// Parses a query a validates the syntax but does not execute it.
    ///
    /// If the query can be parsed without error the abstract syntax tree (AST)
    /// of the query is returned.
    pub fn parse_query<Q>(&self, query: Q) -> Result<ParsedQuery>
        where Q: Into<String>
    {
        self.execute(ParseQuery::from_query(query.into()))
    }

    /// Fetch the document with the given id from the database of this session.
    pub fn get_document<T>(&self, id: DocumentId) -> Result<Document<T>>
        where T: 'static + DeserializeOwned
    {
        self.execute(GetDocument::with_id(id))
    }

    /// Returns a new `CollectionSession` for the collection with the given
    /// name.
    pub fn use_collection_with_name<N>(&self, collection_name: N) -> CollectionSession<C>
        where N: Into<String>
    {
        CollectionSession::new(
            Entity::Name(collection_name.into()),
            self.database_name.clone(),
            self.connector.clone(),
            self.core.clone(),
        )
    }

    /// Returns a new `CollectionSession` for the given collection.
    pub fn use_collection(&self, collection: Collection) -> CollectionSession<C> {
        CollectionSession::new(
            Entity::Object(collection),
            self.database_name.clone(),
            self.connector.clone(),
            self.core.clone(),
        )
    }

    /// Creates a new collection within the database of this session.
    pub fn create_collection<N>(&self, collection_name: N) -> Result<CollectionSession<C>>
        where N: Into<String>
    {
        self.execute(CreateCollection::with_name(collection_name))
            .map(|props|
                CollectionSession::new(
                    Entity::Object(Collection::from(props)),
                    self.database_name.clone(),
                    self.connector.clone(),
                    self.core.clone(),
                )
            )
    }

    /// Drops the collection with the given name from the database of this
    /// session and returns the identifier of the dropped collection.
    pub fn drop_collection<N>(&self, collection_name: N) -> Result<String>
        where N: Into<String>
    {
        self.execute(DropCollection::with_name(collection_name))
    }

    /// Fetches a list of all collections in this database.
    ///
    /// System collections are not included in the returned list.
    pub fn list_collections(&self) -> Result<Vec<Collection>> {
        self.execute(ListCollections::new())
    }

    /// Fetches a list of all collections in this database including system
    /// collections.
    pub fn list_collections_including_system(&self) -> Result<Vec<Collection>> {
        self.execute(ListCollections::including_system())
    }

    /// Returns a new `GraphSession` for the graph with the given name.
    pub fn use_graph_with_name<N>(&self, graph_name: N) -> GraphSession<C>
        where N: Into<String>
    {
        GraphSession::new(
            Entity::Name(graph_name.into()),
            self.database_name.clone(),
            self.connector.clone(),
            self.core.clone(),
        )
    }

    /// Returns a new `GraphSession` for the given graph.
    pub fn use_graph(&self, graph: Graph) -> GraphSession<C> {
        GraphSession::new(
            Entity::Object(graph),
            self.database_name.clone(),
            self.connector.clone(),
            self.core.clone(),
        )
    }

    /// Creates a new graph in the database represented by this
    /// `DatabaseSession`.
    pub fn create_graph(&self, new_graph: NewGraph) -> Result<GraphSession<C>> {
        let core = self.core.clone();
        let connector = self.connector.clone();
        let database_name = self.database_name.clone();
        self.execute(CreateGraph::new(new_graph))
            .map(|graph|
                GraphSession::new(
                    Entity::Object(graph),
                    database_name,
                    connector,
                    core,
                )
            )
    }

    /// Drops the graph with the given name from the database of this session.
    ///
    /// This function returns true if the graph has been deleted and false
    /// otherwise.
    pub fn drop_graph<N>(&self, graph_name: N) -> Result<bool>
        where N: Into<String>
    {
        self.execute(DropGraph::with_name(graph_name))
    }

    /// Fetches a list of all graphs in this database.
    pub fn list_graphs(&self) -> Result<Vec<Graph>> {
        self.execute(ListGraphs::new())
    }
}