Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6f5d752
chore: enhance test case coverage
burmecia Mar 3, 2026
40d0430
Update wrappers/src/fdw/airtable_fdw/tests.rs
burmecia Mar 3, 2026
7fdb0d2
chore: update data type references in airtable_fdw tests
burmecia Mar 3, 2026
e5ad0c0
chore: enhance mock server metadata and update test cases
burmecia Mar 4, 2026
e2eee16
chore: add additional test cases for fields and partitioning transfor…
burmecia Mar 4, 2026
f2967b2
chore: update test commands to use pgrx for supabase-wrappers and enh…
burmecia Mar 4, 2026
b005757
chore: update test commands to use cargo test with specific features …
burmecia Mar 4, 2026
6207251
chore: add rustflags for Linux target in Cargo configuration
burmecia Mar 4, 2026
7f36988
chore: add RUSTFLAGS to workflows for improved warning handling and u…
burmecia Mar 4, 2026
f0be841
chore: enhance test coverage by adding new test cases and updating lo…
burmecia Mar 4, 2026
0ca29cd
chore: enhance test coverage by adding new foreign table creation tes…
burmecia Mar 4, 2026
6a39f22
chore: enhance test coverage by adding tests for new table creation a…
burmecia Mar 4, 2026
1fb748c
chore: enhance test coverage by updating query assertions in ClickHou…
burmecia Mar 4, 2026
2230810
chore: enhance test coverage by expanding insert statement in bigquer…
burmecia Mar 4, 2026
153cd5e
chore: enhance test coverage by updating Stripe mock tests and preser…
burmecia Mar 4, 2026
89fbaaa
chore: enhance test coverage by updating endpoint logic and adding ne…
burmecia Mar 5, 2026
e413ed2
chore: enhance test coverage by adding support for additional ClickHo…
burmecia Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[target.'cfg(target_os="macos")']
# Postgres symbols won't be available until runtime
rustflags = ["-Clink-arg=-Wl,-undefined,dynamic_lookup"]

[target.'cfg(target_os="linux")']
# Postgres symbols won't be available until runtime
rustflags = ["-Clink-arg=-Wl,--unresolved-symbols=ignore-all"]
4 changes: 3 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ jobs:

- name: Generate code coverage
id: coverage
env:
RUSTFLAGS: "-D warnings -Clink-arg=-Wl,--unresolved-symbols=ignore-all"
run: |
source <(cargo llvm-cov show-env --export-prefix --no-cfg-coverage)
cargo llvm-cov clean --workspace
cargo test -p supabase-wrappers --lib
cargo test -p supabase-wrappers --no-default-features --features pg15 --lib
cargo pgrx test --features "native_fdws" --manifest-path wrappers/Cargo.toml pg15
cargo llvm-cov report --lcov --output-path lcov.info

Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/test_supabase_wrappers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ jobs:
run: |
cd supabase-wrappers && RUSTFLAGS="-D warnings" cargo clippy --all --tests --no-deps

