// 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 . use pgrx::pg_sys::panic::ErrorReport; use pgrx::*; use serde_json::{json, Map, Value}; #[pg_extern(immutable, parallel_safe)] #[allow(clippy::too_many_arguments)] pub fn field( name: &str, indexed: default!(Option, "NULL"), stored: default!(Option, "NULL"), fast: default!(Option, "NULL"), fieldnorms: default!(Option, "NULL"), record: default!(Option, "NULL"), expand_dots: default!(Option, "NULL"), tokenizer: default!(Option, "NULL"), normalizer: default!(Option, "NULL"), ) -> JsonB { if let Some(true) = stored { ErrorReport::new( PgSqlErrorCode::ERRCODE_WARNING_DEPRECATED_FEATURE, "the `stored` option is deprecated", function_name!(), ) .set_detail("the `stored` option is deprecated sine it is no longer needed by the index") .set_hint("remove it from the index configuration") .report(PgLogLevel::WARNING); } let mut config = Map::new(); indexed.map(|v| config.insert("indexed".to_string(), Value::Bool(v))); fast.map(|v| config.insert("fast".to_string(), Value::Bool(v))); fieldnorms.map(|v| config.insert("fieldnorms".to_string(), Value::Bool(v))); record.map(|v| config.insert("record".to_string(), Value::String(v))); expand_dots.map(|v| config.insert("expand_dots".to_string(), Value::Bool(v))); tokenizer.map(|v| config.insert("tokenizer".to_string(), v.0)); normalizer.map(|v| config.insert("normalizer".to_string(), Value::String(v))); JsonB(json!({ name: config })) } #[pg_extern(immutable, parallel_safe)] #[allow(clippy::too_many_arguments)] pub fn tokenizer( name: &str, remove_long: default!(Option, "255"), lowercase: default!(Option, "true"), min_gram: default!(Option, "NULL"), max_gram: default!(Option, "NULL"), prefix_only: default!(Option, "NULL"), language: default!(Option, "NULL"), pattern: default!(Option, "NULL"), stemmer: default!(Option, "NULL"), stopwords_language: default!(Option, "NULL"), stopwords: default!(Option>, "NULL"), ) -> JsonB { let mut config = Map::new(); config.insert("type".to_string(), Value::String(name.to_string())); // Options for all types remove_long.map(|v| config.insert("remove_long".to_string(), Value::Number(v.into()))); lowercase.map(|v| config.insert("lowercase".to_string(), Value::Bool(v))); stemmer.map(|v| config.insert("stemmer".to_string(), Value::String(v))); stopwords_language.map(|v| config.insert("stopwords_language".to_string(), Value::String(v))); stopwords.map(|v| { config.insert( "stopwords".to_string(), Value::Array(v.into_iter().map(Value::String).collect()), ) }); // Options for type = ngram min_gram.map(|v| config.insert("min_gram".to_string(), Value::Number(v.into()))); max_gram.map(|v| config.insert("max_gram".to_string(), Value::Number(v.into()))); prefix_only.map(|v| config.insert("prefix_only".to_string(), Value::Bool(v))); // Options for type = stem language.map(|v| config.insert("language".to_string(), Value::String(v))); // Options for type = regex pattern.map(|v| config.insert("pattern".to_string(), Value::String(v))); JsonB(json!(config)) }