#[cfg(not(feature = "std"))]
use crate::prelude::*;
use crate::values::PostgresValue;
use drizzle_core::expr::{AggregateKind, Expr, NonNull, Null, SQLExpr};
use drizzle_core::scope::Arg;
use drizzle_core::sql::{SQL, SQLChunk, Token};
fn jsonb_operand<'a>(operand: SQL<'a, PostgresValue<'a>>) -> SQL<'a, PostgresValue<'a>> {
SQL::func("CAST", operand.push(Token::AS).append(SQL::raw("JSONB")))
}
fn typed_param<'a>(
value: PostgresValue<'a>,
type_name: &'static str,
) -> SQL<'a, PostgresValue<'a>> {
SQL::func(
"CAST",
SQL::param(value)
.push(Token::AS)
.append(SQL::raw(type_name)),
)
}
use drizzle_types::postgres::types::{Any, Boolean, Json, Jsonb, Text, Varchar};
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a PostgreSQL JSON type",
label = "JSON operators need a `json` or `jsonb` operand"
)]
pub trait JsonType {
type Field: drizzle_types::DataType;
}
impl JsonType for Json {
type Field = Json;
}
impl JsonType for Jsonb {
type Field = Jsonb;
}
impl JsonType for Any {
type Field = Json;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not `jsonb`",
label = "this operator exists only for `jsonb`",
note = "PostgreSQL has no `@>`, `<@`, `?`, `?|` or `?&` for `json`; declare the column as `jsonb`"
)]
pub trait JsonbType {}
impl JsonbType for Jsonb {}
impl JsonbType for Any {}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be cast to `jsonb` for a containment check",
label = "expected a JSON value, JSON text, or untyped SQL"
)]
pub trait JsonbOperand {}
impl JsonbOperand for Json {}
impl JsonbOperand for Jsonb {}
impl JsonbOperand for Text {}
impl JsonbOperand for Varchar {}
impl JsonbOperand for Any {}
pub fn json_get<'a, E>(
expr: E,
key: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, <E::SQLType as JsonType>::Field, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("->".into()))
.append(typed_param(PostgresValue::Text(key.into()), "TEXT")),
)
}
pub fn json_get_idx<'a, E>(
expr: E,
index: i32,
) -> SQLExpr<'a, PostgresValue<'a>, <E::SQLType as JsonType>::Field, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("->".into()))
.append(typed_param(PostgresValue::Integer(index), "INTEGER")),
)
}
pub fn json_get_text<'a, E>(
expr: E,
key: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("->>".into()))
.append(typed_param(PostgresValue::Text(key.into()), "TEXT")),
)
}
pub fn json_get_text_idx<'a, E>(
expr: E,
index: i32,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("->>".into()))
.append(typed_param(PostgresValue::Integer(index), "INTEGER")),
)
}
pub fn json_get_path<'a, E>(
expr: E,
path: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, <E::SQLType as JsonType>::Field, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("#>".into()))
.append(typed_param(PostgresValue::Text(path.into()), "TEXT[]")),
)
}
pub fn json_get_path_text<'a, E>(
expr: E,
path: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, E::Aggregate, E::Sources>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("#>>".into()))
.append(typed_param(PostgresValue::Text(path.into()), "TEXT[]")),
)
}
#[allow(clippy::type_complexity)]
pub fn jsonb_contains<'a, L, R>(
left: L,
right: R,
) -> SQLExpr<
'a,
PostgresValue<'a>,
Boolean,
NonNull,
<L::Aggregate as AggregateKind>::Or<R::Aggregate>,
(Arg<L::Nullable, L::Sources>, Arg<R::Nullable, R::Sources>),
>
where
L: Expr<'a, PostgresValue<'a>>,
L::SQLType: JsonbType,
R: Expr<'a, PostgresValue<'a>>,
R::SQLType: JsonbOperand,
{
SQLExpr::new(
left.to_sql()
.push(SQLChunk::Raw("@>".into()))
.append(jsonb_operand(right.to_sql())),
)
}
#[allow(clippy::type_complexity)]
pub fn jsonb_contained<'a, L, R>(
left: L,
right: R,
) -> SQLExpr<
'a,
PostgresValue<'a>,
Boolean,
NonNull,
<L::Aggregate as AggregateKind>::Or<R::Aggregate>,
(Arg<L::Nullable, L::Sources>, Arg<R::Nullable, R::Sources>),
>
where
L: Expr<'a, PostgresValue<'a>>,
L::SQLType: JsonbType,
R: Expr<'a, PostgresValue<'a>>,
R::SQLType: JsonbOperand,
{
SQLExpr::new(
left.to_sql()
.push(SQLChunk::Raw("<@".into()))
.append(jsonb_operand(right.to_sql())),
)
}
#[allow(clippy::type_complexity)]
pub fn jsonb_exists_key<'a, E>(
expr: E,
key: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, Boolean, NonNull, E::Aggregate, Arg<E::Nullable, E::Sources>>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonbType,
{
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("?".into()))
.append(typed_param(PostgresValue::Text(key.into()), "TEXT")),
)
}
#[allow(clippy::type_complexity)]
pub fn jsonb_exists_any<'a, E>(
expr: E,
keys: &[&'a str],
) -> SQLExpr<'a, PostgresValue<'a>, Boolean, NonNull, E::Aggregate, Arg<E::Nullable, E::Sources>>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonbType,
{
let arr: Vec<PostgresValue<'a>> = keys
.iter()
.map(|k| PostgresValue::Text((*k).into()))
.collect();
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("?|".into()))
.append(SQL::param(PostgresValue::Array(arr))),
)
}
#[allow(clippy::type_complexity)]
pub fn jsonb_exists_all<'a, E>(
expr: E,
keys: &[&'a str],
) -> SQLExpr<'a, PostgresValue<'a>, Boolean, NonNull, E::Aggregate, Arg<E::Nullable, E::Sources>>
where
E: Expr<'a, PostgresValue<'a>>,
E::SQLType: JsonbType,
{
let arr: Vec<PostgresValue<'a>> = keys
.iter()
.map(|k| PostgresValue::Text((*k).into()))
.collect();
SQLExpr::new(
expr.to_sql()
.push(SQLChunk::Raw("?&".into()))
.append(SQL::param(PostgresValue::Array(arr))),
)
}
pub trait JsonExprExt<'a>: Expr<'a, PostgresValue<'a>> + Sized {
fn json_get(
self,
key: &'a str,
) -> SQLExpr<
'a,
PostgresValue<'a>,
<Self::SQLType as JsonType>::Field,
Null,
Self::Aggregate,
Self::Sources,
>
where
Self::SQLType: JsonType,
{
json_get(self, key)
}
fn json_get_idx(
self,
index: i32,
) -> SQLExpr<
'a,
PostgresValue<'a>,
<Self::SQLType as JsonType>::Field,
Null,
Self::Aggregate,
Self::Sources,
>
where
Self::SQLType: JsonType,
{
json_get_idx(self, index)
}
fn json_get_text(
self,
key: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, Self::Aggregate, Self::Sources>
where
Self::SQLType: JsonType,
{
json_get_text(self, key)
}
fn json_get_text_idx(
self,
index: i32,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, Self::Aggregate, Self::Sources>
where
Self::SQLType: JsonType,
{
json_get_text_idx(self, index)
}
fn json_get_path(
self,
path: &'a str,
) -> SQLExpr<
'a,
PostgresValue<'a>,
<Self::SQLType as JsonType>::Field,
Null,
Self::Aggregate,
Self::Sources,
>
where
Self::SQLType: JsonType,
{
json_get_path(self, path)
}
fn json_get_path_text(
self,
path: &'a str,
) -> SQLExpr<'a, PostgresValue<'a>, Text, Null, Self::Aggregate, Self::Sources>
where
Self::SQLType: JsonType,
{
json_get_path_text(self, path)
}
#[allow(clippy::type_complexity)]
fn jsonb_contains<R>(
self,
other: R,
) -> SQLExpr<
'a,
PostgresValue<'a>,
Boolean,
NonNull,
<Self::Aggregate as AggregateKind>::Or<R::Aggregate>,
(
Arg<Self::Nullable, Self::Sources>,
Arg<R::Nullable, R::Sources>,
),
>
where
Self::SQLType: JsonbType,
R: Expr<'a, PostgresValue<'a>>,
R::SQLType: JsonbOperand,
{
jsonb_contains(self, other)
}
#[allow(clippy::type_complexity)]
fn jsonb_contained<R>(
self,
other: R,
) -> SQLExpr<
'a,
PostgresValue<'a>,
Boolean,
NonNull,
<Self::Aggregate as AggregateKind>::Or<R::Aggregate>,
(
Arg<Self::Nullable, Self::Sources>,
Arg<R::Nullable, R::Sources>,
),
>
where
Self::SQLType: JsonbType,
R: Expr<'a, PostgresValue<'a>>,
R::SQLType: JsonbOperand,
{
jsonb_contained(self, other)
}
#[allow(clippy::type_complexity)]
fn jsonb_exists_key(
self,
key: &'a str,
) -> SQLExpr<
'a,
PostgresValue<'a>,
Boolean,
NonNull,
Self::Aggregate,
Arg<Self::Nullable, Self::Sources>,
>
where
Self::SQLType: JsonbType,
{
jsonb_exists_key(self, key)
}
}
impl<'a, E: Expr<'a, PostgresValue<'a>>> JsonExprExt<'a> for E {}