use database::*;
use serde_json;
use serde_json::Value;
use std::ops::{Index, IndexMut};
use types::*;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Document {
#[serde(skip_serializing)]
pub _id: DocumentId,
#[serde(skip_serializing)]
pub _rev: String,
doc: Value,
}
impl Document {
pub fn new(doc: Value) -> Document {
Document {
_id: json_extr!(doc["_id"]),
_rev: json_extr!(doc["_rev"]),
doc: doc,
}
}
pub fn get_keys(&self) -> Vec<String> {
let mut ret: Vec<String> = Vec::new();
if let Some(obj) = self.doc.as_object() {
for (k, _) in obj.into_iter() {
ret.push(k.clone());
}
}
ret
}
pub fn get_data(&self) -> Value {
self.doc.clone()
}
pub fn merge(&mut self, doc: Value) -> &Self {
if let Some(obj) = doc.as_object() {
for (k, v) in obj.into_iter() {
match k.as_str() {
"_id" | "_rev" => {
continue;
}
_ => {
self[k] = v.clone();
}
}
}
}
self
}
pub fn populate(&mut self, field: &String, db: Database) -> &Self {
let ref val = self[field].clone();
if *val == Value::Null {
return self;
}
let ids = val.as_array()
.unwrap_or(&Vec::new())
.into_iter()
.map(|v| s!(v.as_str().unwrap_or("")))
.collect();
let data = db.get_bulk(ids).and_then(|docs| Ok(docs.get_data()));
match data {
Ok(data) => {
self[field] = data.into_iter()
.filter_map(|d: Value| {
let did = match d["_id"].as_str() {
Some(did) => did,
None => return None,
};
if val[did] != Value::Null {
Some(d.clone())
} else {
None
}
})
.collect();
}
Err(_) => {
return self;
}
}
self
}
}
impl<I> Index<I> for Document
where
I: serde_json::value::Index,
{
type Output = Value;
fn index(&self, index: I) -> &Value {
&self.doc[index]
}
}
impl<I> IndexMut<I> for Document
where
I: serde_json::value::Index,
{
fn index_mut(&mut self, index: I) -> &mut Value {
&mut self.doc[index]
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct DocumentCollectionItem {
pub id: DocumentId,
pub doc: Document,
}
impl DocumentCollectionItem {
pub fn new(doc: Document) -> DocumentCollectionItem {
let id = doc._id.clone();
DocumentCollectionItem { doc: doc, id: id }
}
}
#[derive(Default, Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct DocumentCollection {
pub offset: u32,
pub rows: Vec<DocumentCollectionItem>,
pub total_rows: u32,
}
impl DocumentCollection {
pub fn new(doc: Value) -> DocumentCollection {
let rows: Vec<Value> = json_extr!(doc["rows"]);
let items: Vec<DocumentCollectionItem> = rows.into_iter()
.filter(|d| {
let id: String = json_extr!(d["doc"]["_id"]);
!id.starts_with('_')
})
.map(|d| {
let document: Value = json_extr!(d["doc"]);
DocumentCollectionItem::new(Document::new(document))
})
.collect();
DocumentCollection {
offset: json_extr!(doc["offset"]),
total_rows: items.len() as u32,
rows: items,
}
}
pub fn new_from_documents(docs: Vec<Document>) -> DocumentCollection {
let len = docs.len() as u32;
DocumentCollection {
offset: 0,
total_rows: len,
rows: docs.into_iter().map(|d| DocumentCollectionItem::new(d)).collect(),
}
}
pub fn get_data(&self) -> Vec<Value> {
self.rows.iter().map(|doc_item| doc_item.doc.get_data()).collect()
}
}
impl Index<usize> for DocumentCollection {
type Output = DocumentCollectionItem;
fn index(&self, index: usize) -> &DocumentCollectionItem {
&self.rows.get(index).unwrap()
}
}
impl IndexMut<usize> for DocumentCollection {
fn index_mut(&mut self, index: usize) -> &mut DocumentCollectionItem {
self.rows.get_mut(index).unwrap()
}
}