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
use std::ffi::CString; use libc::{c_int, c_uint}; use ejdb_sys; use super::Collection; use Result; impl<'db> Collection<'db> { /// Returns an index builder for the provided field in this collection. /// /// The index builder may be used to create, modify or delete various indices on /// collection fields. A field may have more than one index of different types. /// This may be useful if this field is heterogeneous, i.e. if it may hold different types /// of data. /// /// # Example /// /// ```no_run /// # use ejdb::Database; /// let db = Database::open("/path/to/db").unwrap(); /// let coll = db.collection("some_collection").unwrap(); /// /// // create a case sensitive string index on "name" field in this collection /// coll.index("name").string(true).set().unwrap(); /// ``` /// /// See builder methods for more examples. pub fn index<S: Into<String>>(&self, key: S) -> Index { Index { coll: self, key: key.into(), flags: None, } } } /// A builder for an operation on an index of a certain field of an EJDB collection. /// /// In EJDB every collection can have an index on the fields of its records. Indices can be /// of one of three types: /// /// * string (possibly case insensitive); /// * number; /// * array. /// /// Indices can be set, dropped, optimized or rebuilt. Indices are stored in a separate file /// from their collections and can speed up certain access patterns in queries. Naturally, /// indices are specified for some field in collection records, so this structure is used to /// configure indices for one specific field. /// /// Index manipulation is done with this structure which provides a builder-like interface /// to create, change properties or drop an index on one field. Since an index can't exist /// separately from a collection, this structure is linked via a lifetime to its corresponding /// collection object. An instance of this structure is obtained with `Collection::index()` method. /// /// # Example /// /// ```no_run /// # use ejdb::Database; /// let db = Database::open("/path/to/db").unwrap(); /// let coll = db.collection("some_collection").unwrap(); /// /// // create a string index on `name` field /// coll.index("name").string(true).set().unwrap(); /// /// // create multiple indices on `coords` field /// coll.index("coords").number().array().set().unwrap(); /// ``` pub struct Index<'coll, 'db: 'coll> { coll: &'coll Collection<'db>, key: String, flags: Option<c_uint>, } impl<'coll, 'db: 'coll> Index<'coll, 'db> { fn add_flags(self, flags: c_uint) -> Self { Index { coll: self.coll, key: self.key, flags: Some(self.flags.unwrap_or(0) | flags), } } /// Specifies that this index must be built over string values of this field. /// /// `case_sensitive` argument determines whether this index must take string case into account, /// `true` for case sensitive matching, `false` for the opposite. pub fn string(self, case_sensitive: bool) -> Self { self.add_flags(if case_sensitive { ejdb_sys::JBIDXSTR } else { ejdb_sys::JBIDXISTR }) } /// Specifies that this index must be built over numeric values of this field. pub fn number(self) -> Self { self.add_flags(ejdb_sys::JBIDXNUM) } /// Specifies that this index must be built over array values of this field. pub fn array(self) -> Self { self.add_flags(ejdb_sys::JBIDXARR) } /// Creates one or more indices of specified types on this field. /// /// Panics if no types were specified before calling this method. pub fn set(self) -> Result<()> { self.check_type().execute() } /// Drops all indices on this field. pub fn drop_all(mut self) -> Result<()> { self.flags = Some(ejdb_sys::JBIDXDROPALL); self.execute() } /// Drops indices of the previously specified types on this field. /// /// Panics if no type has been set prior to calling this method. pub fn drop(self) -> Result<()> { self.add_flags(ejdb_sys::JBIDXDROP).check_type().execute() } /// Rebuilds indices of the previously specified types on this field from scratch. /// /// Panics if no type has been set prior to calling this method. pub fn rebuild(self) -> Result<()> { self.add_flags(ejdb_sys::JBIDXREBLD).check_type().execute() } /// Optimizes indices of the previously specified types on this field. /// /// Panics if no type has been set prior to calling this method. pub fn optimize(self) -> Result<()> { self.add_flags(ejdb_sys::JBIDXOP).check_type().execute() } fn check_type(self) -> Self { let flags = self.flags.expect("index type is not specified"); assert!( [ ejdb_sys::JBIDXSTR, ejdb_sys::JBIDXISTR, ejdb_sys::JBIDXNUM, ejdb_sys::JBIDXARR ] .iter() .any(|&f| flags & f != 0), "index type is not specified" ); self } fn execute(self) -> Result<()> { let flags = self.flags.expect("index flags are not defined"); // should always unwrap let key = try!(CString::new(self.key).map_err(|_| "invalid key")); let result = unsafe { ejdb_sys::ejdbsetindex(self.coll.coll, key.as_ptr(), flags as c_int) }; if result { Ok(()) } else { self.coll.db.last_error("cannot update index") } } }