2021-10-28 17:18:32 +08:00
use std ::collections ::BTreeSet ;
2021-06-14 22:58:38 +08:00
use std ::convert ::Infallible ;
2021-06-10 23:31:08 +08:00
use std ::error ::Error as StdError ;
2021-06-14 22:58:38 +08:00
use std ::{ fmt , io , str } ;
2021-06-09 23:05:46 +08:00
2021-06-17 00:33:33 +08:00
use heed ::{ Error as HeedError , MdbError } ;
2021-06-14 22:58:38 +08:00
use rayon ::ThreadPoolBuildError ;
2021-06-10 23:31:08 +08:00
use serde_json ::{ Map , Value } ;
2021-09-28 01:07:22 +08:00
use crate ::{ CriterionError , DocumentId , FieldId , SortError } ;
2021-06-10 21:55:22 +08:00
2021-06-10 23:31:08 +08:00
pub type Object = Map < String , Value > ;
2021-06-09 23:05:46 +08:00
2021-09-02 21:57:40 +08:00
pub fn is_reserved_keyword ( keyword : & str ) -> bool {
2021-09-20 23:21:02 +08:00
[ " _geo " , " _geoDistance " , " _geoPoint " , " _geoRadius " ] . contains ( & keyword )
2021-09-02 21:57:40 +08:00
}
2021-06-10 23:31:08 +08:00
#[ derive(Debug) ]
2021-06-09 23:05:46 +08:00
pub enum Error {
InternalError ( InternalError ) ,
IoError ( io ::Error ) ,
UserError ( UserError ) ,
}
2021-06-10 23:31:08 +08:00
#[ derive(Debug) ]
2021-06-09 23:05:46 +08:00
pub enum InternalError {
2021-06-14 22:58:38 +08:00
DatabaseClosing ,
2021-06-10 23:31:08 +08:00
DatabaseMissingEntry { db_name : & 'static str , key : Option < & 'static str > } ,
2021-06-09 23:05:46 +08:00
FieldIdMapMissingEntry ( FieldIdMapMissingEntry ) ,
2022-03-24 00:28:41 +08:00
FieldIdMappingMissingEntry { key : FieldId } ,
2021-06-14 22:58:38 +08:00
Fst ( fst ::Error ) ,
GrenadInvalidCompressionType ,
2022-02-16 22:28:48 +08:00
GrenadInvalidFormatVersion ,
2021-06-10 23:31:08 +08:00
IndexingMergingKeys { process : & 'static str } ,
2021-06-10 21:55:22 +08:00
InvalidDatabaseTyping ,
2021-06-14 22:58:38 +08:00
RayonThreadPool ( ThreadPoolBuildError ) ,
SerdeJson ( serde_json ::Error ) ,
Serialization ( SerializationError ) ,
Store ( MdbError ) ,
Utf8 ( str ::Utf8Error ) ,
2021-06-10 21:55:22 +08:00
}
2021-06-10 23:31:08 +08:00
#[ derive(Debug) ]
2021-06-10 21:55:22 +08:00
pub enum SerializationError {
Decoding { db_name : Option < & 'static str > } ,
Encoding { db_name : Option < & 'static str > } ,
InvalidNumberSerialization ,
2021-06-09 23:05:46 +08:00
}
2021-06-10 23:31:08 +08:00
#[ derive(Debug) ]
2021-06-09 23:05:46 +08:00
pub enum FieldIdMapMissingEntry {
2021-06-15 17:10:50 +08:00
FieldId { field_id : FieldId , process : & 'static str } ,
FieldName { field_name : String , process : & 'static str } ,
2021-06-09 23:05:46 +08:00
}
2021-06-10 23:31:08 +08:00
#[ derive(Debug) ]
2021-06-09 23:05:46 +08:00
pub enum UserError {
2021-06-10 21:55:22 +08:00
AttributeLimitReached ,
2021-09-22 22:02:07 +08:00
CriterionError ( CriterionError ) ,
2021-06-10 21:55:22 +08:00
DocumentLimitReached ,
2021-06-10 23:31:08 +08:00
InvalidDocumentId { document_id : Value } ,
2021-10-28 17:18:32 +08:00
InvalidFacetsDistribution { invalid_facets_name : BTreeSet < String > } ,
2022-05-03 01:19:50 +08:00
InvalidGeoField ( GeoError ) ,
2021-11-05 00:24:55 +08:00
InvalidFilter ( String ) ,
2021-10-28 17:18:32 +08:00
InvalidSortableAttribute { field : String , valid_fields : BTreeSet < String > } ,
2021-09-07 16:37:57 +08:00
SortRankingRuleMissing ,
2021-06-14 22:58:38 +08:00
InvalidStoreFile ,
2021-06-23 19:56:13 +08:00
MaxDatabaseSizeReached ,
2021-10-26 23:49:35 +08:00
MissingDocumentId { primary_key : String , document : Object } ,
2021-06-10 21:55:22 +08:00
MissingPrimaryKey ,
NoSpaceLeftOnDevice ,
2021-10-26 23:49:35 +08:00
PrimaryKeyCannotBeChanged ( String ) ,
2021-06-14 22:58:38 +08:00
SerdeJson ( serde_json ::Error ) ,
2021-09-28 01:07:22 +08:00
SortError ( SortError ) ,
2021-06-14 22:58:38 +08:00
UnknownInternalDocumentId { document_id : DocumentId } ,
2022-03-31 20:15:02 +08:00
InvalidMinTypoWordLenSetting ( u8 , u8 ) ,
2021-06-10 21:55:22 +08:00
}
2022-05-03 01:19:50 +08:00
#[ derive(Debug) ]
pub enum GeoError {
MissingLatitude { document_id : Value } ,
MissingLongitude { document_id : Value } ,
BadLatitude { document_id : Value , value : Value } ,
BadLongitude { document_id : Value , value : Value } ,
}
2021-06-10 21:55:22 +08:00
impl From < io ::Error > for Error {
fn from ( error : io ::Error ) -> Error {
// TODO must be improved and more precise
Error ::IoError ( error )
}
}
2021-06-14 22:58:38 +08:00
impl From < fst ::Error > for Error {
fn from ( error : fst ::Error ) -> Error {
Error ::InternalError ( InternalError ::Fst ( error ) )
}
}
2021-06-17 00:33:33 +08:00
impl < E > From < grenad ::Error < E > > for Error
where
Error : From < E > ,
{
2021-06-14 22:58:38 +08:00
fn from ( error : grenad ::Error < E > ) -> Error {
match error {
grenad ::Error ::Io ( error ) = > Error ::IoError ( error ) ,
grenad ::Error ::Merge ( error ) = > Error ::from ( error ) ,
grenad ::Error ::InvalidCompressionType = > {
Error ::InternalError ( InternalError ::GrenadInvalidCompressionType )
2021-06-17 00:33:33 +08:00
}
2022-02-16 22:28:48 +08:00
grenad ::Error ::InvalidFormatVersion = > {
Error ::InternalError ( InternalError ::GrenadInvalidFormatVersion )
}
2021-06-14 22:58:38 +08:00
}
}
}
impl From < str ::Utf8Error > for Error {
fn from ( error : str ::Utf8Error ) -> Error {
Error ::InternalError ( InternalError ::Utf8 ( error ) )
}
}
impl From < Infallible > for Error {
fn from ( _error : Infallible ) -> Error {
unreachable! ( )
}
}
2021-06-10 21:55:22 +08:00
impl From < HeedError > for Error {
fn from ( error : HeedError ) -> Error {
use self ::Error ::* ;
use self ::InternalError ::* ;
use self ::SerializationError ::* ;
use self ::UserError ::* ;
2021-06-09 23:05:46 +08:00
2021-06-10 21:55:22 +08:00
match error {
HeedError ::Io ( error ) = > Error ::from ( error ) ,
2021-06-15 23:20:33 +08:00
HeedError ::Mdb ( MdbError ::MapFull ) = > UserError ( MaxDatabaseSizeReached ) ,
2021-06-10 21:55:22 +08:00
HeedError ::Mdb ( MdbError ::Invalid ) = > UserError ( InvalidStoreFile ) ,
2021-06-14 22:58:38 +08:00
HeedError ::Mdb ( error ) = > InternalError ( Store ( error ) ) ,
HeedError ::Encoding = > InternalError ( Serialization ( Encoding { db_name : None } ) ) ,
HeedError ::Decoding = > InternalError ( Serialization ( Decoding { db_name : None } ) ) ,
2021-06-10 21:55:22 +08:00
HeedError ::InvalidDatabaseTyping = > InternalError ( InvalidDatabaseTyping ) ,
HeedError ::DatabaseClosing = > InternalError ( DatabaseClosing ) ,
}
}
2021-06-09 23:05:46 +08:00
}
2021-06-10 23:31:08 +08:00
2021-06-14 22:58:38 +08:00
impl From < ThreadPoolBuildError > for Error {
fn from ( error : ThreadPoolBuildError ) -> Error {
Error ::InternalError ( InternalError ::RayonThreadPool ( error ) )
}
}
impl From < FieldIdMapMissingEntry > for Error {
fn from ( error : FieldIdMapMissingEntry ) -> Error {
Error ::InternalError ( InternalError ::FieldIdMapMissingEntry ( error ) )
}
}
impl From < InternalError > for Error {
fn from ( error : InternalError ) -> Error {
Error ::InternalError ( error )
}
}
impl From < UserError > for Error {
fn from ( error : UserError ) -> Error {
Error ::UserError ( error )
}
}
impl From < SerializationError > for Error {
fn from ( error : SerializationError ) -> Error {
Error ::InternalError ( InternalError ::Serialization ( error ) )
}
}
2021-06-10 23:31:08 +08:00
impl fmt ::Display for Error {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
2021-10-26 23:49:35 +08:00
Self ::InternalError ( error ) = > write! ( f , " internal: {}. " , error ) ,
2021-06-10 23:31:08 +08:00
Self ::IoError ( error ) = > error . fmt ( f ) ,
Self ::UserError ( error ) = > error . fmt ( f ) ,
}
}
}
impl StdError for Error { }
impl fmt ::Display for InternalError {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
Self ::DatabaseMissingEntry { db_name , key } = > {
2021-10-26 23:49:35 +08:00
write! ( f , " Missing {} in the {} database. " , key . unwrap_or ( " key " ) , db_name )
2021-06-17 00:33:33 +08:00
}
2021-06-10 23:31:08 +08:00
Self ::FieldIdMapMissingEntry ( error ) = > error . fmt ( f ) ,
2022-03-24 00:28:41 +08:00
Self ::FieldIdMappingMissingEntry { key } = > {
write! ( f , " Missing {} in the field id mapping. " , key )
}
2021-06-14 22:58:38 +08:00
Self ::Fst ( error ) = > error . fmt ( f ) ,
Self ::GrenadInvalidCompressionType = > {
2021-10-26 23:49:35 +08:00
f . write_str ( " Invalid compression type have been specified to grenad. " )
2021-06-17 00:33:33 +08:00
}
2022-02-16 22:28:48 +08:00
Self ::GrenadInvalidFormatVersion = > {
f . write_str ( " Invalid grenad file with an invalid version format. " )
}
2021-06-10 23:31:08 +08:00
Self ::IndexingMergingKeys { process } = > {
2021-10-26 23:49:35 +08:00
write! ( f , " Invalid merge while processing {}. " , process )
2021-06-17 00:33:33 +08:00
}
2021-06-14 22:58:38 +08:00
Self ::Serialization ( error ) = > error . fmt ( f ) ,
2021-06-10 23:31:08 +08:00
Self ::InvalidDatabaseTyping = > HeedError ::InvalidDatabaseTyping . fmt ( f ) ,
2021-06-14 22:58:38 +08:00
Self ::RayonThreadPool ( error ) = > error . fmt ( f ) ,
Self ::SerdeJson ( error ) = > error . fmt ( f ) ,
2021-06-10 23:31:08 +08:00
Self ::DatabaseClosing = > HeedError ::DatabaseClosing . fmt ( f ) ,
2021-06-14 22:58:38 +08:00
Self ::Store ( error ) = > error . fmt ( f ) ,
Self ::Utf8 ( error ) = > error . fmt ( f ) ,
2021-06-10 23:31:08 +08:00
}
}
}
impl StdError for InternalError { }
impl fmt ::Display for UserError {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
2021-11-06 23:34:30 +08:00
Self ::InvalidFilter ( error ) = > f . write_str ( error ) ,
2021-11-04 20:19:32 +08:00
Self ::AttributeLimitReached = > f . write_str ( " A document cannot contain more than 65,535 fields. " ) ,
2021-09-22 22:59:23 +08:00
Self ::CriterionError ( error ) = > write! ( f , " {} " , error ) ,
2021-10-26 23:49:35 +08:00
Self ::DocumentLimitReached = > f . write_str ( " Maximum number of documents reached. " ) ,
2021-06-23 19:56:13 +08:00
Self ::InvalidFacetsDistribution { invalid_facets_name } = > {
let name_list =
invalid_facets_name . iter ( ) . map ( AsRef ::as_ref ) . collect ::< Vec < _ > > ( ) . join ( " , " ) ;
write! (
f ,
2021-10-26 23:49:35 +08:00
" Invalid facet distribution, the fields `{}` are not set as filterable. " ,
2021-06-23 19:56:13 +08:00
name_list
)
}
2022-05-03 01:19:50 +08:00
Self ::InvalidGeoField ( error ) = > write! ( f , " {error} " ) ,
2021-06-10 23:31:08 +08:00
Self ::InvalidDocumentId { document_id } = > {
2021-10-26 23:49:35 +08:00
let document_id = match document_id {
Value ::String ( id ) = > id . clone ( ) ,
_ = > document_id . to_string ( ) ,
} ;
2021-06-22 17:31:58 +08:00
write! (
f ,
2021-10-26 23:49:35 +08:00
" Document identifier `{}` is invalid. \
A document identifier can be of type integer or string , \
only composed of alphanumeric characters ( a - z A - Z 0 - 9 ) , hyphens ( - ) and underscores ( _ ) . " ,
document_id
2021-06-22 17:31:58 +08:00
)
2021-06-17 00:33:33 +08:00
}
2021-08-23 17:37:18 +08:00
Self ::InvalidSortableAttribute { field , valid_fields } = > {
let valid_names =
valid_fields . iter ( ) . map ( AsRef ::as_ref ) . collect ::< Vec < _ > > ( ) . join ( " , " ) ;
2022-03-05 03:34:03 +08:00
if valid_names . is_empty ( ) {
write! (
f ,
" Attribute `{}` is not sortable. This index does not have configured sortable attributes. " ,
field
)
} else {
write! (
f ,
" Attribute `{}` is not sortable. Available sortable attributes are: `{}`. " ,
field , valid_names
)
}
2021-08-23 17:37:18 +08:00
}
2021-09-07 16:37:57 +08:00
Self ::SortRankingRuleMissing = > f . write_str (
2021-10-26 23:49:35 +08:00
" The sort ranking rule must be specified in the \
ranking rules settings to use the sort parameter at search time . " ,
2021-09-07 16:37:57 +08:00
) ,
2021-10-26 23:49:35 +08:00
Self ::MissingDocumentId { primary_key , document } = > {
2021-06-10 23:31:08 +08:00
let json = serde_json ::to_string ( document ) . unwrap ( ) ;
2021-10-26 23:49:35 +08:00
write! ( f , " Document doesn't have a `{}` attribute: `{}`. " , primary_key , json )
2021-06-17 00:33:33 +08:00
}
2021-11-04 20:19:32 +08:00
Self ::MissingPrimaryKey = > f . write_str ( " The primary key inference process failed because the engine did not find any fields containing `id` substring in their name. If your document identifier does not contain any `id` substring, you can set the primary key of the index. " ) ,
2021-11-03 18:24:06 +08:00
Self ::MaxDatabaseSizeReached = > f . write_str ( " Maximum database size has been reached. " ) ,
Self ::NoSpaceLeftOnDevice = > f . write_str ( " There is no more space left on the device. Consider increasing the size of the disk/partition. " ) ,
Self ::InvalidStoreFile = > f . write_str ( " The database file is in an invalid state. " ) ,
2021-10-26 23:49:35 +08:00
Self ::PrimaryKeyCannotBeChanged ( primary_key ) = > {
write! ( f , " Index already has a primary key: `{}`. " , primary_key )
2021-06-17 00:33:33 +08:00
}
2021-06-14 22:58:38 +08:00
Self ::SerdeJson ( error ) = > error . fmt ( f ) ,
2021-09-28 01:07:22 +08:00
Self ::SortError ( error ) = > write! ( f , " {} " , error ) ,
2021-06-14 22:58:38 +08:00
Self ::UnknownInternalDocumentId { document_id } = > {
2021-10-26 23:49:35 +08:00
write! ( f , " An unknown internal document id have been used: `{}`. " , document_id )
2021-06-17 00:33:33 +08:00
}
2022-03-31 20:15:02 +08:00
Self ::InvalidMinTypoWordLenSetting ( one , two ) = > write! ( f , " `minWordSizeForTypos` setting is invalid. `oneTypo` and `twoTypos` fields should be between `0` and `255`, and `twoTypos` should be greater or equals to `oneTypo` but found `oneTypo: {}` and twoTypos: {}`. " , one , two ) ,
2021-06-10 23:31:08 +08:00
}
}
}
impl StdError for UserError { }
impl fmt ::Display for FieldIdMapMissingEntry {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
2021-06-15 17:10:50 +08:00
Self ::FieldId { field_id , process } = > {
write! ( f , " unknown field id {} coming from the {} process " , field_id , process )
2021-06-17 00:33:33 +08:00
}
2021-06-15 17:10:50 +08:00
Self ::FieldName { field_name , process } = > {
write! ( f , " unknown field name {} coming from the {} process " , field_name , process )
2021-06-17 00:33:33 +08:00
}
2021-06-10 23:31:08 +08:00
}
}
}
impl StdError for FieldIdMapMissingEntry { }
2022-05-03 01:19:50 +08:00
impl From < GeoError > for UserError {
fn from ( geo_error : GeoError ) -> Self {
UserError ::InvalidGeoField ( geo_error )
}
}
impl fmt ::Display for GeoError {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
match self {
GeoError ::MissingLatitude { document_id } = > {
write! ( f , " Could not find latitude in the document with the id: `{document_id}`. Was expecting a `_geo.lat` field. " )
}
GeoError ::MissingLongitude { document_id } = > {
write! ( f , " Could not find longitude in the document with the id: `{document_id}`. Was expecting a `_geo.lng` field. " )
}
GeoError ::BadLatitude { document_id , value } = > {
write! ( f , " Could not parse latitude in the document with the id: `{document_id}`. Was expecting a number but instead got `{value}`. " )
}
GeoError ::BadLongitude { document_id , value } = > {
write! ( f , " Could not parse longitude in the document with the id: `{document_id}`. Was expecting a number but instead got `{value}`. " )
}
}
}
}
impl StdError for GeoError { }
2021-06-10 23:31:08 +08:00
impl fmt ::Display for SerializationError {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
Self ::Decoding { db_name : Some ( name ) } = > {
write! ( f , " decoding from the {} database failed " , name )
2021-06-17 00:33:33 +08:00
}
2021-06-10 23:31:08 +08:00
Self ::Decoding { db_name : None } = > f . write_str ( " decoding failed " ) ,
Self ::Encoding { db_name : Some ( name ) } = > {
write! ( f , " encoding into the {} database failed " , name )
2021-06-17 00:33:33 +08:00
}
2021-06-10 23:31:08 +08:00
Self ::Encoding { db_name : None } = > f . write_str ( " encoding failed " ) ,
Self ::InvalidNumberSerialization = > f . write_str ( " number is not a valid finite number " ) ,
}
}
}
impl StdError for SerializationError { }
2022-03-05 03:34:03 +08:00
#[ test ]
fn conditionally_lookup_for_error_message ( ) {
let prefix = " Attribute `name` is not sortable. " ;
let messages = vec! [
( BTreeSet ::new ( ) , " This index does not have configured sortable attributes. " ) ,
( BTreeSet ::from ( [ " age " . to_string ( ) ] ) , " Available sortable attributes are: `age`. " ) ,
] ;
for ( list , suffix ) in messages {
let err =
UserError ::InvalidSortableAttribute { field : " name " . to_string ( ) , valid_fields : list } ;
assert_eq! ( err . to_string ( ) , format! ( " {} {} " , prefix , suffix ) ) ;
}
}