Skip to content

Commit

Permalink
Feat/get (#602)
Browse files Browse the repository at this point in the history
* feat: add doc store

* feat: add get doc by id

* test: add test case
  • Loading branch information
imotai authored Aug 9, 2023
1 parent bb44ae3 commit 2e27ee2
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 13 deletions.
2 changes: 1 addition & 1 deletion sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "db3.js",
"version": "0.4.1",
"version": "0.4.6",
"description": "DB3 Network Javascript API",
"author": "dbpunk labs",
"keywords": [
Expand Down
3 changes: 2 additions & 1 deletion sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
createFromExternal,
} from './account/db3_account'
export type { Client, ReadClient } from './client/types'
export type { DocumentData, DocumentEntry } from './client/base'
export type {
Database,
Collection,
Expand All @@ -30,7 +31,7 @@ export type {
MutationResult,
QueryResult,
} from './store/types'
export { addDoc, updateDoc, deleteDoc, queryDoc } from './store/document_v2'
export { addDoc, updateDoc, deleteDoc, queryDoc, getDoc } from './store/document_v2'

export { SystemConfig, SystemStatus, Version } from './proto/db3_base'
export {
Expand Down
15 changes: 15 additions & 0 deletions sdk/src/provider/indexer_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
RunQueryRequest,
GetContractSyncStatusRequest,
GetCollectionOfDatabaseRequest,
GetDocRequest,
} from '../proto/db3_indexer'
import { SetupRequest, GetSystemStatusRequest } from '../proto/db3_system'
import { Query } from '../proto/db3_database_v2'
Expand Down Expand Up @@ -61,6 +62,20 @@ export class IndexerProvider {
throw new DB3Error(e as RpcError)
}
}

async getDoc(db: string, colName: string, id: string) {
const request: GetDocRequest = {
dbAddr: db,
colName,
id,
}
try {
const { response } = await this.client.getDoc(request)
return response
} catch (e) {
throw new DB3Error(e as RpcError)
}
}
async setup(signature: string, payload: string) {
try {
const request: SetupRequest = {
Expand Down
30 changes: 30 additions & 0 deletions sdk/src/store/document_v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ async function runQueryInternal<T>(col: Collection, query: Query) {
id: doc.id,
} as DocumentEntry<T>
})

return {
docs: entries,
collection: col,
Expand Down Expand Up @@ -115,6 +116,35 @@ export async function queryDoc<T = DocumentData>(
}
}

/**
*
* This function gets a document from the database by its ID.
*
* ```ts
* const doc = await getDoc(collection, "10")
* const id = doc.id
* const content = doc.doc
* ```
* @param col - the instance of collection
* @param id - the id of document
* @returns the {@link DocumentEntry} if the document was found. Otherwise, raises an error.
**/
export async function getDoc<T = DocumentData>(col: Collection, id: string) {
const response = await col.db.client.indexer.getDoc(
col.db.addr,
col.name,
id
)
if (response.document) {
return {
doc: JSON.parse(response.document.doc) as T,
id: response.document.id,
} as DocumentEntry<T>
} else {
throw new Error('no document was found with id ' + id)
}
}

export async function deleteDoc(col: Collection, ids: string[]) {
const documentMutation: DocumentMutation = {
collectionName: col.name,
Expand Down
17 changes: 17 additions & 0 deletions sdk/tests/client_v2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
deleteDoc,
updateDoc,
queryDoc,
getDoc
} from '../src/store/document_v2'
import {
createFromPrivateKey,
Expand Down Expand Up @@ -370,6 +371,21 @@ describe('test db3.js client module', () => {
age: 1,
})
await new Promise((r) => setTimeout(r, 1000))
{
const doc = await getDoc(collection, doc2Ret.id)
expect(doc).toBeDefined()
expect(doc.id).toBe(doc2Ret.id)
expect(doc.doc.city).toBe('beijing2')
expect(doc.doc.author).toBe('imotai1')
expect(doc.doc.age).toBe(1)
}
{
try {
const doc = await getDoc(collection, 1000000000000)
except(1).toBe(0)
} catch(e) {}
}

{
const queryStr = '/[city = beijing]'
const resultSet = await queryDoc<Profile>(
Expand Down Expand Up @@ -465,6 +481,7 @@ describe('test db3.js client module', () => {
age: 10,
})
await new Promise((r) => setTimeout(r, 2000))

{
const queryStr = '/[city = beijing]'
const resultSet = await queryDoc<Profile>(
Expand Down
19 changes: 17 additions & 2 deletions src/node/src/indexer_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use db3_event::event_processor::EventProcessorConfig;
use db3_proto::db3_indexer_proto::indexer_node_server::IndexerNode;
use db3_proto::db3_indexer_proto::{
ContractSyncStatus, GetCollectionOfDatabaseRequest, GetCollectionOfDatabaseResponse,
GetContractSyncStatusRequest, GetContractSyncStatusResponse, RunQueryRequest, RunQueryResponse,
GetContractSyncStatusRequest, GetContractSyncStatusResponse, GetDocRequest, GetDocResponse,
RunQueryRequest, RunQueryResponse,
};
use db3_proto::db3_mutation_v2_proto::MutationAction;
use db3_proto::db3_storage_proto::block_response::MutationWrapper;
Expand Down Expand Up @@ -367,6 +368,21 @@ impl IndexerNode for IndexerNodeImpl {
}))
}

async fn get_doc(
&self,
request: Request<GetDocRequest>,
) -> std::result::Result<Response<GetDocResponse>, Status> {
let r = request.into_inner();
let addr = DB3Address::from_hex(r.db_addr.as_str()).map_err(|e| {
Status::invalid_argument(format!("fail to parse the db address for {e}"))
})?;
let document = self
.db_store
.get_doc(&addr, r.col_name.as_str(), r.id)
.map_err(|e| Status::internal(format!("{e}")))?;
Ok(Response::new(GetDocResponse { document }))
}

async fn run_query(
&self,
request: Request<RunQueryRequest>,
Expand All @@ -376,7 +392,6 @@ impl IndexerNode for IndexerNodeImpl {
Status::invalid_argument(format!("fail to parse the db address for {e}"))
})?;
if let Some(q) = &r.query {
info!("query str {} q {:?}", q.query_str, q);
let (documents, count) = self
.db_store
.query_docs(&addr, r.col_name.as_str(), q)
Expand Down
11 changes: 11 additions & 0 deletions src/proto/proto/db3_indexer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,20 @@ message GetContractSyncStatusResponse {

message GetContractSyncStatusRequest {}

message GetDocRequest {
string db_addr = 1;
string col_name = 2;
int64 id = 3;
}

message GetDocResponse {
db3_database_v2_proto.Document document = 1;
}

service IndexerNode {
rpc GetContractSyncStatus(GetContractSyncStatusRequest) returns (GetContractSyncStatusResponse) {}
rpc GetCollectionOfDatabase(GetCollectionOfDatabaseRequest) returns (GetCollectionOfDatabaseResponse) {}
// method for query document
rpc RunQuery(RunQueryRequest) returns (RunQueryResponse) {}
rpc GetDoc(GetDocRequest) returns (GetDocResponse) {}
}
24 changes: 24 additions & 0 deletions src/storage/src/db_store_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,30 @@ impl DBStoreV2 {
Ok(())
}

pub fn get_doc(
&self,
db_addr: &DB3Address,
col_name: &str,
doc_id: i64,
) -> Result<Option<Document>> {
if !self.is_db_collection_exist(db_addr, col_name)? {
return Err(DB3Error::CollectionNotFound(
col_name.to_string(),
db_addr.to_hex(),
));
}
if self.config.enable_doc_store {
let doc = self.doc_store.get_doc(db_addr, col_name, doc_id)?;
if let Some(d) = doc {
Ok(Some(Document { id: doc_id, doc: d }))
} else {
Ok(None)
}
} else {
Ok(None)
}
}

pub fn get_doc_key_from_doc_id(&self, doc_id: i64) -> Result<Vec<u8>> {
let doc_owner_store_cf_handle = self
.se
Expand Down
15 changes: 6 additions & 9 deletions src/storage/src/doc_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,18 +237,15 @@ impl DocStore {
}
}

pub fn get_doc(&self, db_addr: &DB3Address, col_name: &str, id: i64) -> Result<String> {
pub fn get_doc(&self, db_addr: &DB3Address, col_name: &str, id: i64) -> Result<Option<String>> {
let db_opt = self.get_db_ref(db_addr);
if let Some(db) = db_opt {
let opt = db
.get::<String>(col_name, id)
.map_err(|e| DB3Error::WriteStoreError(format!("{e}")))?;
Ok(opt)
Ok(Some(opt))
} else {
Err(DB3Error::WriteStoreError(format!(
"no database found with addr {}",
db_addr.to_hex()
)))
Ok(None)
}
}

Expand Down Expand Up @@ -349,7 +346,7 @@ mod tests {
fn doc_get_test() {
let (doc_store, id) = prepare_the_dataset();
let doc_str = r#"{"f2":"f2", "f1":"f1"}"#;
if let Ok(value) = doc_store.get_doc(&DB3Address::ZERO, "col1", id) {
if let Ok(Some(value)) = doc_store.get_doc(&DB3Address::ZERO, "col1", id) {
let value: serde_json::Value = serde_json::from_str(value.as_str()).unwrap();
let right: serde_json::Value = serde_json::from_str(doc_str).unwrap();
assert_eq!(value, right);
Expand Down Expand Up @@ -417,7 +414,7 @@ mod tests {
fn doc_store_smoke_test() {
let (doc_store, id) = prepare_the_dataset();
let db_id = DB3Address::ZERO;
if let Ok(value) = doc_store.get_doc(&db_id, "col1", id) {
if let Ok(Some(value)) = doc_store.get_doc(&db_id, "col1", id) {
println!("{}", value.as_str());
let value: serde_json::Value = serde_json::from_str(value.as_str()).unwrap();
assert_eq!(value["f1"].as_str(), Some("f1"));
Expand Down Expand Up @@ -475,7 +472,7 @@ mod tests {
assert!(false);
}

if let Ok(value) = doc_store.get_doc(&db_id, "col1", id) {
if let Ok(Some(value)) = doc_store.get_doc(&db_id, "col1", id) {
let value: serde_json::Value = serde_json::from_str(value.as_str()).unwrap();
assert_eq!(value["test"].as_str(), Some("v2"));
} else {
Expand Down

0 comments on commit 2e27ee2

Please sign in to comment.