commands/list: implement new list command to the search channel

Closes #22
This commit is contained in:
Dmitriy Pleshevskiy 2022-10-24 18:06:28 +03:00 committed by pleshevskiy
parent 65dfd3136c
commit 529105d340
8 changed files with 198 additions and 17 deletions

View file

@ -2,7 +2,7 @@ version: '3'
services: services:
sonic: sonic:
image: valeriansaliou/sonic:v1.3.5 image: valeriansaliou/sonic:v1.4.0
ports: ports:
- 36999:1491 - 36999:1491
volumes: volumes:

View file

@ -1,5 +1,20 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1662096612, "lastModified": 1662096612,
@ -18,22 +33,31 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"utils": "utils" "sonic-server": "sonic-server"
} }
}, },
"utils": { "sonic-server": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1666618211,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-kKeIM9dXUi8eYcvSomx8kqSqq9zmqMx4mE5wdpEZ6O8=",
"owner": "numtide", "owner": "pleshevskiy",
"repo": "flake-utils", "repo": "sonic",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "e83de87ebd2e29b210c8cc6e7dfed5d2f14a0d24",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "numtide", "owner": "pleshevskiy",
"repo": "flake-utils", "repo": "sonic",
"type": "github" "type": "github"
} }
} }

View file

@ -1,17 +1,26 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
sonic-server = {
url = "github:pleshevskiy/sonic";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
}; };
outputs = { self, nixpkgs, utils }: outputs = inputs @ { self, nixpkgs, flake-utils, ... }:
utils.lib.eachDefaultSystem (system: flake-utils.lib.eachDefaultSystem (system:
let let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs {
inherit system;
overlays = [ inputs.sonic-server.overlays.default ];
};
in in
{ {
devShell = pkgs.mkShell { devShell = pkgs.mkShell {
packages = with pkgs; [ cargo rustc rustfmt clippy rust-analyzer ]; packages = with pkgs; [ cargo rustc rustfmt clippy rust-analyzer sonic-server inetutils ];
RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc; RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc;
}; };
}); });

View file

@ -130,4 +130,35 @@ impl SearchChannel {
req: SuggestRequest, req: SuggestRequest,
); );
); );
init_command!(
/// Enumerates all words in an index.
///
/// Note: This method requires enabling the `search` feature and start
/// connection in Search mode.
///
/// ```rust,no_run
/// # use sonic_channel::*;
/// # fn main() -> result::Result<()> {
/// let search_channel = SearchChannel::start(
/// "localhost:1491",
/// "SecretPassword",
/// )?;
///
/// let result = search_channel.list(
/// ListRequest::new(Dest::col("search"))
/// )?;
/// dbg!(result);
///
/// let result = search_channel.list(
/// ListRequest::new(Dest::col("search")).limit(2)
/// )?;
/// dbg!(result);
/// # Ok(())
/// # }
/// ```
use ListCommand for fn list(
req: ListRequest,
);
);
} }

View file

