Skip to content

Commit d6ae46b

Browse files
committed
Rust functionalities added
1 parent 08900ac commit d6ae46b

12 files changed

+1378
-48
lines changed

src/collection.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use crate::{
2+
CblRef, Listener, ListenerToken, release, retain,
3+
c_api::{
4+
CBLCollection, CBLCollectionChange, CBLCollection_AddChangeListener, CBLCollection_Scope,
5+
CBLCollection_Name, CBLCollection_Count,
6+
},
7+
scope::Scope,
8+
};
9+
10+
pub static DEFAULT_NAME: &str = "_default";
11+
12+
#[derive(Debug, PartialEq, Eq)]
13+
pub struct Collection {
14+
cbl_ref: *mut CBLCollection,
15+
}
16+
17+
impl Collection {
18+
pub(crate) fn retain(cbl_ref: *mut CBLCollection) -> Self {
19+
Self {
20+
cbl_ref: unsafe { retain(cbl_ref) },
21+
}
22+
}
23+
24+
/** Returns the scope of the collection. */
25+
pub fn scope(&self) -> Scope {
26+
unsafe { Scope::retain(CBLCollection_Scope(self.get_ref())) }
27+
}
28+
29+
/** Returns the collection name. */
30+
pub fn name(&self) -> String {
31+
unsafe {
32+
CBLCollection_Name(self.get_ref())
33+
.to_string()
34+
.unwrap_or_default()
35+
}
36+
}
37+
38+
/** Returns the number of documents in the collection. */
39+
pub fn count(&self) -> u64 {
40+
unsafe { CBLCollection_Count(self.get_ref()) }
41+
}
42+
43+
/** Registers a collection change listener callback. It will be called after one or more documents are changed on disk. */
44+
pub fn add_listener(
45+
&mut self,
46+
listener: CollectionChangeListener,
47+
) -> Listener<CollectionChangeListener> {
48+
unsafe {
49+
let listener = Box::new(listener);
50+
let ptr = Box::into_raw(listener);
51+
52+
Listener::new(
53+
ListenerToken {
54+
cbl_ref: CBLCollection_AddChangeListener(
55+
self.get_ref(),
56+
Some(c_collection_change_listener),
57+
ptr.cast(),
58+
),
59+
},
60+
Box::from_raw(ptr),
61+
)
62+
}
63+
}
64+
}
65+
66+
impl CblRef for Collection {
67+
type Output = *mut CBLCollection;
68+
fn get_ref(&self) -> Self::Output {
69+
self.cbl_ref
70+
}
71+
}
72+
73+
impl Drop for Collection {
74+
fn drop(&mut self) {
75+
unsafe { release(self.get_ref()) }
76+
}
77+
}
78+
79+
impl Clone for Collection {
80+
fn clone(&self) -> Self {
81+
Self::retain(self.get_ref())
82+
}
83+
}
84+
85+
/** A collection change listener callback, invoked after one or more documents are changed on disk. */
86+
type CollectionChangeListener = Box<dyn Fn(Collection, Vec<String>)>;
87+
88+
#[no_mangle]
89+
unsafe extern "C" fn c_collection_change_listener(
90+
context: *mut ::std::os::raw::c_void,
91+
change: *const CBLCollectionChange,
92+
) {
93+
let callback = context as *const CollectionChangeListener;
94+
if let Some(change) = change.as_ref() {
95+
let collection = Collection::retain(change.collection as *mut CBLCollection);
96+
let doc_ids = std::slice::from_raw_parts(change.docIDs, change.numDocs as usize)
97+
.iter()
98+
.filter_map(|doc_id| doc_id.to_string())
99+
.collect();
100+
101+
(*callback)(collection, doc_ids);
102+
}
103+
}

src/database.rs

