Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b7a297e

Browse files
committed
refactor(test): dedup ORE/OPE fixtures and ordering test helpers
Collapse the two near-identical ORE/OPE fixture-table DO blocks in schema.sql into one kind-parameterized loop, fold the OPE ordering tests into a shared run_order_test helper, and delegate the ORE text-ordering helpers to ore_order_generic. Also add guidance on choosing ope vs ore to the encrypted-index docs. Addresses PR review feedback.
1 parent 951fba2 commit b7a297e

4 files changed

Lines changed: 152 additions & 221 deletions

File tree

docs/how-to/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ SELECT eql_v2.add_search_config(
228228

229229
The first SQL statement adds a `match` index, which is used for partial matches with `LIKE`.
230230
The second SQL statement adds an `ore` index, which is used for ordering with `ORDER BY` and range comparisons (`<`, `<=`, `>`, `>=`).
231-
The third SQL statement adds an `ope` index, which supports the same range and ordering operators as `ore` and is a drop-in alternative — pick `ope` or `ore` per column, not both.
231+
The third SQL statement adds an `ope` index, which supports the same range and ordering operators as `ore`.
232+
233+
`ore` and `ope` are alternatives for range and ordering queries — add one or the other to a column, not both. `ore` is the recommended default. `ope` produces ciphertexts that sort under PostgreSQL's native byte ordering, which makes ordering and range scans cheaper, but as an order-preserving scheme it reveals more about the relative order of stored values than `ore` does. Choose based on your performance and threat-model requirements; see the [EQL `INDEX` documentation](https://github.com/cipherstash/encrypt-query-language/blob/main/docs/reference/INDEX.md) for the full tradeoffs.
232234

233235

234236
> ![IMPORTANT]

packages/cipherstash-proxy-integration/src/map_ope_index_order.rs

Lines changed: 55 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,105 +3,89 @@ mod tests {
33
use crate::common::{
44
clear_table, connect_with_tls, interleaved_indices, random_id, trace, PROXY,
55
};
6+
use std::fmt::Debug;
7+
use tokio_postgres::types::{FromSql, ToSql};
68

79
#[tokio::test]
810
async fn map_ope_order_text_asc() {
9-
trace();
10-
let table = "encrypted_ope_order_text_asc";
11-
clear_table(table).await;
12-
let client = connect_with_tls(PROXY).await;
13-
14-
let values = ["aardvark", "aplomb", "chimera", "chrysalis", "zephyr"];
15-
16-
let insert = format!("INSERT INTO {table} (id, encrypted_text) VALUES ($1, $2)");
17-
for idx in interleaved_indices(values.len()) {
18-
client
19-
.query(&insert, &[&random_id(), &values[idx]])
20-
.await
21-
.unwrap();
22-
}
23-
24-
let select = format!("SELECT encrypted_text FROM {table} ORDER BY encrypted_text");
25-
let rows = client.query(&select, &[]).await.unwrap();
26-
27-
let actual: Vec<String> = rows.iter().map(|r| r.get(0)).collect();
28-
let expected: Vec<String> = values.iter().map(|s| s.to_string()).collect();
29-
30-
assert_eq!(actual, expected);
11+
run_order_test(
12+
"encrypted_ope_order_text_asc",
13+
"encrypted_text",
14+
text_values(),
15+
false,
16+
)
17+
.await;
3118
}
3219

3320
#[tokio::test]
3421
async fn map_ope_order_text_desc() {
35-
trace();
36-
let table = "encrypted_ope_order_text_desc";
37-
clear_table(table).await;
38-
let client = connect_with_tls(PROXY).await;
39-
40-
let values = ["aardvark", "aplomb", "chimera", "chrysalis", "zephyr"];
41-
42-
let insert = format!("INSERT INTO {table} (id, encrypted_text) VALUES ($1, $2)");
43-
for idx in interleaved_indices(values.len()) {
44-
client
45-
.query(&insert, &[&random_id(), &values[idx]])
46-
.await
47-
.unwrap();
48-
}
49-
50-
let select = format!("SELECT encrypted_text FROM {table} ORDER BY encrypted_text DESC");
51-
let rows = client.query(&select, &[]).await.unwrap();
52-
53-
let actual: Vec<String> = rows.iter().map(|r| r.get(0)).collect();
54-
let expected: Vec<String> = values.iter().rev().map(|s| s.to_string()).collect();
55-
56-
assert_eq!(actual, expected);
22+
run_order_test(
23+
"encrypted_ope_order_text_desc",
24+
"encrypted_text",
25+
text_values(),
26+
true,
27+
)
28+
.await;
5729
}
5830

5931
#[tokio::test]
6032
async fn map_ope_order_int4_asc() {
61-
trace();
62-
let table = "encrypted_ope_order_int4_asc";
63-
clear_table(table).await;
64-
let client = connect_with_tls(PROXY).await;
65-
66-
let values: Vec<i32> = vec![-100, -1, 0, 1, 42, 1000, i32::MAX];
67-
68-
let insert = format!("INSERT INTO {table} (id, encrypted_int4) VALUES ($1, $2)");
69-
for idx in interleaved_indices(values.len()) {
70-
client
71-
.query(&insert, &[&random_id(), &values[idx]])
72-
.await
73-
.unwrap();
74-
}
75-
76-
let select = format!("SELECT encrypted_int4 FROM {table} ORDER BY encrypted_int4");
77-
let rows = client.query(&select, &[]).await.unwrap();
78-
79-
let actual: Vec<i32> = rows.iter().map(|r| r.get(0)).collect();
80-
assert_eq!(actual, values);
33+
run_order_test(
34+
"encrypted_ope_order_int4_asc",
35+
"encrypted_int4",
36+
vec![-100i32, -1, 0, 1, 42, 1000, i32::MAX],
37+
false,
38+
)
39+
.await;
8140
}
8241

8342
#[tokio::test]
8443
async fn map_ope_order_int4_desc() {
44+
run_order_test(
45+
"encrypted_ope_order_int4_desc",
46+
"encrypted_int4",
47+
vec![-100i32, -1, 0, 1, 42, 1000, i32::MAX],
48+
true,
49+
)
50+
.await;
51+
}
52+
53+
fn text_values() -> Vec<String> {
54+
["aardvark", "aplomb", "chimera", "chrysalis", "zephyr"]
55+
.iter()
56+
.map(|s| s.to_string())
57+
.collect()
58+
}
59+
60+
/// Inserts `values` (given in ascending order) in interleaved order, then
61+
/// verifies `ORDER BY {col_name}` returns them sorted in the requested
62+
/// direction.
63+
async fn run_order_test<T>(table: &str, col_name: &str, values: Vec<T>, descending: bool)
64+
where
65+
for<'a> T: PartialEq + ToSql + Sync + FromSql<'a> + Debug,
66+
{
8567
trace();
86-
let table = "encrypted_ope_order_int4_desc";
8768
clear_table(table).await;
8869
let client = connect_with_tls(PROXY).await;
8970

90-
let values: Vec<i32> = vec![-100, -1, 0, 1, 42, 1000, i32::MAX];
91-
92-
let insert = format!("INSERT INTO {table} (id, encrypted_int4) VALUES ($1, $2)");
71+
let insert = format!("INSERT INTO {table} (id, {col_name}) VALUES ($1, $2)");
9372
for idx in interleaved_indices(values.len()) {
9473
client
9574
.query(&insert, &[&random_id(), &values[idx]])
9675
.await
9776
.unwrap();
9877
}
9978

100-
let select = format!("SELECT encrypted_int4 FROM {table} ORDER BY encrypted_int4 DESC");
79+
let dir = if descending { "DESC" } else { "ASC" };
80+
let select = format!("SELECT {col_name} FROM {table} ORDER BY {col_name} {dir}");
10181
let rows = client.query(&select, &[]).await.unwrap();
10282

103-
let actual: Vec<i32> = rows.iter().map(|r| r.get(0)).collect();
104-
let expected: Vec<i32> = values.into_iter().rev().collect();
83+
let actual: Vec<T> = rows.iter().map(|r| r.get(0)).collect();
84+
let expected: Vec<T> = if descending {
85+
values.into_iter().rev().collect()
86+
} else {
87+
values
88+
};
10589
assert_eq!(actual, expected);
10690
}
10791

packages/cipherstash-proxy-integration/src/ore_order_helpers.rs

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,64 +30,45 @@ impl SortDirection {
3030
}
3131
}
3232

33-
/// Text ASC ordering with lexicographic edge cases.
34-
pub async fn ore_order_text(client: &tokio_postgres::Client, table: &str) {
35-
let values = [
33+
/// Text values with lexicographic edge cases (shared common prefixes), in
34+
/// ascending order.
35+
fn ore_order_text_values() -> Vec<String> {
36+
[
3637
"aardvark",
3738
"aplomb",
3839
"apparatus",
3940
"chimera",
4041
"chrysalis",
4142
"chrysanthemum",
4243
"zephyr",
43-
];
44-
45-
let insert_sql = format!("INSERT INTO {table} (id, encrypted_text) VALUES ($1, $2)");
46-
47-
for idx in interleaved_indices(values.len()) {
48-
client
49-
.query(&insert_sql, &[&random_id(), &values[idx]])
50-
.await
51-
.unwrap();
52-
}
53-
54-
let sql = format!("SELECT encrypted_text FROM {table} ORDER BY encrypted_text");
55-
let rows = client.query(&sql, &[]).await.unwrap();
56-
57-
let actual = rows.iter().map(|row| row.get(0)).collect::<Vec<String>>();
58-
let expected: Vec<String> = values.iter().map(|s| s.to_string()).collect();
44+
]
45+
.iter()
46+
.map(|s| s.to_string())
47+
.collect()
48+
}
5949

60-
assert_eq!(actual, expected);
50+
/// Text ASC ordering with lexicographic edge cases.
51+
pub async fn ore_order_text(client: &tokio_postgres::Client, table: &str) {
52+
ore_order_generic(
53+
client,
54+
table,
55+
"encrypted_text",
56+
ore_order_text_values(),
57+
SortDirection::Asc,
58+
)
59+
.await;
6160
}
6261

6362
/// Text DESC ordering with lexicographic edge cases.
6463
pub async fn ore_order_text_desc(client: &tokio_postgres::Client, table: &str) {
65-
let values = [
66-
"aardvark",
67-
"aplomb",
68-
"apparatus",
69-
"chimera",
70-
"chrysalis",
71-
"chrysanthemum",
72-
"zephyr",
73-
];
74-
75-
let insert_sql = format!("INSERT INTO {table} (id, encrypted_text) VALUES ($1, $2)");
76-
77-
for idx in interleaved_indices(values.len()) {
78-
client
79-
.query(&insert_sql, &[&random_id(), &values[idx]])
80-
.await
81-
.unwrap();
82-
}
83-
84-
let sql = format!("SELECT encrypted_text FROM {table} ORDER BY encrypted_text DESC");
85-
let rows = client.query(&sql, &[]).await.unwrap();
86-
87-
let actual = rows.iter().map(|row| row.get(0)).collect::<Vec<String>>();
88-
let expected: Vec<String> = values.iter().rev().map(|s| s.to_string()).collect();
89-
90-
assert_eq!(actual, expected);
64+
ore_order_generic(
65+
client,
66+
table,
67+
"encrypted_text",
68+
ore_order_text_values(),
69+
SortDirection::Desc,
70+
)
71+
.await;
9172
}
9273

9374
/// NULLs sort last in ASC by default.

0 commit comments

Comments
 (0)