Skip to content

Commit

Permalink
Merge pull request #3 from manyuanrong/curd
Browse files Browse the repository at this point in the history
Basic curd
  • Loading branch information
manyuanrong authored Mar 5, 2020
2 parents ff72aa4 + 6ef92d8 commit 913ae41
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 54 deletions.
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> **deno_mongo** is a **MongoDB** database driver developed for deno, based on rust's official [`mongodb`](https://crates.io/crates/mongodb) library package.
[![tag](https://img.shields.io/github/tag/manyuanrong/deno_mongo.svg)](https://github.com/manyuanrong/deno_mongo)
[![tag](https://img.shields.io/github/tag/manyuanrong/deno_mongo.svg)](https://github.com/manyuanrong/deno_mongo/releases)
[![Build Status](https://github.com/manyuanrong/deno_mongo/workflows/ci/badge.svg?branch=master)](https://github.com/manyuanrong/deno_mongo/actions)
[![license](https://img.shields.io/github/license/manyuanrong/deno_mongo.svg)](https://github.com/manyuanrong/deno_mongo)
[![tag](https://img.shields.io/badge/deno-v0.35.0-green.svg)](https://github.com/denoland/deno)
Expand All @@ -16,10 +16,10 @@
## Examples

```ts
import { init, MongoClient } from "https://deno.land/x/mongo/mod.ts";
import { init, MongoClient } from "https://deno.land/x/mongo@v0.3.0/mod.ts";

// Initialize the plugin and specify the binary release version (because the binary currently has no idea how to associate the version in ts and the binary)
await init("0.1.0");
// Initialize the plugin
await init();

const client = new MongoClient();
client.connectWithUri("mongodb://localhost:27017");
Expand All @@ -33,9 +33,39 @@ const insertId = await users.insertOne({
password: "pass1"
});

// insertMany
const insertIds = await users.insertMany([
{
username: "user1",
password: "pass1"
},
{
username: "user2",
password: "pass2"
}
]);

// findOne
const user1 = await users.findOne({ _id: insertId });

// find
const users = await users.find({ username: { $ne: null } });

// updateOne
const { matchedCount, modifiedCount, upsertedId } = await users.updateOne(
username: { $ne: null },
{ $set: { username: "USERNAME" } }
);

// updateMany
const { matchedCount, modifiedCount, upsertedId } = await users.updateMany(
username: { $ne: null },
{ $set: { username: "USERNAME" } }
);

// deleteOne
const deleteCount = await users.deleteOne({ _id: insertId });

// deleteMany
const deleteCount2 = await users.deleteMany({ usename: "test" });
```
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ClientOptions, MongoClient } from "./ts/client.ts";
export { Database } from "./ts/database.ts";
export { init } from "./ts/util.ts";
export const VERSION = "v0.3.0";
42 changes: 42 additions & 0 deletions src/command/find.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::*;
use bson::Document;
use mongodb::error::Result;
use serde_json::Value;
use util::maybe_json_to_document;

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct FindArgs {
db_name: String,
collection_name: String,
filter: Option<Value>,
find_one: bool,
}

pub fn find(command: Command) -> CoreOp {
let fut = async move {
let client = command.get_client();
let data = command.data;
let args: FindArgs = serde_json::from_slice(data.unwrap().as_ref()).unwrap();
let db_name = args.db_name;
let collection_name = args.collection_name;
let filter = maybe_json_to_document(args.filter);
let database = client.database(&db_name);
let collection = database.collection(&collection_name);

if args.find_one {
let doc = collection.find_one(filter, None).unwrap();
Ok(util::async_result(&command.args, doc))
} else {
let cursor = collection.find(filter, None).unwrap();
let docs: Vec<Document> = cursor
.filter_map(|doc: Result<Document>| match doc {
Ok(doc) => Some(doc),
_ => None,
})
.collect();
Ok(util::async_result(&command.args, docs))
}
};
CoreOp::Async(fut.boxed())
}
27 changes: 0 additions & 27 deletions src/command/find_one.rs

This file was deleted.

6 changes: 4 additions & 2 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
mod connect;
mod delete;
mod find_one;
mod find;
mod insert;
mod list_collection_names;
mod list_database_names;
mod update;

pub use connect::{connect_with_options, connect_with_uri};
pub use delete::delete;
pub use find_one::find_one;
pub use find::find;
pub use insert::{insert_many, insert_one};
pub use list_collection_names::list_collection_names;
pub use list_database_names::list_database_names;
pub use update::update;
50 changes: 50 additions & 0 deletions src/command/update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::*;
use serde_json::Value;

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct UpdateArgs {
db_name: String,
collection_name: String,
query: Value,
update: Value,
update_one: bool,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
struct UpdateResultArgs {
pub matched_count: i64,
pub modified_count: i64,
pub upserted_id: Option<Value>,
}

pub fn update(command: Command) -> CoreOp {
let fut = async move {
let client = command.get_client();
let data = command.data;
let args: UpdateArgs = serde_json::from_slice(data.unwrap().as_ref()).unwrap();
let db_name = args.db_name;
let collection_name = args.collection_name;
let query_doc = util::json_to_document(args.query).expect("query canot be null");
let update_doc = util::json_to_document(args.update).expect("update_doc canot be null");
let database = client.database(&db_name);
let collection = database.collection(&collection_name);

let result = if args.update_one {
collection.update_one(query_doc, update_doc, None).unwrap()
} else {
collection.update_many(query_doc, update_doc, None).unwrap()
};

Ok(util::async_result(
&command.args,
UpdateResultArgs {
matched_count: result.matched_count,
modified_count: result.modified_count,
upserted_id: result.upserted_id.map(|id| id.into()),
},
))
};
CoreOp::Async(fut.boxed())
}
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ pub enum CommandType {
ConnectWithOptions,
ConnectWithUri,
ListDatabases,
FindOne,
Find,
ListCollectionNames,
InsertMany,
InsertOne,
Delete,
Update,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -93,10 +94,11 @@ fn op_command(data: &[u8], zero_copy: Option<ZeroCopyBuf>) -> CoreOp {
CommandType::ConnectWithUri => command::connect_with_uri,
CommandType::ListDatabases => command::list_database_names,
CommandType::ListCollectionNames => command::list_collection_names,
CommandType::FindOne => command::find_one,
CommandType::Find => command::find,
CommandType::InsertOne => command::insert_one,
CommandType::InsertMany => command::insert_many,
CommandType::Delete => command::delete,
CommandType::Update => command::update,
};

executor(Command::new(args, zero_copy))
Expand Down
52 changes: 39 additions & 13 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,31 @@ test(async function testInsertOne() {
});
});

test(async function testFindOne() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const user1 = await users.findOne();
assert(user1 instanceof Object);
assertEquals(Object.keys(user1), ["_id", "username", "password"]);

const findNull = await users.findOne({ test: 1 });
assertEquals(findNull, null);
});

test(async function testUpdateOne() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const result = await users.updateOne({}, { username: "USER1" });
assertEquals(result, { matchedCount: 1, modifiedCount: 1, upsertedId: null });
});

test(async function testDeleteOne() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const deleteCount = await users.deleteOne({});
assertEquals(deleteCount, 1);
});

test(async function testInsertMany() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
Expand All @@ -72,33 +97,34 @@ test(async function testInsertMany() {
assertEquals(insertIds.length, 2);
});

test(async function testFindOne() {
test(async function testFind() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const user1 = await users.findOne();
assert(user1 instanceof Object);
assertEquals(Object.keys(user1), ["_id", "username", "password"]);
const findUsers = await users.find({ username: "many" });
assert(findUsers instanceof Array);
assertEquals(findUsers.length, 2);

const findNull = await users.findOne({ test: 1 });
assertEquals(findNull, null);
const notFound = await users.find({ test: 1 });
assertEquals(notFound, []);
});

test(async function testDeleteOne() {
test(async function testUpdateMany() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const deleteCount = await users.deleteOne({});
assertEquals(deleteCount, 1);
const result = await users.updateMany(
{ username: "many" },
{ $set: { username: "MANY" } }
);
assertEquals(result, { matchedCount: 2, modifiedCount: 2, upsertedId: null });
});

test(async function testDeleteMany() {
const db = getClient().database("test");
const users = db.collection("mongo_test_users");
const deleteCount = await users.deleteMany({
username: "many"
});
const deleteCount = await users.deleteMany({ username: "MANY" });
assertEquals(deleteCount, 2);
});

await cargoBuild();
await init("master");
await init();
await runTests();
47 changes: 44 additions & 3 deletions ts/collection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MongoClient } from "./client.ts";
import { UpdateResult } from "./result.ts";
import { CommandType } from "./types.ts";
import { dispatchAsync, encode } from "./util.ts";

Expand All @@ -9,23 +10,32 @@ export class Collection {
private readonly collectionName: string
) {}

public async findOne(filter?: Object): Promise<any> {
private async _find(filter?: Object, findOne: boolean = false): Promise<any> {
const doc = await dispatchAsync(
{
command_type: CommandType.FindOne,
command_type: CommandType.Find,
client_id: this.client.clientId
},
encode(
JSON.stringify({
dbName: this.dbName,
collectionName: this.collectionName,
filter
filter,
findOne
})
)
);
return doc;
}

public async findOne(filter?: Object): Promise<any> {
return this._find(filter, true);
}

public async find(filter?: Object): Promise<any> {
return this._find(filter, false);
}

public async insertOne(doc: Object): Promise<any> {
const _id = await dispatchAsync(
{
Expand Down Expand Up @@ -88,4 +98,35 @@ export class Collection {
public deleteMany(query: Object): Promise<number> {
return this._delete(query, false);
}

private async _update(
query: Object,
update: Object,
updateOne: boolean = false
): Promise<UpdateResult> {
const result = await dispatchAsync(
{
command_type: CommandType.Update,
client_id: this.client.clientId
},
encode(
JSON.stringify({
dbName: this.dbName,
collectionName: this.collectionName,
query,
update,
updateOne
})
)
);
return result as UpdateResult;
}

public updateOne(query: Object, update: Object): Promise<UpdateResult> {
return this._update(query, update, true);
}

public updateMany(query: Object, update: Object): Promise<UpdateResult> {
return this._update(query, update, false);
}
}
5 changes: 5 additions & 0 deletions ts/result.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface UpdateResult {
matchedCount: number;
modifiedCount: number;
upsertedId: Object | null;
}
Loading

0 comments on commit 913ae41

Please sign in to comment.