Lines changed: 161 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ use crate::{
2929
CBL_DeleteDatabase, CBLEncryptionKey_FromPassword, FLString, kCBLMaintenanceTypeCompact,
3030
kCBLEncryptionNone, kCBLMaintenanceTypeFullOptimize, kCBLMaintenanceTypeIntegrityCheck,
3131
kCBLMaintenanceTypeOptimize, kCBLMaintenanceTypeReindex, CBL_CopyDatabase,
32+
CBLDatabase_ScopeNames, CBLDatabase_CollectionNames, CBLDatabase_Scope,
33+
CBLDatabase_Collection, CBLDatabase_CreateCollection, CBLDatabase_DeleteCollection,
34+
CBLDatabase_DefaultScope, CBLDatabase_DefaultCollection,
3235
},
3336
Listener, check_error, Error, CouchbaseLiteError,
37+
collection::Collection,
38+
scope::Scope,
39+
MutableArray,
3440
};
3541
use std::path::{Path, PathBuf};
3642
use std::ptr;
@@ -89,7 +95,8 @@ enum_from_primitive! {
8995
}
9096

9197
/** A database change listener callback, invoked after one or more documents are changed on disk. */
92-
type ChangeListener = Box<dyn Fn(&Database, Vec<String>)>;
98+
#[deprecated(note = "please use `CollectionChangeListener` on default collection instead")]
99+
type DatabaseChangeListener = Box<dyn Fn(&Database, Vec<String>)>;
93100

