Skip to content

Commit

Permalink
feat: getMany, values, keys
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-online committed Apr 11, 2024
1 parent 4a77d1e commit 70d78da
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,4 @@ Cargo.lock

*.node

*.sqlite
*.sqlite*
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
}
},
"rust-analyzer.procMacro.ignored": { "napi-derive": ["napi"] }
}
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 0 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ napi = { version = "2.16.1", default-features = false, features = [
# https://github.com/launchbadge/sqlx/pull/3190
time = "=0.3.34"
napi-derive = "2.16.1"
sea-orm = { version = "0.12.15", features = [
"runtime-tokio-native-tls",
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"macros"
] }
brinedb-entity = { path = "crates/entity" }
brinedb-migration = { path = "crates/migration" }

Expand Down
8 changes: 7 additions & 1 deletion crates/entity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@ license = "MIT"
edition = "2018"

[dependencies]
sea-orm = { version = "0.12.15" }
sea-orm = { version = "0.12.15", features = [
"runtime-tokio-native-tls",
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"macros"
] }
2 changes: 2 additions & 0 deletions crates/entity/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod doc;

pub extern crate sea_orm;
33 changes: 17 additions & 16 deletions crates/migration/src/m20240407_192852_add_indexes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_index(
Index::create()
.table(Brine::Table)
.col(Brine::Key)
.name("idx_key")
.to_owned(),
)
.await
}
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_index(
Index::create()
.table(Brine::Table)
.col(Brine::Key)
.name("idx_key")
.if_not_exists()
.to_owned(),
)
.await
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_index(Index::drop().table(Brine::Table).name("idx_key").to_owned())
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_index(Index::drop().table(Brine::Table).name("idx_key").to_owned())
.await
}
}
2 changes: 1 addition & 1 deletion native/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class BrineDb {
get(key: string): Promise<string | null>
set(key: string, value: string): Promise<void>
setMany(data: Array<[string, string]>): Promise<void>
getMany(keys: Array<string>): Promise<Array<Array<string>>>
getMany(keys: Array<string>): Promise<Record<string, string | undefined | null>>
clear(): Promise<void>
delete(key: string): Promise<void>
deleteMany(keys: Array<string>): Promise<void>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"build": "yarn build:rs && yarn build:ts",
"build:ts": "tsup",
"build:rs": "napi build --platform --release native",
"build:debug": "napi build --platform",
"build:rs:debug": "napi build --platform",
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
"test": "vitest run",
"universal": "napi universal",
Expand Down
56 changes: 56 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ class Brine<T = unknown> {
*
* @param data An array of 2d arrays containing keys and values
* @returns Promise<void>
* @example
* ```ts
* await brinedb.setMany([
* ["key1", "value1"],
* ["key2", "value2"],
* ]);
*/
public async setMany(data: [string, T][]) {
const serializedData = (await Promise.all(
Expand All @@ -227,6 +233,56 @@ class Brine<T = unknown> {
await this.db.setMany(serializedData);
}

/**
* Get many keys from the database
*
* @param keys The keys to get
* @returns Promise<[string, string][]>
* @example
* ```ts
* const data = await brinedb.getMany(["key1", "key2"]);
* ```
*/
public async getMany(keys: string[]): Promise<Record<string, T | null>> {
const result = await this.db.getMany(keys);

const parsed: Record<string, T | null> = {};

for (const [key, value] of Object.entries(result)) {
parsed[key] = value ? await this.deserialize(value) : null;
}

return parsed;
}

/**
* Get all keys from the database
*
* @returns Promise<string[]>
* @example
* ```ts
* const keys = await brinedb.keys();
* ```
*/
public async keys() {
return this.db.keys();
}

/**
* Get all values from the database
*
* @returns Promise<T[]>
* @example
* ```ts
* const values = await brinedb.values();
* ```
*/
public async values() {
const values = await this.db.values();

return Promise.all(values.map((value) => this.deserialize(value)));
}

/**
* Close the connection to the database
*
Expand Down
82 changes: 55 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
use brinedb_entity::doc::ActiveModel as ActiveDocumentModel;
use brinedb_entity::doc::Column as DocumentColumn;
use brinedb_entity::doc::Entity as Document;
use brinedb_entity::sea_orm;
use brinedb_entity::sea_orm::ColumnTrait;
use brinedb_entity::sea_orm::ConnectOptions;
use brinedb_entity::sea_orm::ConnectionTrait;
use brinedb_entity::sea_orm::Database;
use brinedb_entity::sea_orm::DatabaseConnection;
use brinedb_entity::sea_orm::EntityTrait;
use brinedb_entity::sea_orm::PaginatorTrait;
use brinedb_entity::sea_orm::QueryFilter;
use brinedb_entity::sea_orm::QuerySelect;
use brinedb_entity::sea_orm::Set;
use migration::sea_orm::FromQueryResult;
use migration::Migrator;
use migration::MigratorTrait;
use migration::OnConflict;
use napi::bindgen_prelude::*;
use sea_orm::ColumnTrait;
use sea_orm::ConnectOptions;
use sea_orm::ConnectionTrait;
use sea_orm::DatabaseConnection;
use sea_orm::EntityTrait;
use sea_orm::PaginatorTrait;
use sea_orm::QueryFilter;
use sea_orm::QuerySelect;
use sea_orm::Set;
use std::collections::HashMap;

#[macro_use]
extern crate napi_derive;
Expand All @@ -38,19 +42,19 @@ impl BrineDB {
pub async unsafe fn connect(&mut self) -> Result<bool> {
let opt = ConnectOptions::new(&self.connection_uri);

let connection = sea_orm::Database::connect(opt)
let connection = Database::connect(opt)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;

if self.connection_uri.starts_with("sqlite") {
connection
.execute_unprepared("PRAGMA journal_mode = wal;")
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
connection
.execute_unprepared("PRAGMA synchronous = 1;")
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
let pragmas = vec!["PRAGMA journal_mode = wal;", "PRAGMA synchronous = 1;"];

for pragma in pragmas {
connection
.execute_unprepared(pragma)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
}
}

self.connection = Some(connection);
Expand Down Expand Up @@ -79,7 +83,13 @@ impl BrineDB {
.as_ref()
.ok_or_else(|| Error::new(Status::GenericFailure, "No connection found"))?;

#[derive(FromQueryResult)]
struct GetDoc {
value: String,
}

let res = Document::find_by_id(&key)
.into_model::<GetDoc>()
.one(connection)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
Expand All @@ -103,7 +113,7 @@ impl BrineDB {
value: Set(value),
};

Document::insert(model)
Document::insert(model.clone())
.on_conflict(
OnConflict::column(DocumentColumn::Key)
.update_column(DocumentColumn::Value)
Expand Down Expand Up @@ -145,24 +155,30 @@ impl BrineDB {
}

#[napi]
pub async fn get_many(&self, keys: Vec<String>) -> Result<Vec<Vec<String>>> {
pub async fn get_many(&self, keys: Vec<String>) -> Result<HashMap<String, Option<String>>> {
let connection = self
.connection
.as_ref()
.ok_or_else(|| Error::new(Status::GenericFailure, "No connection found"))?;

let res = Document::find()
.filter(DocumentColumn::Key.is_in(keys))
.filter(DocumentColumn::Key.is_in(&keys))
.all(connection)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;

Ok(
res
.into_iter()
.map(|doc| vec![doc.key, doc.value])
.collect(),
)
let mut res = res
.into_iter()
.map(|doc| (doc.key, Some(doc.value)))
.collect::<HashMap<_, _>>();

for key in keys {
if !res.contains_key(&key) {
res.insert(key, None);
}
}

Ok(res)
}

#[napi]
Expand Down Expand Up @@ -223,9 +239,15 @@ impl BrineDB {
.as_ref()
.ok_or_else(|| Error::new(Status::GenericFailure, "No connection found"))?;

#[derive(FromQueryResult)]
struct KeysOnlyDoc {
key: String,
}

let res = Document::find()
.select_only()
.column(DocumentColumn::Key)
.into_model::<KeysOnlyDoc>()
.all(connection)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
Expand All @@ -240,9 +262,15 @@ impl BrineDB {
.as_ref()
.ok_or_else(|| Error::new(Status::GenericFailure, "No connection found"))?;

#[derive(FromQueryResult)]
struct ValuesOnlyDoc {
value: String,
}

let res = Document::find()
.select_only()
.column(DocumentColumn::Value)
.into_model::<ValuesOnlyDoc>()
.all(connection)
.await
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?;
Expand Down
23 changes: 15 additions & 8 deletions tests/bench.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ const randomData = (length: number) => {
describe("Benchmark", () => {
test("Brine", async () => {
const bench = new Bench({ time: 200 });
const brinedb = new Brine(BrineDatabases.sqlite.file("test.sqlite"));
const brinedb = new Brine(BrineDatabases.sqlite.file("test.sqlite"), {
serialize: (value) => value as string,
deserialize: (value) => value,
});

await brinedb.init();
await brinedb.clear();

const setInitialManyData: [string, string][] = [];
const size = 1_000;
Expand All @@ -36,20 +40,23 @@ describe("Benchmark", () => {

bench
.add("get", async () => {
const res = await brinedb.get(
`key-${Math.floor(Math.random() * size)}`,
);

if (res == null) {
throw new Error("Value not found");
}
await brinedb.get(`key-${Math.floor(Math.random() * size)}`);
})
.add("set", async () => {
await brinedb.set(
`key-${Math.floor(Math.random() * size)}`,
randomData(100),
);
})
.add("getMany", async () => {
await brinedb.getMany(setInitialManyData.map(([key]) => key));
})
.add("keys", async () => {
await brinedb.keys();
})
.add("values", async () => {
await brinedb.values();
})
.add("count", async () => {
await brinedb.count();
});
Expand Down
Loading

0 comments on commit 70d78da

Please sign in to comment.