Skip to content

Commit

Permalink
Added into_iter for anyarray (#1851)
Browse files Browse the repository at this point in the history
Fixes #1832.

The implementation isn't what I want, but it adds `into_iter` for
`&AnyArray` and I hope unblocking thomcc. Later it would be better to
get rid of `AnyArray` in its current state and use `Array<AnyElement>`
instead, I will investigate that possibility. But for now that is how it
is and without any breaking change.
  • Loading branch information
YohDeadfall authored Sep 11, 2024
1 parent d13cd30 commit 86c6a0f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
19 changes: 19 additions & 0 deletions pgrx-tests/src/tests/anyarray_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ fn anyarray_arg(array: AnyArray) -> Json {
.expect("conversion to json returned null")
}

#[pg_extern]
fn anyarray_iter_arg(array: AnyArray) -> Json {
let mut vec = Vec::<_>::new();
for el in &array {
vec.push(el.expect("element is null").datum().value() as i64)
}
unsafe { direct_function_call::<Json>(pg_sys::array_to_json, &[vec.into_datum()]) }
.expect("conversion to json returned null")
}

#[cfg(any(test, feature = "pg_test"))]
#[pgrx::pg_schema]
mod tests {
Expand All @@ -33,4 +43,13 @@ mod tests {
assert_eq!(json.0, json! {[1,2,3]});
Ok(())
}

#[pg_test]
fn test_anyarray_iter_arg() -> std::result::Result<(), pgrx::spi::Error> {
let json =
Spi::get_one::<Json>("SELECT anyarray_iter_arg(ARRAY[1::integer,2,3]::integer[]);")?
.expect("datum was null");
assert_eq!(json.0, json! {[1,2,3]});
Ok(())
}
}
54 changes: 53 additions & 1 deletion pgrx/src/datum/anyarray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
//LICENSE All rights reserved.
//LICENSE
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
use crate::{pg_sys, FromDatum, IntoDatum};
use super::ArrayIntoIterator;
use crate::{pg_sys, AnyElement, Array, FromDatum, IntoDatum};
use pgrx_sql_entity_graph::metadata::{
ArgumentError, Returns, ReturnsError, SqlMapping, SqlTranslatable,
};
use std::iter::FusedIterator;

/// The [`anyarray` polymorphic pseudo-type][anyarray].
///
Expand Down Expand Up @@ -84,3 +86,53 @@ unsafe impl SqlTranslatable for AnyArray {
Ok(Returns::One(SqlMapping::literal("anyarray")))
}
}

impl<'a> IntoIterator for &'a AnyArray
where
Self: 'a,
{
type Item = Option<AnyElement>;
type IntoIter = AnyArrayIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
unsafe {
AnyArrayIterator {
inner: Array::<pg_sys::Datum>::from_polymorphic_datum(
self.datum(),
false,
self.oid(),
)
.map(|a| a.into_iter()),
typelem: pg_sys::get_element_type(self.oid()),
}
}
}
}

pub struct AnyArrayIterator<'a> {
inner: Option<ArrayIntoIterator<'a, pg_sys::Datum>>,
typelem: pg_sys::Oid,
}

impl<'a> Iterator for AnyArrayIterator<'a> {
type Item = Option<AnyElement>;

fn next(&mut self) -> Option<Self::Item> {
self.inner.as_mut().and_then(|i| {
i.next().map(|d| match d {
Some(d) => unsafe { AnyElement::from_polymorphic_datum(d, false, self.typelem) },
None => None,
})
})
}

fn size_hint(&self) -> (usize, Option<usize>) {
match &self.inner {
Some(inner) => inner.size_hint(),
None => (0, Some(0)),
}
}
}

impl<'a> ExactSizeIterator for AnyArrayIterator<'a> {}
impl<'a> FusedIterator for AnyArrayIterator<'a> {}

0 comments on commit 86c6a0f

Please sign in to comment.