94101
#[no_mangle]
95102
unsafe extern "C" fn c_database_change_listener(
@@ -98,7 +105,7 @@ unsafe extern "C" fn c_database_change_listener(
98105
num_docs: ::std::os::raw::c_uint,
99106
c_doc_ids: *mut FLString,
100107
) {
101-
let callback = context as *const ChangeListener;
108+
let callback = context as *const DatabaseChangeListener;
102109
let database = Database::retain(db as *mut CBLDatabase);
103110

104111
let doc_ids = std::slice::from_raw_parts(c_doc_ids, num_docs as usize)
@@ -324,10 +331,157 @@ impl Database {
324331
}
325332

326333
/** Returns the number of documents in the database. */
334+
#[deprecated(note = "please use `count` on the default collection instead")]
327335
pub fn count(&self) -> u64 {
328336
unsafe { CBLDatabase_Count(self.get_ref()) }
329337
}
330338

339+
/** Returns the names of all existing scopes in the database.
340+
The scope exists when there is at least one collection created under the scope.
341+
The default scope is exceptional in that it will always exists even there are no collections under it. */
342+
pub fn scope_names(&self) -> Result<Vec<String>> {
343+
let mut error = CBLError::default();
344+
let array = unsafe { CBLDatabase_ScopeNames(self.get_ref(), &mut error) };
345+
346+
check_error(&error).map(|()| unsafe {
347+
MutableArray::adopt(array)
348+
.iter()
349+
.map(|v| v.as_string().unwrap_or("").to_string())
350+
.collect()
351+
})
352+
}
353+
354+
/** Returns the names of all collections in the scope. */
355+
pub fn collection_names(&self, scope_name: String) -> Result<Vec<String>> {
356+
let scope_name = from_str(&scope_name);
357+
let mut error = CBLError::default();
358+
let array = unsafe {
359+
CBLDatabase_CollectionNames(self.get_ref(), scope_name.get_ref(), &mut error)
360+
};
361+
362+
check_error(&error).map(|()| unsafe {
363+
MutableArray::adopt(array)
364+
.iter()
365+
.map(|v| v.as_string().unwrap_or("").to_string())
366+
.collect()
367+
})
368+
}
369+
370+
/** Returns an existing scope with the given name.
371+
The scope exists when there is at least one collection created under the scope.
372+
The default scope is exception in that it will always exists even there are no collections under it. */
373+
pub fn scope(&self, scope_name: String) -> Result<Option<Scope>> {
374+
let scope_name = from_str(&scope_name);
375+
let mut error = CBLError::default();
376+
let scope = unsafe { CBLDatabase_Scope(self.get_ref(), scope_name.get_ref(), &mut error) };
377+
378+
check_error(&error).map(|()| {
379+
if scope.is_null() {
380+
None
381+
} else {
382+
Some(Scope::retain(scope))
383+
}
384+
})
385+
}
386+
387+
/** Returns the existing collection with the given name and scope. */
388+
pub fn collection(
389+
&self,
390+
collection_name: String,
391+
scope_name: String,
392+
) -> Result<Option<Collection>> {
393+
let collection_name = from_str(&collection_name);
394+
let scope_name = from_str(&scope_name);
395+
let mut error = CBLError::default();
396+
let collection = unsafe {
397+
CBLDatabase_Collection(
398+
self.get_ref(),
399+
collection_name.get_ref(),
400+
scope_name.get_ref(),
401+
&mut error,
402+
)
403+
};
404+
405+
check_error(&error).map(|()| {
406+
if collection.is_null() {
407+
None
408+
} else {
409+
Some(Collection::retain(collection))
410+
}
411+
})
412+
}
413+
414+
/** Create a new collection.
415+
The naming rules of the collections and scopes are as follows:
416+
- Must be between 1 and 251 characters in length.
417+
- Can only contain the characters A-Z, a-z, 0-9, and the symbols _, -, and %.
418+
- Cannot start with _ or %.
419+
- Both scope and collection names are case sensitive.
420+
If the collection already exists, the existing collection will be returned. */
421+
pub fn create_collection(
422+
&self,
423+
collection_name: String,
424+
scope_name: String,
425+
) -> Result<Collection> {
426+
let collection_name = from_str(&collection_name);
427+
let scope_name = from_str(&scope_name);
428+
let mut error = CBLError::default();
429+
let collection = unsafe {
430+
CBLDatabase_CreateCollection(
431+
self.get_ref(),
432+
collection_name.get_ref(),
433+
scope_name.get_ref(),
434+
&mut error,
435+
)
436+
};
437+
438+
check_error(&error).map(|()| Collection::retain(collection))
439+
}
440+
441+
/** Delete an existing collection.
442+
@note The default collection cannot be deleted.
443+
@param db The database.
444+
@param collectionName The name of the collection.
445+
@param scopeName The name of the scope.
446+
@param outError On failure, the error will be written here.
447+
@return True if success, or False if an error occurred. */
448+
pub fn delete_collection(&self, collection_name: String, scope_name: String) -> Result<()> {
449+
let collection_name = from_str(&collection_name);
450+
let scope_name = from_str(&scope_name);
451+
unsafe {
452+
check_bool(|error| {
453+
CBLDatabase_DeleteCollection(
454+
self.get_ref(),
455+
collection_name.get_ref(),
456+
scope_name.get_ref(),
457+
error,
458+
)
459+
})
460+
}
461+
}
462+
463+
/** Returns the default scope. */
464+
pub fn default_scope(&self) -> Result<Scope> {
465+
let mut error = CBLError::default();
466+
let scope = unsafe { CBLDatabase_DefaultScope(self.get_ref(), &mut error) };
467+
468+
check_error(&error).map(|()| Scope::retain(scope))
469+
}
470+
471+
/** Returns the default collection. */
472+
pub fn default_collection(&self) -> Result<Option<Collection>> {
473+
let mut error = CBLError::default();
474+
let collection = unsafe { CBLDatabase_DefaultCollection(self.get_ref(), &mut error) };
475+
476+
check_error(&error).map(|()| {
477+
if collection.is_null() {
478+
None
479+
} else {
480+
Some(Collection::retain(collection))
481+
}
482+
})
483+
}
484+
331485
//////// NOTIFICATIONS:
332486

333487
/** Registers a database change listener function. It will be called after one or more
@@ -340,7 +494,11 @@ impl Database {
340494
You must keep the `Listener` object as long as you need it.
341495
*/
342496
#[must_use]
343-
pub fn add_listener(&mut self, listener: ChangeListener) -> Listener<ChangeListener> {
497+
#[deprecated(note = "please use `add_listener` on default collection instead")]
498+
pub fn add_listener(
499+
&mut self,
500+
listener: DatabaseChangeListener,
501+
) -> Listener<DatabaseChangeListener> {
344502
unsafe {
345503
let listener = Box::new(listener);
346504
let ptr = Box::into_raw(listener);

0 commit comments

Comments
 (0)