Skip to main content

drizzle_postgres/expr/
mod.rs

1//! `PostgreSQL`-only operators: arrays, JSON and JSONB, `ILIKE`, and POSIX
2//! regular expressions.
3//!
4//! Each operator is a free function and, through an extension trait
5//! ([`ArrayExprExt`], [`JsonExprExt`], [`RegexExprExt`]), a method on any
6//! `PostgreSQL` expression. Operand types are checked at compile time, as
7//! described below. Portable operators (`eq`, `like`, `and`, ...) live in
8//! `drizzle_core::expr`.
9//!
10//! The examples use `raw_non_null::<PostgresValue, T>("col")` to stand for a
11//! non-null column of SQL type `T`; in real code, use a table column.
12//!
13//! # Arrays
14//!
15//! | Operator | Function / method | True when |
16//! |---|---|---|
17//! | `@>` | [`array_contains`] / [`ArrayExprExt::array_contains`] | the left array holds every element of the right |
18//! | `<@` | [`array_contained`] / [`ArrayExprExt::array_contained`] | every element of the left array is in the right |
19//! | `&&` | [`array_overlaps`] / [`ArrayExprExt::array_overlaps`] | the arrays share at least one element |
20//!
21//! ## Operand types
22//!
23//! Both operands must be arrays, checked through [`ArrayOperand`]:
24//!
25//! - An `Array<T>` column (for example a `text[]` column) accepts an
26//!   `Array<U>` operand when `T` is [`Compatible`](drizzle_types::Compatible) with `U`.
27//! - Bind a Rust list with [`PgArray`]: `PgArray(vec!["a", "b"])` is an
28//!   `Array<Text>`. A bare `Vec` or a single value is not an array operand.
29//! - A placeholder or untyped SQL (`SQL::raw`) is accepted on either side.
30//!
31//! ## Examples
32//!
33//! ```
34//! use drizzle_core::{ToSQL, expr::raw_non_null};
35//! use drizzle_postgres::expr::{ArrayExprExt, PgArray};
36//! use drizzle_postgres::values::PostgresValue;
37//! use drizzle_types::{Array, postgres::types::Text};
38//!
39//! // Stands in for a `tags text[] NOT NULL` column.
40//! let tags = raw_non_null::<PostgresValue, Array<Text>>("tags");
41//! let condition = tags.array_contains(PgArray(vec!["rust", "sql"]));
42//! assert_eq!(condition.to_sql().sql(), "tags @> $1");
43//! ```
44//!
45//! # JSON and JSONB
46//!
47//! Access operators work on `json` and `jsonb` (operand bound: [`JsonType`]):
48//!
49//! | Operator | Function | Returns |
50//! |---|---|---|
51//! | `->` key | [`json_get`] | the field, as the input type (`json` or `jsonb`) |
52//! | `->` index | [`json_get_idx`] | the array element, as the input type |
53//! | `->>` key | [`json_get_text`] | the field as `text` |
54//! | `->>` index | [`json_get_text_idx`] | the array element as `text` |
55//! | `#>` path | [`json_get_path`] | the value at the path, as the input type |
56//! | `#>>` path | [`json_get_path_text`] | the value at the path as `text` |
57//!
58//! Access results are nullable: a missing key, index or path yields NULL.
59//!
60//! Containment and key operators exist only for `jsonb` (operand bound: [`JsonbType`]):
61//!
62//! | Operator | Function | True when |
63//! |---|---|---|
64//! | `@>` | [`jsonb_contains`] | the left value contains the right value |
65//! | `<@` | [`jsonb_contained`] | the left value is contained in the right value |
66//! | `?` | [`jsonb_exists_key`] | the key is a top-level key |
67//! | `?\|` | [`jsonb_exists_any`] | any of the keys is a top-level key |
68//! | `?&` | [`jsonb_exists_all`] | all of the keys are top-level keys |
69//!
70//! [`JsonExprExt`] offers most of these as methods.
71//! Untyped SQL (`SQL::raw`) is accepted wherever a JSON operand is expected.
72//!
73//! ## Examples
74//!
75//! ```
76//! use drizzle_core::{ToSQL, expr::raw_non_null};
77//! use drizzle_postgres::expr::JsonExprExt;
78//! use drizzle_postgres::values::PostgresValue;
79//! use drizzle_types::postgres::types::Jsonb;
80//!
81//! // Stands in for a `profile jsonb NOT NULL` column.
82//! let profile = raw_non_null::<PostgresValue, Jsonb>("profile");
83//! let city = profile.json_get("address").json_get_text("city");
84//! assert_eq!(
85//!     city.to_sql().sql(),
86//!     "profile -> CAST ($1 AS TEXT) ->> CAST ($2 AS TEXT)"
87//! );
88//! ```
89//!
90//! # Pattern matching
91//!
92//! [`ilike`] and [`not_ilike`] match a `LIKE` pattern ignoring case. Both
93//! sides must be textual ([`Textual`](drizzle_types::Textual)): the left a
94//! `text`, `varchar`, `char` or enum expression, the pattern a compatible
95//! textual value such as a `&str` or a placeholder.
96//!
97//! The regex functions, also available as [`RegexExprExt`] methods:
98//!
99//! | Operator | Function / method | True when the text |
100//! |---|---|---|
101//! | `~` | [`regex_match`] | matches the pattern (case-sensitive) |
102//! | `~*` | [`regex_match_ci`] | matches the pattern (case-insensitive) |
103//! | `!~` | [`regex_not_match`] | does not match the pattern (case-sensitive) |
104//! | `!~*` | [`regex_not_match_ci`] | does not match the pattern (case-insensitive) |
105//!
106//! The left operand must be textual, as for `ILIKE`. The pattern is a `&str` bound as
107//! a `text` parameter. The pattern matches anywhere in the string unless it is
108//! anchored with `^` or `$`. Results are NULL when the left operand is NULL.
109//!
110//! ## Examples
111//!
112//! ```
113//! use drizzle_core::{ToSQL, expr::raw_non_null};
114//! use drizzle_postgres::expr::RegexExprExt;
115//! use drizzle_postgres::values::PostgresValue;
116//! use drizzle_types::postgres::types::Text;
117//!
118//! let sku = raw_non_null::<PostgresValue, Text>("sku");
119//! let cond = sku.regex_match("^[A-Z]{3}-[0-9]+$");
120//! assert_eq!(cond.to_sql().sql(), "sku ~ $1");
121//! ```
122//!
123//! ## Type safety
124//!
125//! ```compile_fail
126//! use drizzle_core::expr::raw_non_null;
127//! use drizzle_postgres::expr::regex_match;
128//! use drizzle_postgres::values::PostgresValue;
129//! use drizzle_types::postgres::types::Int8;
130//!
131//! let id = raw_non_null::<PostgresValue, Int8>("id");
132//! let _ = regex_match(id, "^1"); // `int8` is not textual
133//! ```
134
135mod array_ops;
136mod ilike;
137mod json_ops;
138mod regex;
139
140pub use array_ops::*;
141pub use ilike::*;
142pub use json_ops::*;
143pub use regex::*;