@ -11,6 +11,8 @@ mod pop;
#[cfg(feature = "ingest")] #[cfg(feature = "ingest")]
mod push; mod push;
#[cfg(feature = "search")]
mod list;
#[cfg(feature = "search")] #[cfg(feature = "search")]
mod query; mod query;
#[cfg(feature = "search")] #[cfg(feature = "search")]
@ -29,9 +31,9 @@ pub(crate) use self::{
pub use self::{count::CountRequest, flush::FlushRequest, pop::PopRequest, push::PushRequest}; pub use self::{count::CountRequest, flush::FlushRequest, pop::PopRequest, push::PushRequest};
#[cfg(feature = "search")] #[cfg(feature = "search")]
pub(crate) use self::{query::QueryCommand, suggest::SuggestCommand}; pub(crate) use self::{list::ListCommand, query::QueryCommand, suggest::SuggestCommand};
#[cfg(feature = "search")] #[cfg(feature = "search")]
pub use self::{query::QueryRequest, suggest::SuggestRequest}; pub use self::{list::ListRequest, query::QueryRequest, suggest::SuggestRequest};
#[cfg(feature = "control")] #[cfg(feature = "control")]
pub(crate) use trigger::TriggerCommand; pub(crate) use trigger::TriggerCommand;

69
src/commands/list.rs Normal file
View file

@ -0,0 +1,69 @@
use super::StreamCommand;
use crate::misc::Dest;
use crate::protocol;
use crate::result::*;
/// Parameters for the `suggest` command.
#[derive(Debug)]
pub struct ListRequest {
/// Collection and bucket where we should enumerate all words in index.
pub dest: Dest,
/// Limit of result words.
pub limit: Option<usize>,
/// Offset of result words.
pub offset: Option<usize>,
}
impl ListRequest {
/// Creates a base suggest request.
pub fn new(dest: Dest) -> Self {
Self {
dest,
limit: None,
offset: None,
}
}
/// Set a limit for the request.
pub fn limit(mut self, limit: usize) -> Self {
self.limit = Some(limit);
self
}
/// Set an offset for the request.
pub fn offset(mut self, offset: usize) -> Self {
self.offset = Some(offset);
self
}
}
#[derive(Debug)]
pub struct ListCommand {
pub(crate) req: ListRequest,
}
impl StreamCommand for ListCommand {
type Response = Vec<String>;
fn request(&self) -> protocol::Request {
let dest = &self.req.dest;
protocol::Request::List {
collection: dest.collection().clone(),
bucket: dest
.bucket_opt()
.cloned()
.unwrap_or_else(|| String::from("default")),
limit: self.req.limit,
offset: self.req.offset,
}
}
fn receive(&self, res: protocol::Response) -> Result<Self::Response> {
if let protocol::Response::Event(protocol::EventKind::List, _id, words) = res {
Ok(words)
} else {
Err(Error::WrongResponse)
}
}
}

View file

@ -76,6 +76,17 @@ impl Protocol {
} }
} }
#[rustfmt::skip]
Request::List { collection, bucket, limit, offset } => {
write!(res, "LIST {} {}", collection, bucket)?;
if let Some(limit) = limit {
write!(res, " LIMIT({})", limit)?;
}
if let Some(offset) = offset {
write!(res, " OFFSET({})", offset)?;
}
}
Request::Trigger(triger_req) => match triger_req { Request::Trigger(triger_req) => match triger_req {
TriggerRequest::Consolidate => write!(res, "TRIGGER consolidate")?, TriggerRequest::Consolidate => write!(res, "TRIGGER consolidate")?,
TriggerRequest::Backup(path) => { TriggerRequest::Backup(path) => {
@ -123,6 +134,7 @@ impl Protocol {
let event_kind = match segments.next() { let event_kind = match segments.next() {
Some("SUGGEST") => Ok(EventKind::Suggest), Some("SUGGEST") => Ok(EventKind::Suggest),
Some("QUERY") => Ok(EventKind::Query), Some("QUERY") => Ok(EventKind::Query),
Some("LIST") => Ok(EventKind::List),
_ => Err(Error::WrongResponse), _ => Err(Error::WrongResponse),
}?; }?;
@ -202,6 +214,7 @@ pub struct StartedPayload {
pub enum EventKind { pub enum EventKind {
Suggest, Suggest,
Query, Query,
List,
} }
//===========================================================================// //===========================================================================//
@ -223,6 +236,12 @@ pub enum Request {
word: String, word: String,
limit: Option<usize>, limit: Option<usize>,
}, },
List {
collection: String,
bucket: String,
limit: Option<usize>,
offset: Option<usize>,
},
Query { Query {
collection: String, collection: String,
bucket: String, bucket: String,

27
tests/list_command.rs Normal file
View file

@ -0,0 +1,27 @@
mod common;
use common::*;
const COLLECTION: &str = "Search";
#[test]
fn should_list_all_words() {
let bucket = "suggest_nearest";
let title = "Sweet Teriyaki Beef Skewers";
let dest = Dest::col_buc(COLLECTION, bucket);
let ingest_channel = ingest_start();
ingest_channel
.push(PushRequest::new(dest.clone().obj("1"), title))
.unwrap();
consolidate();
let search_channel = search_start();
match search_channel.list(ListRequest::new(dest.clone())) {
Ok(object_ids) => assert_eq!(object_ids, vec!["beef", "skewers", "sweet", "teriyaki"]),
Err(e) => unreachable!(),
}
flush_bucket(COLLECTION, bucket);
}