- run: cd supabase-wrappers && cargo test
- name: Run tests
env:
RUSTFLAGS: "-D warnings -Clink-arg=-Wl,--unresolved-symbols=ignore-all"
run: cargo test -p supabase-wrappers --no-default-features --features pg15 --lib
217 changes: 217 additions & 0 deletions supabase-wrappers/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,3 +948,220 @@ pub trait ForeignDataWrapper<E: Into<ErrorReport>> {
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

fn assert_cell_clone(cell: Cell) {
let cell_clone = cell.clone();

match (cell, cell_clone) {
(Cell::Bool(left), Cell::Bool(right)) => assert_eq!(left, right),
(Cell::I8(left), Cell::I8(right)) => assert_eq!(left, right),
(Cell::I16(left), Cell::I16(right)) => assert_eq!(left, right),
(Cell::F32(left), Cell::F32(right)) => assert_eq!(left, right),
(Cell::I32(left), Cell::I32(right)) => assert_eq!(left, right),
(Cell::F64(left), Cell::F64(right)) => assert_eq!(left, right),
(Cell::I64(left), Cell::I64(right)) => assert_eq!(left, right),
(Cell::String(left), Cell::String(right)) => assert_eq!(left, right),
(Cell::BoolArray(left), Cell::BoolArray(right)) => assert_eq!(left, right),
(Cell::I16Array(left), Cell::I16Array(right)) => assert_eq!(left, right),
(Cell::I32Array(left), Cell::I32Array(right)) => assert_eq!(left, right),
(Cell::I64Array(left), Cell::I64Array(right)) => assert_eq!(left, right),
(Cell::F32Array(left), Cell::F32Array(right)) => assert_eq!(left, right),
(Cell::F64Array(left), Cell::F64Array(right)) => assert_eq!(left, right),
(Cell::StringArray(left), Cell::StringArray(right)) => assert_eq!(left, right),
(left, right) => panic!("cell clone variant mismatch: left={left:?}, right={right:?}",),
}
}

// ==========================================================================
// Tests for Cell
// ==========================================================================
#[test]
fn test_cell_clone() {
let cell = Cell::String("hello".to_string());
assert_cell_clone(cell);
}

#[test]
fn test_cell_clone_primitives() {
let cases = vec![
Cell::Bool(true),
Cell::I8(-8),
Cell::I16(-16),
Cell::F32(123.456f32),
Cell::I32(32),
Cell::F64(654.321f64),
Cell::I64(64),
Cell::String("supabase".to_string()),
];

for cell in cases {
assert_cell_clone(cell);
}
}

#[test]
fn test_cell_clone_array_variants() {
let cases = vec![
Cell::BoolArray(vec![Some(true), None, Some(false)]),
Cell::I16Array(vec![Some(-1), None, Some(2)]),
Cell::I32Array(vec![Some(-10), None, Some(20)]),
Cell::I64Array(vec![Some(-100), None, Some(200)]),
Cell::F32Array(vec![Some(1.5), None, Some(2.5)]),
Cell::F64Array(vec![Some(10.5), None, Some(20.5)]),
Cell::StringArray(vec![Some("a".to_string()), None, Some("b".to_string())]),
];

for cell in cases {
let cell_clone = cell.clone();
assert_cell_clone(cell);
assert!(cell_clone.is_array());
}
}

#[test]
fn test_cell_clone_deep_copy_for_owned_types() {
let mut string_cell = Cell::String("hello".to_string());
let string_cell_clone = string_cell.clone();
if let Cell::String(value) = &mut string_cell {
value.push_str(" world");
}
match string_cell_clone {
Cell::String(value) => assert_eq!(value, "hello"),
other => panic!("expected Cell::String clone, got {other:?}"),
}
match string_cell {
Cell::String(value) => assert_eq!(value, "hello world"),
other => panic!("expected mutated Cell::String, got {other:?}"),
}

let mut string_array_cell =
Cell::StringArray(vec![Some("foo".to_string()), None, Some("bar".to_string())]);
let string_array_cell_clone = string_array_cell.clone();
if let Cell::StringArray(values) = &mut string_array_cell {
values[0] = Some("baz".to_string());
}
match string_array_cell_clone {
Cell::StringArray(values) => {
assert_eq!(
values,
vec![Some("foo".to_string()), None, Some("bar".to_string())]
)
}
other => panic!("expected Cell::StringArray clone, got {other:?}"),
}
match string_array_cell {
Cell::StringArray(values) => {
assert_eq!(
values,
vec![Some("baz".to_string()), None, Some("bar".to_string())]
)
}
other => panic!("expected mutated Cell::StringArray, got {other:?}"),
}
}

#[test]
fn test_cell_display_primitives_and_string() {
assert_eq!(format!("{}", Cell::Bool(true)), "true");
assert_eq!(format!("{}", Cell::I8(-8)), "-8");
assert_eq!(format!("{}", Cell::I16(16)), "16");
assert_eq!(format!("{}", Cell::I32(32)), "32");
assert_eq!(format!("{}", Cell::I64(64)), "64");
assert_eq!(format!("{}", Cell::F32(3.5)), "3.5");
assert_eq!(format!("{}", Cell::F64(7.25)), "7.25");
assert_eq!(format!("{}", Cell::String("hello".to_string())), "'hello'");
}

#[test]
fn test_cell_display_arrays_with_nulls() {
assert_eq!(
format!("{}", Cell::BoolArray(vec![Some(true), None, Some(false)])),
"[true,null,false]"
);
assert_eq!(
format!("{}", Cell::I32Array(vec![Some(1), None, Some(3)])),
"[1,null,3]"
);
assert_eq!(
format!(
"{}",
Cell::StringArray(vec![Some("foo".to_string()), None, Some("bar".to_string())])
),
"[foo,null,bar]"
);
}

#[test]
fn test_cell_display_empty_arrays() {
assert_eq!(format!("{}", Cell::BoolArray(vec![])), "[]");
assert_eq!(format!("{}", Cell::I16Array(vec![])), "[]");
assert_eq!(format!("{}", Cell::I32Array(vec![])), "[]");
assert_eq!(format!("{}", Cell::I64Array(vec![])), "[]");
assert_eq!(format!("{}", Cell::F32Array(vec![])), "[]");
assert_eq!(format!("{}", Cell::F64Array(vec![])), "[]");
assert_eq!(format!("{}", Cell::StringArray(vec![])), "[]");
}

#[cfg(all(feature = "pg_test", pgrx_embed))]
#[test]
fn test_cell_into_datum_scalars_round_trip() {
let bool_datum = Cell::Bool(true).into_datum().expect("bool should convert");
let bool_value =
unsafe { bool::from_datum(bool_datum, false) }.expect("bool should decode");
assert!(bool_value);

let i32_datum = Cell::I32(42).into_datum().expect("i32 should convert");
let i32_value = unsafe { i32::from_datum(i32_datum, false) }.expect("i32 should decode");
assert_eq!(i32_value, 42);

let f64_datum = Cell::F64(12.5).into_datum().expect("f64 should convert");
let f64_value = unsafe { f64::from_datum(f64_datum, false) }.expect("f64 should decode");
assert_eq!(f64_value, 12.5);

let string_datum = Cell::String("hello".to_string())
.into_datum()
.expect("string should convert");
let string_value =
unsafe { String::from_datum(string_datum, false) }.expect("string should decode");
assert_eq!(string_value, "hello");
}

#[cfg(all(feature = "pg_test", pgrx_embed))]
#[test]
fn test_cell_into_datum_arrays_round_trip() {
let bool_array_datum = Cell::BoolArray(vec![Some(true), None, Some(false)])
.into_datum()
.expect("bool array should convert");
let bool_array_value = unsafe { Vec::<Option<bool>>::from_datum(bool_array_datum, false) }
.expect("bool array should decode");
assert_eq!(bool_array_value, vec![Some(true), None, Some(false)]);

let i64_array_datum = Cell::I64Array(vec![Some(1), None, Some(3)])
.into_datum()
.expect("i64 array should convert");
let i64_array_value = unsafe { Vec::<Option<i64>>::from_datum(i64_array_datum, false) }
.expect("i64 array should decode");
assert_eq!(i64_array_value, vec![Some(1), None, Some(3)]);

let string_array_datum =
Cell::StringArray(vec![Some("foo".to_string()), None, Some("bar".to_string())])
.into_datum()
.expect("string array should convert");
let string_array_value =
unsafe { Vec::<Option<String>>::from_datum(string_array_datum, false) }
.expect("string array should decode");
assert_eq!(
string_array_value,
vec![Some("foo".to_string()), None, Some("bar".to_string())]
);
}

#[test]
fn test_cell_into_datum_type_oid_is_invalid() {
assert_eq!(Cell::type_oid(), Oid::INVALID);
}
}
42 changes: 42 additions & 0 deletions supabase-wrappers/src/qual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,3 +501,45 @@ pub(crate) unsafe fn extract_quals(
})
}
}

