New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for currently unsupported JSON/JSONB operators #3032
Comments
|
Believe it or not, I was considering suggesting this some time last week! Edit: @weiznich what version do we add this in, current or master? |
|
@czotomo Any new feature should target the master branch. |
|
Jsonb concat PR: #3035 |
|
Alright, let's continue with the trivial ones. Edit: |
|
Alright, I'll implement the array and object indexing operators by ints and strings, I don't see a reason to split this work. |
|
Hey, I'd like to get my hands dirty with these two operators if that's ok.. |
|
@czotomo You can likely combine these two operations
in one function by using a similar trick as for implementing the (Also these operators need there own ExpressionMethods trait as these need to be implemented for the Json type as well. Again thats possible by using a corresponding auxiliary trait implemented for jsonb and json + their nullable variants.) @mrbuzz |
|
Hi, I'd like to try adding support for these two operators. |
|
@czotomo Would it be possible to team up on this? Quite new to Rust, but have plenty of development experience. I'd be happy with just being a fly on the wall, and just see how the problem is solved. |
|
@gamesbrainiac sure, I did not do too much work on these four yet. Please reach out to me on gitter (same handle as on Github) so we can sync. |
|
I'd like to take these three operators as my next task: |
|
@gamesbrainiac @czotomo Is there any information that I could provide to help you? As additional side note: Opening a WIP PR could also be a good idea, as this makes it easier for others to comment on specific code issues, as they have access to the whole change. |
|
@mrbuzz I'm happy to answer any question that comes up. Just ask . |
|
I'll try these operators next. Edit: they aren't marked as |
|
@zaneduffield Yes those would need marker traits for json/jsonb. So basically this thing here: diesel/diesel/src/pg/expression/expression_methods.rs Lines 1554 to 1564 in b479e83
but so that the helper trait ( |
|
This is the progress we've made so far. gamesbrainiac@3e857bb We tried the tests, but it keeps failing. It should work, but it's hard to figure out what's wrong. @mrbuzz Do you have gitter? We usually communicate using that. |
|
@weiznich is there a diesel development / maintenance Gitter room where people who know ins and outs hang out, or are the conversations strictly performed in issues' and PRs' comments? |
|
@gamesbrainiac @@ -1363,7 +1363,7 @@ pub trait PgAnyJsonExpressionMethods: Expression + Sized {
/// .values((name.eq("Claus"), address.eq(&santas_address)))
/// .execute(conn)?;
///
- /// let santas_postcode = contacts.select(address.retrieve_as_object("postcode")).get_result::<serde_json::Value>(conn)?;
+ /// let santas_postcode = contacts.select(address.retrieve_as_object::<diesel::sql_types::Text, _>("postcode")).get_result::<serde_json::Value>(conn)?;
/// assert_eq!(santas_postcode, serde_json::json!("99705"));
///
///
@@ -1388,7 +1388,8 @@ pub trait PgAnyJsonExpressionMethods: Expression + Sized {
///
/// let roberts_second_address_in_db = contacts
/// .filter(name.eq("Robert Downey Jr."))
- /// .select(address.retrieve_as_object(1))
+ /// .select(address.retrieve_as_object::<
+ /// diesel::sql_types::Integer, _>(1))
/// .get_result::<serde_json::Value>(conn)?;
///
/// let roberts_second_address = serde_json::json!({
@@ -1405,9 +1406,9 @@ pub trait PgAnyJsonExpressionMethods: Expression + Sized {
/// # Ok(())
/// # }
/// ```
- fn retrieve_as_object<T, ST>(self, other: T) -> dsl::RetrieveAsObjectJsonb<Self, T, ST>
+ fn retrieve_as_object<ST, T>(self, other: T) -> dsl::RetrieveAsObjectJsonb<Self, T, ST>
where
- ST: SqlType + TypedExpressionType,
+ ST: SqlType + TypedExpressionType + TextOrInteger,
T: AsExpression<ST>,
{
Grouped(RetrieveAsObjectJsonb::new(self, other.as_expression()))
@@ -1432,6 +1433,5 @@ impl<T> PgAnyJsonExpressionMethods for T
where
Self::SqlType: JsonOrNullableJsonOrJsonbOrNullableJsonb,
T: Expression,
- T::SqlType: TextOrInteger,
{
}To explain that a bit: The change in line 1432 (removing The other changes work around the fact that rustc cannot infer the correct sql type for @czotomo It's fine to ask these question in the normal gitter room, but if there is need for that we can just create a new room for that. |
|
Perhaps we have two methods? Or perhaps we always get text, and cast it later to Integer? You're right, this looks very ugly. |
Just opened a draft PR #3044 for the remove key operators. I used an extra generic parameter to carry the input type as @gamesbrainiac and @czotomo did in their implementation.
Yep! Same name as on Github. Feel free to ping me any time |
|
I just want to leave a comment here that I'm away for this week. So don't expect prompt answers from me. I will try yo answer the outstanding questions next week. |
|
@mrbuzz @gamesbrainiac @czotomo Sorry for being away so long. I've pushed #3092 which contains all of your work + some fixes to the operators. Additionally it adds the missing operators. Feel free to leave comments about potential improvements on that PR. |
|
@weiznich should these operators be mentioned in the changelog for version 2? |
|
@czotomo Yes that would be great |


Diesel currently supports the postgres json and jsonb types. We do not provide built-in support for various operators available for these types. This is a tracking issue for adding support for these operators.
The general strategy for adding support for new operators is as following:
infix_operator!(). The contains operator would be defined as following:infix_operator!(KeyExists, " ? ", backend: Pg);These operators can be defined here. If there is already an existing definition, this step could be skipped.ExpressionMethodsextension trait for the corresponding types. This only needs to happen once forjsonband once forjsonb+json. See thePgRangeExpressionMethodstrait here as example.ExpressionMethodstrait. See here for an example for a different operator/type. This definition should:TRYBUILD=overwrite cargo testinside ofdiesel_compile_tests. (This is required if you've added a new operator based oninfix_operator!Operator list:
json/jsonb -> integer(indexing by index, returnsjson/jsonb) **json/jsonb -> text(indexing by key name, returnsjson/jsonb) **json/jsonb ->> integer(indexing by index, returns field astext) **json/jsonb ->> text(indexing by key name, returns field astext) **json/jsonb #> text[](indexing by path, returns field asjson/jsonb) *json/jsonb #>> text[](indexing by path, returns field astext) *jsonb @> jsonb(checks if the second value is contained by the first value, returns aboolean) *jsonb <@ jsonb(checks if the first value is contained by the second value, returns aboolean) *jsonb ? text(checks if a string exists as top level key in the given json, returns aboolean) *jsonb ?| text[](checks if any of the strings exists as top level key in the given json, returns aboolean) *jsonb ?& text[](checks if all of the strings exist as top level key in the given json, returns aboolean) *jsonb || jsonb(concats two json values, returnsjsonb) *jsonb - text(remove the key given as string from the json, returnsjsonb) **jsonb - text[](removes all keys given as string from the json, returnsjsonb) **jsonb - integer(removes the field with the given index from the json, returnsjsonb) **jsonb #- text[](removes the given path from the json, returnsjsonb) *jsonb @? jsonpath(Does JSON path return any item for the specified JSON value?, returns aboolean) ***jsonb @@ jsonpath (Returns the result of a JSON path predicate check for the specified JSON value. Only the first item of the result is taken into account. If the result is not Boolean, then NULL is returned., returns aboolean`) ***Items marked with one
*can follow the instructions directly, items marked with**require additional work to unify the different input types behind a common operator/function call (See here for a general example on how to abstract over expressions of different types), items marked with***likely require additional design work.Please add a comment to this issue if you plan to work on a specific operator.
If there is anything unclear about how to add a support for a specific operator just ask and we will try to answer your questions.
The text was updated successfully, but these errors were encountered: