diff --git a/Cargo.lock b/Cargo.lock index a1e4c6c755..2b2a96e275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,13 +248,34 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "generic-array", + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -275,6 +296,12 @@ dependencies = [ "glob", ] +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "bytea" version = "0.1.0" @@ -315,9 +342,12 @@ dependencies = [ "clap", "clap-cargo", "color-eyre", + "convert_case", "env_proxy", "eyre", "fork", + "handlebars", + "include_dir", "libloading", "num_cpus", "owo-colors", @@ -328,6 +358,10 @@ dependencies = [ "regex", "rttp_client", "semver 1.0.6", + "serde", + "serde_json", + "structmap", + "structmap-derive", "symbolic", "syn", "tracing", @@ -583,7 +617,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ - "generic-array", + "generic-array 0.14.5", "typenum", ] @@ -631,13 +665,22 @@ dependencies = [ "uuid", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "block-buffer", + "block-buffer 0.10.2", "crypto-common", "subtle", ] @@ -739,6 +782,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -917,6 +966,15 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.5" @@ -982,6 +1040,20 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "handlebars" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error", + "serde", + "serde_json", +] + [[package]] name = "hash32" version = "0.2.1" @@ -1030,7 +1102,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.3", ] [[package]] @@ -1050,6 +1122,26 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "include_dir" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482a2e29200b7eed25d7fdbd14423326760b7f6658d21a4cf12d55a50713c69f" +dependencies = [ + "glob", + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e074c19deab2501407c91ba1860fa3d6820bfde307db6d8cb851b55a10be89b" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indent_write" version = "2.2.0" @@ -1207,7 +1299,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" dependencies = [ - "digest", + "digest 0.10.3", ] [[package]] @@ -1412,6 +1504,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "openssl" version = "0.10.38" @@ -1553,6 +1651,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + [[package]] name = "petgraph" version = "0.6.0" @@ -1836,6 +1968,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.15" @@ -2272,6 +2410,18 @@ dependencies = [ "serde", ] +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.2" @@ -2280,7 +2430,7 @@ checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.3", ] [[package]] @@ -2423,6 +2573,26 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "structmap" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004de240cbe6afd3b7feccc8d5f0bd607548a1b9d958811c34fad2ebb2650ba3" +dependencies = [ + "structmap-derive", +] + +[[package]] +name = "structmap-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39163add6d8ce1ddaf5391097fdc2b9d48b34859a51e2b46c363f7b2db72505" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.4.1" diff --git a/cargo-pgx/Cargo.toml b/cargo-pgx/Cargo.toml index 7db3fa90e1..49ba681008 100644 --- a/cargo-pgx/Cargo.toml +++ b/cargo-pgx/Cargo.toml @@ -1,41 +1,74 @@ [package] -name = "cargo-pgx" -version = "0.4.0-beta.0" authors = ["ZomboDB, LLC "] -license = "MIT" +categories = ["development-tools::cargo-plugins", "command-line-utilities", "database"] description = "Cargo subcommand for 'pgx' to make Postgres extension development easy" -homepage = "https://github.com/zombodb/pgx" -repository = "https://github.com/zombodb/pgx" documentation = "https://docs.rs/cargo-pgx" -categories = ["development-tools::cargo-plugins", "command-line-utilities", "database"] +edition = "2021" +exclude = ["*.png"] +homepage = "https://github.com/zombodb/pgx" keywords = ["database", "postgres", "postgresql", "extension"] +license = "MIT" +name = "cargo-pgx" readme = "README.md" -exclude = [ "*.png" ] -edition = "2021" - +repository = "https://github.com/zombodb/pgx" +version = "0.4.0-beta.0" [dependencies] atty = "0.2" cargo_metadata = "0.14.2" cargo_toml = "0.11.4" -clap = { version = "3.1.2", features = [ "env", "suggestions", "cargo", "derive" ] } -clap-cargo = { version = "0.8.0", features = [ "cargo_metadata" ] } -semver = "1.0.6" -owo-colors = { version = "3.2.0", features = [ "supports-colors" ] } +color-eyre = "0.6.1" +convert_case = "*" env_proxy = "0.4.1" +eyre = "0.6.7" +fork = "0.1.18" +handlebars = "4.2.2" +libloading = "0.7.3" num_cpus = "1.13.1" -pgx-utils = { path = "../pgx-utils", version = "0.4.0-beta.0" } -proc-macro2 = { version = "1.0.36", features = [ "span-locations" ] } quote = "1.0.15" rayon = "1.5.1" regex = "1.5.4" -rttp_client = { version = "0.1.0", features = ["tls-native"] } -syn = { version = "1.0.86", features = [ "extra-traits", "full", "fold", "parsing" ] } -unescape = "0.1.0" -fork = "0.1.18" -libloading = "0.7.3" +semver = "1.0.6" +serde = "1.0.136" +serde_json = "1.0.59" +structmap = "0.1.5" +structmap-derive = "*" symbolic = "8.6.1" -eyre = "0.6.7" -color-eyre = "0.6.1" tracing = "0.1.31" tracing-error = "0.2.0" -tracing-subscriber = { version = "0.3.9", features = [ "env-filter" ] } +unescape = "0.1.0" + +[dependencies.clap] +features = ["env", "suggestions", "cargo", "derive"] +version = "3.1.2" + +[dependencies.clap-cargo] +features = ["cargo_metadata"] +version = "0.8.0" + +[dependencies.include_dir] +features = ["glob"] +version = "0.7.2" + +[dependencies.owo-colors] +features = ["supports-colors"] +version = "3.2.0" + +[dependencies.pgx-utils] +path = "../pgx-utils" +version = "0.4.0-beta.0" + +[dependencies.proc-macro2] +features = ["span-locations"] +version = "1.0.36" + +[dependencies.rttp_client] +features = ["tls-native"] +version = "0.1.0" + +[dependencies.syn] +features = ["extra-traits", "full", "fold", "parsing"] +version = "1.0.86" + +[dependencies.tracing-subscriber] +features = ["env-filter"] +version = "0.3.9" diff --git a/cargo-pgx/src/command/new.rs b/cargo-pgx/src/command/new.rs index 7dad3dd7e5..73469077a5 100644 --- a/cargo-pgx/src/command/new.rs +++ b/cargo-pgx/src/command/new.rs @@ -2,10 +2,20 @@ // governed by the MIT license that can be found in the LICENSE file. use eyre::eyre; +use include_dir::{include_dir, Dir, DirEntry}; +use std::collections::BTreeMap; +use std::ffi::OsStr; use std::{io::Write, path::PathBuf, str::FromStr}; use crate::CommandExecute; +use convert_case::{Case, Casing}; +use handlebars::handlebars_helper; +use handlebars::Handlebars; +use serde::{Deserialize, Serialize}; +use structmap::{value::Value, GenericMap, StringMap, ToMap}; +use structmap_derive::ToMap; + /// Create a new extension crate #[derive(clap::Args, Debug)] #[clap(author)] @@ -13,8 +23,8 @@ pub(crate) struct New { /// The name of the extension name: String, /// Create a background worker template - #[clap(long, short)] - bgworker: bool, + #[clap(long, short, arg_enum)] + template: Template, #[clap(from_global, parse(from_occurrences))] verbose: usize, } @@ -24,7 +34,9 @@ impl CommandExecute for New { fn execute(self) -> eyre::Result<()> { validate_extension_name(&self.name)?; let path = PathBuf::from_str(&format!("{}/", self.name)).unwrap(); - create_crate_template(path, &self.name, self.bgworker) + + let template_vars = TemplateVars { name: self.name }; + create_crate_template(path, template_vars, &self.template) } } @@ -36,97 +48,82 @@ fn validate_extension_name(extname: &str) -> eyre::Result<()> { } Ok(()) } - -#[tracing::instrument(skip_all, fields(path, name))] -pub(crate) fn create_crate_template( - path: PathBuf, - name: &str, - is_bgworker: bool, -) -> eyre::Result<()> { - create_directory_structure(&path)?; - create_control_file(&path, name)?; - create_cargo_toml(&path, name)?; - create_dotcargo_config(&path, name)?; - create_lib_rs(&path, name, is_bgworker)?; - create_git_ignore(&path, name)?; - - Ok(()) -} - -fn create_directory_structure(path: &PathBuf) -> Result<(), std::io::Error> { - let mut src_dir = path.clone(); - - src_dir.push("src"); - std::fs::create_dir_all(&src_dir)?; - - src_dir.pop(); - src_dir.push(".cargo"); - std::fs::create_dir_all(&src_dir)?; - - src_dir.pop(); - src_dir.push("sql"); - std::fs::create_dir_all(&src_dir) -} - -fn create_control_file(path: &PathBuf, name: &str) -> Result<(), std::io::Error> { - let mut filename = path.clone(); - - filename.push(format!("{}.control", name)); - let mut file = std::fs::File::create(filename)?; - - file.write_all(&format!(include_str!("../templates/control"), name = name).as_bytes())?; - - Ok(()) +#[derive(clap::ArgEnum, Debug, Clone)] +pub enum Template { + BGWORKER, + FUNCTION, + AGGREGATE, } -fn create_cargo_toml(path: &PathBuf, name: &str) -> Result<(), std::io::Error> { - let mut filename = path.clone(); - - filename.push("Cargo.toml"); - let mut file = std::fs::File::create(filename)?; - - file.write_all(&format!(include_str!("../templates/cargo_toml"), name = name).as_bytes())?; - - Ok(()) +// This could be improved to detect the directories at compile time +// Could even be a single include and then take the first levels at runtime +static FUNCTION_INCLUDE: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/src/templates/function/"); +static BGWORKER_INCLUDE: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/src/templates/bgworker/"); +static AGGREGATE_INCLUDE: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/src/templates/aggregate/"); + +impl Template { + fn as_payload(&self) -> &Dir<'_> { + match self { + Template::FUNCTION => &FUNCTION_INCLUDE, + Template::BGWORKER => &BGWORKER_INCLUDE, + Template::AGGREGATE => &AGGREGATE_INCLUDE, + } + } } -fn create_dotcargo_config(path: &PathBuf, _name: &str) -> Result<(), std::io::Error> { - let mut filename = path.clone(); - - filename.push(".cargo"); - filename.push("config"); - let mut file = std::fs::File::create(filename)?; - - file.write_all(include_bytes!("../templates/cargo_config"))?; - - Ok(()) +#[derive(Serialize, Deserialize, ToMap, Default)] +pub struct TemplateVars { + name: String, } -fn create_lib_rs(path: &PathBuf, name: &str, is_bgworker: bool) -> Result<(), std::io::Error> { - let mut filename = path.clone(); - - filename.push("src"); - filename.push("lib.rs"); - let mut file = std::fs::File::create(filename)?; - - if is_bgworker { - file.write_all( - &format!(include_str!("../templates/bgworker_lib_rs"), name = name).as_bytes(), - )?; - } else { - file.write_all(&format!(include_str!("../templates/lib_rs"), name = name).as_bytes())?; +#[tracing::instrument(skip_all, fields(path, name))] +pub(crate) fn create_crate_template( + path: PathBuf, + template_vars: TemplateVars, + template: &Template, +) -> eyre::Result<()> { + let template_map: BTreeMap = TemplateVars::to_stringmap(template_vars); + let glob = "**/*"; + let mut handlebars = Handlebars::new(); + handlebars_helper!(camel_case: |x: String| x.to_case(Case::UpperCamel)); + handlebars.register_helper("camel-case", Box::new(camel_case)); + for entry in template.as_payload().find(glob)? { + match entry { + DirEntry::Dir(dir) => { + println!("Found {}", dir.path().display()); + let mut target = path.clone(); + target.push(dir.path()); + std::fs::create_dir_all(&target)?; + } + DirEntry::File(file) => { + println!("Found {}", file.path().display()); + let mut target = path.clone(); + if file.path().file_name() == Some(OsStr::new("control")) { + target.push(format!("{}.control", template_map.get("name").unwrap())); + } else { + target.push(file.path()); + } + + handlebars.register_template_string( + file.path().to_str().unwrap(), + file.contents_utf8().unwrap(), + )?; + + let mut write_file = std::fs::File::create(target)?; + write_file + .write_all( + handlebars + .render(file.path().to_str().unwrap(), &template_map) + .expect(&format!( + "templating {} failed", + file.path().to_str().unwrap() + )) + .as_bytes(), + ) + .expect("error in writing template code"); + } + } } Ok(()) } - -fn create_git_ignore(path: &PathBuf, _name: &str) -> Result<(), std::io::Error> { - let mut filename = path.clone(); - - filename.push(".gitignore"); - let mut file = std::fs::File::create(filename)?; - - file.write_all(include_bytes!("../templates/gitignore"))?; - - Ok(()) -} diff --git a/cargo-pgx/src/main.rs b/cargo-pgx/src/main.rs index ac088c7296..c74ef5cb27 100644 --- a/cargo-pgx/src/main.rs +++ b/cargo-pgx/src/main.rs @@ -46,11 +46,13 @@ impl CommandExecute for CargoSubcommands { } fn main() -> color_eyre::Result<()> { - color_eyre::config::HookBuilder::default().theme(if !atty::is(Stream::Stderr) { - color_eyre::config::Theme::new() - } else { - color_eyre::config::Theme::default() - }).install()?; + color_eyre::config::HookBuilder::default() + .theme(if !atty::is(Stream::Stderr) { + color_eyre::config::Theme::new() + } else { + color_eyre::config::Theme::default() + }) + .install()?; let cargo_cli = CargoCommand::parse(); diff --git a/cargo-pgx/src/templates/cargo_config b/cargo-pgx/src/templates/aggregate/.cargo/config similarity index 100% rename from cargo-pgx/src/templates/cargo_config rename to cargo-pgx/src/templates/aggregate/.cargo/config diff --git a/cargo-pgx/src/templates/gitignore b/cargo-pgx/src/templates/aggregate/.gitignore similarity index 100% rename from cargo-pgx/src/templates/gitignore rename to cargo-pgx/src/templates/aggregate/.gitignore diff --git a/cargo-pgx/src/templates/cargo_toml b/cargo-pgx/src/templates/aggregate/Cargo.toml similarity index 96% rename from cargo-pgx/src/templates/cargo_toml rename to cargo-pgx/src/templates/aggregate/Cargo.toml index f128f52fab..128e6a7bcd 100644 --- a/cargo-pgx/src/templates/cargo_toml +++ b/cargo-pgx/src/templates/aggregate/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "{name}" +name = "{{ name }}" version = "0.0.0" edition = "2021" diff --git a/cargo-pgx/src/templates/aggregate/control b/cargo-pgx/src/templates/aggregate/control new file mode 100644 index 0000000000..4873950d04 --- /dev/null +++ b/cargo-pgx/src/templates/aggregate/control @@ -0,0 +1,5 @@ +comment = '{{ name }}: Created by pgx' +default_version = '@CARGO_VERSION@' +module_pathname = '$libdir/{{ name }}' +relocatable = false +superuser = false diff --git a/cargo-pgx/src/templates/aggregate/src/lib.rs b/cargo-pgx/src/templates/aggregate/src/lib.rs new file mode 100644 index 0000000000..0ef6395541 --- /dev/null +++ b/cargo-pgx/src/templates/aggregate/src/lib.rs @@ -0,0 +1,62 @@ +use pgx::*; +use std::collections::HashSet; + +pg_module_magic!(); + +#[derive(Copy, Clone, Default, Debug)] +pub struct {{ camel-case name }}; + +// This is an example of a basic agg which adds values to a HashSet +// then returns the number of elements which have been added +// see https://hoverbear.org/blog/postgresql-aggregates-with-rust/ for more examples + +#[pg_aggregate] +impl Aggregate for {{ camel-case name }} { + type Args = &'static str; + type State = Internal; + type Finalize = i32; + + fn state( + mut current: Self::State, + arg: Self::Args, + _fcinfo: pg_sys::FunctionCallInfo, + ) -> Self::State { + let inner = unsafe { current.get_or_insert_default::>() }; + inner.insert(arg.to_string()); + current + } + + fn combine( + mut first: Self::State, + mut second: Self::State, + _fcinfo: pg_sys::FunctionCallInfo + ) -> Self::State { + let first_inner = unsafe { first.get_or_insert_default::>() }; + let second_inner = unsafe { second.get_or_insert_default::>() }; + + let unioned: HashSet<_> = first_inner.union(second_inner).collect(); + Internal::new(unioned) + } + + fn finalize( + mut current: Self::State, + _direct_arg: Self::OrderedSetArgs, + _fcinfo: pg_sys::FunctionCallInfo, + ) -> Self::Finalize { + let inner = unsafe { current.get_or_insert_default::>() }; + + inner.len() as i32 + } +} + +#[cfg(test)] +pub mod pg_test { + pub fn setup(_options: Vec<&str>) { + // perform one-off initialization when the pg_test framework starts + } + + pub fn postgresql_conf_options() -> Vec<&'static str> { + // return any postgresql.conf settings that are required for your tests + vec![] + } +} diff --git a/cargo-pgx/src/templates/bgworker/.cargo/config b/cargo-pgx/src/templates/bgworker/.cargo/config new file mode 100644 index 0000000000..2b25fcd1d7 --- /dev/null +++ b/cargo-pgx/src/templates/bgworker/.cargo/config @@ -0,0 +1,3 @@ +[build] +# Postgres symbols won't be available until runtime +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] diff --git a/cargo-pgx/src/templates/bgworker/.gitignore b/cargo-pgx/src/templates/bgworker/.gitignore new file mode 100644 index 0000000000..3906c33241 --- /dev/null +++ b/cargo-pgx/src/templates/bgworker/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.idea/ +/target +*.iml +**/*.rs.bk +Cargo.lock diff --git a/cargo-pgx/src/templates/bgworker/Cargo.toml b/cargo-pgx/src/templates/bgworker/Cargo.toml new file mode 100644 index 0000000000..128e6a7bcd --- /dev/null +++ b/cargo-pgx/src/templates/bgworker/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "{{ name }}" +version = "0.0.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +default = ["pg13"] +pg10 = ["pgx/pg10", "pgx-tests/pg10" ] +pg11 = ["pgx/pg11", "pgx-tests/pg11" ] +pg12 = ["pgx/pg12", "pgx-tests/pg12" ] +pg13 = ["pgx/pg13", "pgx-tests/pg13" ] +pg14 = ["pgx/pg14", "pgx-tests/pg14" ] +pg_test = [] + +[dependencies] +pgx = "0.4.0-beta.0" + +[dev-dependencies] +pgx-tests = "0.4.0-beta.0" + +[profile.dev] +panic = "unwind" +lto = "thin" + +[profile.release] +panic = "unwind" +opt-level = 3 +lto = "fat" +codegen-units = 1 diff --git a/cargo-pgx/src/templates/bgworker/control b/cargo-pgx/src/templates/bgworker/control new file mode 100644 index 0000000000..4873950d04 --- /dev/null +++ b/cargo-pgx/src/templates/bgworker/control @@ -0,0 +1,5 @@ +comment = '{{ name }}: Created by pgx' +default_version = '@CARGO_VERSION@' +module_pathname = '$libdir/{{ name }}' +relocatable = false +superuser = false diff --git a/cargo-pgx/src/templates/bgworker_lib_rs b/cargo-pgx/src/templates/bgworker/src/lib.rs similarity index 75% rename from cargo-pgx/src/templates/bgworker_lib_rs rename to cargo-pgx/src/templates/bgworker/src/lib.rs index 0e40e1c768..1ff2921004 100644 --- a/cargo-pgx/src/templates/bgworker_lib_rs +++ b/cargo-pgx/src/templates/bgworker/src/lib.rs @@ -21,19 +21,19 @@ pg_module_magic!(); #[allow(non_snake_case)] #[pg_guard] -pub extern "C" fn _PG_init() {{ - BackgroundWorkerBuilder::new("{name}") +pub extern "C" fn _PG_init() { + BackgroundWorkerBuilder::new("{{ name }}") .set_function("background_worker_main") - .set_library("{name}") + .set_library("{{ name }}") .set_argument(42i32.into_datum()) .enable_spi_access() .load(); -}} +} #[pg_guard] #[no_mangle] -pub extern "C" fn background_worker_main(arg: pg_sys::Datum) {{ - let arg = unsafe {{ i32::from_datum(arg, false, pg_sys::INT4OID) }}; +pub extern "C" fn background_worker_main(arg: pg_sys::Datum) { + let arg = unsafe { i32::from_datum(arg, false, pg_sys::INT4OID) }; // these are the signals we want to receive. If we don't attach the SIGTERM handler, then // we'll never be able to exit via an external notification @@ -43,37 +43,37 @@ pub extern "C" fn background_worker_main(arg: pg_sys::Datum) {{ BackgroundWorker::connect_worker_to_spi(Some("postgres"), None); log!( - "Background Worker '{{}}' is starting. Argument={{}}", + "Background Worker '{}' is starting. Argument={}", BackgroundWorker::get_name(), arg.unwrap() ); // wake up every 10s or if we received a SIGTERM - while BackgroundWorker::wait_latch(Some(Duration::from_secs(10))) {{ - if BackgroundWorker::sighup_received() {{ + while BackgroundWorker::wait_latch(Some(Duration::from_secs(10))) { + if BackgroundWorker::sighup_received() { // on SIGHUP, you might want to reload some external configuration or something - }} + } // within a transaction, execute an SQL statement, and log its results - BackgroundWorker::transaction(|| {{ - Spi::execute(|client| {{ + BackgroundWorker::transaction(|| { + Spi::execute(|client| { let tuple_table = client.select( "SELECT 'Hi', id, ''||a FROM (SELECT id, 42 from generate_series(1,10) id) a ", None, None, ); - tuple_table.for_each(|tuple| {{ + tuple_table.for_each(|tuple| { let a = tuple.by_ordinal(1).unwrap().value::().unwrap(); let b = tuple.by_ordinal(2).unwrap().value::().unwrap(); let c = tuple.by_ordinal(3).unwrap().value::().unwrap(); - log!("from bgworker: ({{}}, {{}}, {{}})", a, b, c); - }}); - }}); - }}); - }} + log!("from bgworker: ({}, {}, {})", a, b, c); + }); + }); + }); + } log!( - "Background Worker '{{}}' is exiting", + "Background Worker '{}' is exiting", BackgroundWorker::get_name() ); -}} +} diff --git a/cargo-pgx/src/templates/control b/cargo-pgx/src/templates/control deleted file mode 100644 index 797900b7da..0000000000 --- a/cargo-pgx/src/templates/control +++ /dev/null @@ -1,5 +0,0 @@ -comment = '{name}: Created by pgx' -default_version = '@CARGO_VERSION@' -module_pathname = '$libdir/{name}' -relocatable = false -superuser = false diff --git a/cargo-pgx/src/templates/function/.cargo/config b/cargo-pgx/src/templates/function/.cargo/config new file mode 100644 index 0000000000..2b25fcd1d7 --- /dev/null +++ b/cargo-pgx/src/templates/function/.cargo/config @@ -0,0 +1,3 @@ +[build] +# Postgres symbols won't be available until runtime +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] diff --git a/cargo-pgx/src/templates/function/.gitignore b/cargo-pgx/src/templates/function/.gitignore new file mode 100644 index 0000000000..3906c33241 --- /dev/null +++ b/cargo-pgx/src/templates/function/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.idea/ +/target +*.iml +**/*.rs.bk +Cargo.lock diff --git a/cargo-pgx/src/templates/function/Cargo.toml b/cargo-pgx/src/templates/function/Cargo.toml new file mode 100644 index 0000000000..128e6a7bcd --- /dev/null +++ b/cargo-pgx/src/templates/function/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "{{ name }}" +version = "0.0.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +default = ["pg13"] +pg10 = ["pgx/pg10", "pgx-tests/pg10" ] +pg11 = ["pgx/pg11", "pgx-tests/pg11" ] +pg12 = ["pgx/pg12", "pgx-tests/pg12" ] +pg13 = ["pgx/pg13", "pgx-tests/pg13" ] +pg14 = ["pgx/pg14", "pgx-tests/pg14" ] +pg_test = [] + +[dependencies] +pgx = "0.4.0-beta.0" + +[dev-dependencies] +pgx-tests = "0.4.0-beta.0" + +[profile.dev] +panic = "unwind" +lto = "thin" + +[profile.release] +panic = "unwind" +opt-level = 3 +lto = "fat" +codegen-units = 1 diff --git a/cargo-pgx/src/templates/function/control b/cargo-pgx/src/templates/function/control new file mode 100644 index 0000000000..4873950d04 --- /dev/null +++ b/cargo-pgx/src/templates/function/control @@ -0,0 +1,5 @@ +comment = '{{ name }}: Created by pgx' +default_version = '@CARGO_VERSION@' +module_pathname = '$libdir/{{ name }}' +relocatable = false +superuser = false diff --git a/cargo-pgx/src/templates/lib_rs b/cargo-pgx/src/templates/function/src/lib.rs similarity index 50% rename from cargo-pgx/src/templates/lib_rs rename to cargo-pgx/src/templates/function/src/lib.rs index 2792daa6f7..f590c8c745 100644 --- a/cargo-pgx/src/templates/lib_rs +++ b/cargo-pgx/src/templates/function/src/lib.rs @@ -3,30 +3,30 @@ use pgx::*; pg_module_magic!(); #[pg_extern] -fn hello_{name}() -> &'static str {{ - "Hello, {name}" -}} +fn hello_{{ name }}() -> &'static str { + "Hello, {{ name }}" +} #[cfg(any(test, feature = "pg_test"))] #[pg_schema] -mod tests {{ +mod tests { use pgx::*; #[pg_test] - fn test_hello_{name}() {{ - assert_eq!("Hello, {name}", crate::hello_{name}()); - }} + fn test_hello_{{ name }}() { + assert_eq!("Hello, {{ name }}", crate::hello_{{ name }}()); + } -}} +} #[cfg(test)] -pub mod pg_test {{ - pub fn setup(_options: Vec<&str>) {{ +pub mod pg_test { + pub fn setup(_options: Vec<&str>) { // perform one-off initialization when the pg_test framework starts - }} + } - pub fn postgresql_conf_options() -> Vec<&'static str> {{ + pub fn postgresql_conf_options() -> Vec<&'static str> { // return any postgresql.conf settings that are required for your tests vec![] - }} -}} + } +}