Map Filter-related stuff into the Filterable trait
I'm quite unhappy about the `::Query` thinger to disambiguate the very unambiguous associated type, but I don't think I'll be able to get rid of it.
- Id
- 20d59247cf16616e7a423da08fa3d19132882cab
- Author
- Caio
- Commit time
- 2020-02-08T11:03:20+01:00
Modified cantine_derive/src/lib.rs
use std::ops::Range;
use serde::Serialize;
use tantivy::{
collector::{Collector, SegmentCollector},
- DocId, Result, Score, SegmentLocalId, SegmentReader,
+ query::Query,
+ schema::{IntOptions, Schema, SchemaBuilder},
+ DocId, Document, Result, Score, SegmentLocalId, SegmentReader,
};
-pub use cantine_derive_internal::{Aggregable, FilterQuery};
+pub use cantine_derive_internal::{Aggregable, Filterable};
+
+pub trait Filterable: Sized {
+ type Query;
+ type Schema: FilterableSchema<Self, Self::Query>;
+
+ fn create_schema<O: Into<IntOptions>>(builder: &mut SchemaBuilder, options: O) -> Self::Schema;
+ fn load_schema(schema: &Schema) -> Result<Self::Schema>;
+}
+
+pub trait FilterableSchema<T, Q>: Sized {
+ fn add_to_doc(&self, doc: &mut Document, item: &T);
+ fn interpret(&self, query: &Q) -> Vec<Box<dyn Query>>;
+}
#[derive(Serialize, Debug, Clone)]
pub struct RangeStats<T> {
Modified cantine_derive/tests/filter_query.rs
use std::convert::TryFrom;
use tantivy::{
- schema::{SchemaBuilder, Value},
+ schema::{SchemaBuilder, Value, FAST, INDEXED},
Document,
};
-use cantine_derive::FilterQuery;
+use cantine_derive::Filterable;
-#[derive(FilterQuery, Default)]
+#[derive(Filterable, Default)]
pub struct Feat {
pub a: u64,
pub b: Option<i16>,
pub d: Option<f64>,
}
+type Query = <Feat as Filterable>::Query;
+
+#[test]
+#[should_panic]
+fn cannot_create_without_indexed_flag() {
+ let mut builder = SchemaBuilder::new();
+ Feat::create_schema(&mut builder, FAST);
+}
+
#[test]
fn filter_fields_can_read_and_write_from_schema() {
let mut builder = SchemaBuilder::new();
- let original = FeatFilterFields::from(&mut builder);
- let loaded = FeatFilterFields::try_from(&builder.build()).unwrap();
+ let original = Feat::create_schema(&mut builder, INDEXED | FAST);
+ let loaded = Feat::load_schema(&builder.build()).unwrap();
assert_eq!(original, loaded);
}
#[test]
fn filter_query_interpretation() {
let mut builder = SchemaBuilder::new();
- let fields = FeatFilterFields::from(&mut builder);
+ let fields = Feat::create_schema(&mut builder, INDEXED);
- assert_eq!(
- 0,
- fields
- .interpret(&FeatFilterQuery {
- ..FeatFilterQuery::default()
- })
- .len()
- );
+ assert_eq!(0, fields.interpret(&Query { ..Query::default() }).len());
assert_eq!(
1,
fields
- .interpret(&FeatFilterQuery {
+ .interpret(&Query {
a: Some(0..10),
- ..FeatFilterQuery::default()
+ ..Query::default()
})
.len()
);
assert_eq!(
2,
fields
- .interpret(&FeatFilterQuery {
+ .interpret(&Query {
a: Some(0..10),
c: Some(1.1..2.2),
- ..FeatFilterQuery::default()
+ ..Query::default()
})
.len()
);
#[test]
fn add_to_doc_sets_fields_properly() {
let mut builder = SchemaBuilder::new();
- let fields = FeatFilterFields::from(&mut builder);
+ let fields = Feat::create_schema(&mut builder, INDEXED);
let mut doc = Document::new();
Modified cantine_derive/internal/src/lib.rs
PathArguments, Type, Visibility,
};
-#[proc_macro_derive(FilterQuery)]
+#[proc_macro_derive(Filterable)]
pub fn derive_filter_and_agg(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let filter_query = make_filter_query(&input);
};
quote_spanned! { field.span()=>
- #name: builder.#method(#quoted, tantivy::schema::INDEXED | tantivy::schema::FAST)
+ #name: builder.#method(#quoted, flags.clone())
}
});
#(#index_fields),*
}
+ impl cantine_derive::Filterable for #feat {
+ type Query = #name;
+ type Schema = #index_name;
+
+ fn load_schema(schema: &tantivy::schema::Schema) -> tantivy::Result<Self::Schema> {
+ Self::Schema::try_from(schema)
+ }
+
+ fn create_schema<O: Into<tantivy::schema::IntOptions>>(
+ builder: &mut tantivy::schema::SchemaBuilder,
+ options: O,
+ ) -> Self::Schema {
+ Self::Schema::with_flags(builder, options)
+ }
+ }
+
+ impl cantine_derive::FilterableSchema<#feat, #name> for #index_name {
+ fn add_to_doc(&self, doc: &mut tantivy::Document, item: &#feat) {
+ <#index_name>::add_to_doc(self, doc, item)
+ }
+
+ fn interpret(&self, query: &#name) -> Vec<Box<dyn tantivy::query::Query>> {
+ <#index_name>::interpret(self, query)
+ }
+ }
+
impl std::convert::TryFrom<&tantivy::schema::Schema> for #index_name {
type Error = tantivy::TantivyError;
- fn try_from(schema: &tantivy::schema::Schema) -> std::result::Result<Self, Self::Error> {
+ fn try_from(schema: &tantivy::schema::Schema) -> Result<Self, Self::Error> {
Ok(Self {
#(#try_from_decls),*
})
impl From<&mut tantivy::schema::SchemaBuilder> for #index_name {
fn from(builder: &mut tantivy::schema::SchemaBuilder) -> Self {
- Self {
- #(#from_decls),*
- }
+ Self::with_flags(builder, tantivy::schema::INDEXED)
}
}
pub fn add_to_doc(&self, doc: &mut tantivy::Document, feat: &#feat) {
#(#add_to_doc_code);*
+ }
+
+ pub fn with_flags<O: Into<tantivy::schema::IntOptions>>(
+ builder: &mut tantivy::schema::SchemaBuilder,
+ flags: O
+ ) -> Self {
+ let flags = flags.into();
+ let new = Self {
+ #(#from_decls),*
+ };
+
+ if ! flags.is_indexed() {
+ panic!("Missing required INDEXED option");
+ }
+
+ new
}
}
}