-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create and validate abstract queries (#302)
* Introduce query module with find and find_many methods * First sketches on how the API could look like * Add filtering options, automatically merge them * Add tests for merging elements * Add test converting to single element * Add more general filter tests * Add doc-string to upsert method * Correct doc-string * Rename Range to Interval * Share Field type between Order and Filter structs, try different names * Delete wrong doc-string line * Clean up a little bit * Derive PartialEq, add some more constructors * Separate files into own module * Derive Default for Find struct as well * Prepare validation method for query * Expose struct fields * Allow all of this to be unused for now * Make Cursor a trait * Implement Cursor for String only for tests * Add a few more tests * Implement validation logic * Convert from string and query value to filter * Make clippy happy * Add TODO * Remove store for now, we do this in a separate PR * Rename helpers to test_utils * Move code a little * Formatting * Add Select struct to select fields in document * Validate selected fields as well * Extend validation test case a little * Simplfy test helpers * Move errors over to query module * Add some tests for validation * Add documentation and some more tests * Add entry to CHANGELOG.md
- Loading branch information
1 parent
89ff11e
commit 0dfddcd
Showing
12 changed files
with
1,353 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
use thiserror::Error; | ||
|
||
/// Validation errors for "abstract" queries. | ||
#[derive(Error, Debug)] | ||
pub enum QueryError { | ||
/// Selection contains a field which is not part of the given schema. | ||
#[error("Can't select unknown field '{0}'")] | ||
SelectFieldUnknown(String), | ||
|
||
/// Filter contains a field which is not part of the given schema. | ||
#[error("Can't apply filter on unknown field '{0}'")] | ||
FilterFieldUnknown(String), | ||
|
||
/// Ordering is based on a field which is not part of the given schema. | ||
#[error("Can't apply ordering on unknown field '{0}'")] | ||
OrderFieldUnknown(String), | ||
|
||
/// Filter can not be applied to a field of given type. | ||
#[error("Filter type '{0}' for field '{1}' is not matching schema type '{2}'")] | ||
FilterInvalidType(String, String, String), | ||
|
||
/// Set filters are not possible for boolean values. | ||
#[error("Can't apply set filter as field '{0}' is of type boolean")] | ||
FilterInvalidSet(String), | ||
|
||
/// Interval filters arae not possible for booleans and relations. | ||
#[error("Can't apply interval filter as field '{0}' is not of type string, float or integer")] | ||
FilterInvalidInterval(String), | ||
|
||
/// Search filters can only be applied on strings. | ||
#[error("Can't apply search filter as field '{0}' is not of type string")] | ||
FilterInvalidSearch(String), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
use std::convert::TryFrom; | ||
|
||
use anyhow::bail; | ||
use p2panda_rs::schema::FieldName; | ||
|
||
/// Pre-defined constant fields for every document. | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub enum MetaField { | ||
/// Identifier of the document. | ||
DocumentId, | ||
|
||
/// Latest version of the document. | ||
DocumentViewId, | ||
|
||
/// Public key of the original author (owner) of the document. | ||
Owner, | ||
|
||
/// Flag indicating if document was edited at least once. | ||
Edited, | ||
|
||
/// Flag indicating if document was deleted. | ||
Deleted, | ||
} | ||
|
||
impl TryFrom<&str> for MetaField { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(value: &str) -> Result<Self, Self::Error> { | ||
match value { | ||
"documentId" => Ok(MetaField::DocumentId), | ||
"viewId" => Ok(MetaField::DocumentViewId), | ||
"owner" => Ok(MetaField::Owner), | ||
"edited" => Ok(MetaField::Edited), | ||
"deleted" => Ok(MetaField::Deleted), | ||
_ => bail!("Unknown meta field"), | ||
} | ||
} | ||
} | ||
|
||
impl ToString for MetaField { | ||
fn to_string(&self) -> String { | ||
match self { | ||
MetaField::DocumentId => "documentId", | ||
MetaField::DocumentViewId => "viewId", | ||
MetaField::Owner => "owner", | ||
MetaField::Edited => "edited", | ||
MetaField::Deleted => "deleted", | ||
} | ||
.to_string() | ||
} | ||
} | ||
|
||
/// Fields can be either defined by the regarding schema (application fields) or are constants | ||
/// (meta fields) like the identifier of the document itself. | ||
/// | ||
/// Fields can be selected, ordered or filtered. Use the regarding structs to apply settings on top | ||
/// of these fields. | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub enum Field { | ||
/// Pre-defined, constant fields for every document. | ||
Meta(MetaField), | ||
|
||
/// Field defined by the schema. | ||
Field(FieldName), | ||
} | ||
|
||
impl Field { | ||
/// Returns a new application field. | ||
pub fn new(name: &str) -> Self { | ||
Self::Field(name.to_string()) | ||
} | ||
} | ||
|
||
impl From<&str> for Field { | ||
fn from(value: &str) -> Self { | ||
Self::Field(value.to_string()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::Field; | ||
|
||
#[test] | ||
fn create_field_from_str() { | ||
let field: Field = "message".into(); | ||
assert_eq!(field, Field::new("message")); | ||
assert_eq!(Field::Field("favorite".to_string()), Field::new("favorite")); | ||
} | ||
} |
Oops, something went wrong.