#[cfg(test)]
mod tests {
use super::*;
#[cfg(all(feature = "pg_test", pgrx_embed))]
use pgrx::IntoDatum;

#[cfg(all(feature = "pg_test", pgrx_embed))]
#[test]
fn test_form_array_from_datum_int4_array() {
let values = vec![1_i32, 2_i32, 3_i32];
let datum = values
.into_datum()
.expect("int4 array datum should be created");

let result = unsafe { form_array_from_datum(datum, false, pg_sys::INT4ARRAYOID) };
let result = result.expect("int4 array should be parsed");

assert_eq!(result.len(), 3);
assert!(matches!(result[0], Cell::I32(1)));
assert!(matches!(result[1], Cell::I32(2)));
assert!(matches!(result[2], Cell::I32(3)));
}

#[test]
fn test_form_array_from_datum_null_datum_returns_none() {
let result = unsafe { form_array_from_datum(0.into(), true, pg_sys::INT4ARRAYOID) };
assert!(result.is_none());
}

#[cfg(all(feature = "pg_test", pgrx_embed))]
#[test]
fn test_form_array_from_datum_unsupported_oid_returns_none() {
let values = vec![1_i32, 2_i32];
let datum = values
.into_datum()
.expect("int4 array datum should be created");

let result = unsafe { form_array_from_datum(datum, false, pg_sys::UUIDARRAYOID) };
assert!(result.is_none());
}
}
20 changes: 18 additions & 2 deletions wrappers/dockerfiles/airtable/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,15 @@ def do_GET(self):
"strings_array_field": ["foo", "bar"],
"numerics_array_field": [1, 2],
"bools_array_field": [False],
"objects_array_field": [{"foo": "bar"}, {"foo": "baz"}]
"objects_array_field": [{"foo": "bar"}, {"foo": "baz"}],
"char_field": 1,
"int2_field": 1,
"int4_field": 123,
"int8_field": 123456789012345678,
"float4_field": 1.23,
"float8_field": 1.23456789012345,
"date_field": "2023-07-19",
"timestamptz_field": "2023-07-19T06:39:15.000Z",
},
)
client.create(
Expand All @@ -63,7 +71,15 @@ def do_GET(self):
"strings_array_field": ["baz", "qux"],
"numerics_array_field": [3, 4],
"bools_array_field": [True, False, True],
"objects_array_field": [{"foo": "qux"}]
"objects_array_field": [{"foo": "qux"}],
"char_field": 2,
"int2_field": 2,
"int4_field": 456,
"int8_field": 123456789012345678,
"float4_field": 4.56,
"float8_field": 1.23456789012345,
"date_field": "2023-07-20",
"timestamptz_field": "2023-07-20T06:39:15.000Z",
},
)

Expand Down
26 changes: 24 additions & 2 deletions wrappers/dockerfiles/logflare/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@
"tenant_params": []
}
],
"timestamp": 1739866449830000
"timestamp": 1739866449830000,
"bool_field": false,
"char_field": 12,
"int2_field": 123,
"int4_field": 1234,
"int8_field": 12345678,
"float4_field": 12.34,
"float8_field": 1.23456789012345,
"numeric_field": 1234.5678,
"date_field": "2023-07-19",
"ts_field": "2023-07-19T06:39:15",
"tstz_field": "2023-07-19T06:39:15.000Z"
},
{
"event_message": "GET /",
Expand Down Expand Up @@ -110,7 +121,18 @@
"tenant_params": []
}
],
"timestamp": 1739866449826000
"timestamp": 1739866449826000,
"bool_field": false,
"char_field": 12,
"int2_field": 123,
"int4_field": 1234,
"int8_field": 12345678,
"float4_field": 12.34,
"float8_field": 1.23456789012345,
"numeric_field": 1234.5678,
"date_field": "2023-07-19",
"ts_field": "2023-07-19T06:39:15",
"tstz_field": "2023-07-19T06:39:15.000Z"
}
]
}
Loading
Loading