1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.
use std::convert::{TryFrom, TryInto};
use anyhow::bail;
/// Validates a PG typmod from user input and returns a vector of the supplied
/// values whose positions align with those of `val_ranges`.
///
/// # Arguments
/// - `T`: The desired type of the `typ_mod`.
/// - `name`: The name to of the type to return in error messages
/// - `typ_mod`: The user-supplied typmod
/// - `val_ranges`: Valid `typ_mod` values. Tuples are of of the form
/// `(<attribute name>, <lower bound, inclusive>, <upper bound, inclusive>)`.
pub fn extract_typ_mod<T>(
name: &str,
typ_mod: &[u64],
val_ranges: &[(&str, T, T)],
) -> Result<Vec<T>, anyhow::Error>
where
T: TryFrom<u64> + std::fmt::Display + Ord + PartialOrd,
{
if typ_mod.len() > val_ranges.len() {
bail!("invalid {} type modifier", name)
}
let err = |attr: &str, lower: &T, upper: &T, value: &u64| -> Result<(), anyhow::Error> {
bail!(
"{} for type {} must be within [{}-{}], have {}",
attr,
name,
lower,
upper,
value,
)
};
let mut r: Vec<T> = vec![];
for (v, (attr, lower, upper)) in typ_mod.iter().zip(val_ranges.iter()) {
match (*v).try_into() {
Ok(c) => {
if &c < lower || &c > upper {
err(attr, lower, upper, v)?
}
r.push(c)
}
Err(_) => err(attr, lower, upper, v)?,
};
}
Ok(r)
}