// Copyright (c) 2023-2025 ParadeDB, Inc.
//
// This file is part of ParadeDB - Postgres for Search and Analytics
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
mod fixtures;
use bigdecimal::BigDecimal;
use fixtures::*;
use rstest::*;
use sqlx::PgConnection;
#[rstest]
fn one_layer_size(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id', layer_sizes = '1kb');
"#.execute_result(&mut conn);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(
err.into_database_error().unwrap().to_string(),
"There must be at least 2 layers in `layer_sizes`"
);
}
#[rstest]
fn negative_layer_size(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id', layer_sizes = '-1kb');
"#.execute_result(&mut conn);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(
err.into_database_error().unwrap().to_string(),
"a single layer size must be greater than zero"
);
}
#[rstest]
fn zero_layer_size(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id', layer_sizes = '0kb, 1kb');
"#.execute_result(&mut conn);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(
err.into_database_error().unwrap().to_string(),
"a single layer size must be greater than zero"
);
}
#[rstest]
fn malformed_layer_size(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id', layer_sizes = '1kb, bob''s your uncle');
"#.execute_result(&mut conn);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(
err.into_database_error().unwrap().to_string(),
"invalid size: \" bob's your uncle\""
);
}
#[rstest]
fn all_good_layer_sizes(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id', layer_sizes = '1kb, 10kb, 100MB');
"#.execute_result(&mut conn);
assert!(result.is_ok());
}
#[rstest]
fn default_layer_sizes(mut conn: PgConnection) {
let result = r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id');
"#
.execute_result(&mut conn);
assert!(result.is_ok());
let (layer_sizes,) = r#"SELECT paradedb.layer_sizes('idxlayer_sizes')"#
.fetch_one::<(Vec,)>(&mut conn);
assert_eq!(
layer_sizes,
vec![
BigDecimal::from(100 * 1024),
BigDecimal::from(1024 * 1024),
BigDecimal::from(100 * 1024 * 1024)
]
);
}
#[rstest]
fn layer_sizes_after_alter(mut conn: PgConnection) {
r#"
CREATE TABLE layer_sizes (id serial8 not null primary key);
CREATE INDEX idxlayer_sizes ON layer_sizes USING bm25(id) WITH (key_field='id');
ALTER INDEX idxlayer_sizes SET (layer_sizes = '2kb, 3kb, 4kb');
"#
.execute(&mut conn);
let (layer_sizes,) = r#"SELECT paradedb.layer_sizes('idxlayer_sizes')"#
.fetch_one::<(Vec,)>(&mut conn);
assert_eq!(
layer_sizes,
vec![
BigDecimal::from(2 * 1024),
BigDecimal::from(3 * 1024),
BigDecimal::from(4 * 1024)
]
);
}