From 8e849a67d65d45a28d23a69506c9d8f366a48fd1 Mon Sep 17 00:00:00 2001
From: Bo Lu
Date: Wed, 12 Jun 2024 11:08:17 +1000
Subject: [PATCH] add data modify to paddle fdw
---
wasm-wrappers/fdw/paddle_fdw/src/bindings.rs | 391 +++++++++++++++----
wasm-wrappers/fdw/paddle_fdw/src/lib.rs | 82 +++-
wasm-wrappers/wit/http.wit | 4 +
wasm-wrappers/wit/time.wit | 3 +
wrappers/src/fdw/wasm_fdw/host/http.rs | 58 +--
wrappers/src/fdw/wasm_fdw/host/time.rs | 6 +
6 files changed, 427 insertions(+), 117 deletions(-)
diff --git a/wasm-wrappers/fdw/paddle_fdw/src/bindings.rs b/wasm-wrappers/fdw/paddle_fdw/src/bindings.rs
index 1b0e02f5..c3e8bb29 100644
--- a/wasm-wrappers/fdw/paddle_fdw/src/bindings.rs
+++ b/wasm-wrappers/fdw/paddle_fdw/src/bindings.rs
@@ -17,12 +17,18 @@ pub mod supabase {
pub enum Method {
Get,
Post,
+ Put,
+ Patch,
+ Delete,
}
impl ::core::fmt::Debug for Method {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
match self {
Method::Get => f.debug_tuple("Method::Get").finish(),
Method::Post => f.debug_tuple("Method::Post").finish(),
+ Method::Put => f.debug_tuple("Method::Put").finish(),
+ Method::Patch => f.debug_tuple("Method::Patch").finish(),
+ Method::Delete => f.debug_tuple("Method::Delete").finish(),
}
}
}
@@ -77,6 +83,9 @@ pub mod supabase {
let result1 = match method0 {
Method::Get => 0i32,
Method::Post => 1i32,
+ Method::Put => 2i32,
+ Method::Patch => 3i32,
+ Method::Delete => 4i32,
};
let vec2 = url0;
let ptr2 = vec2.as_ptr().cast::();
@@ -234,6 +243,9 @@ pub mod supabase {
let result1 = match method0 {
Method::Get => 0i32,
Method::Post => 1i32,
+ Method::Put => 2i32,
+ Method::Patch => 3i32,
+ Method::Delete => 4i32,
};
let vec2 = url0;
let ptr2 = vec2.as_ptr().cast::();
@@ -391,6 +403,9 @@ pub mod supabase {
let result1 = match method0 {
Method::Get => 0i32,
Method::Post => 1i32,
+ Method::Put => 2i32,
+ Method::Patch => 3i32,
+ Method::Delete => 4i32,
};
let vec2 = url0;
let ptr2 = vec2.as_ptr().cast::();
@@ -534,6 +549,166 @@ pub mod supabase {
}
}
#[allow(unused_unsafe, clippy::all)]
+ pub fn patch(req: &Request) -> HttpResult {
+ unsafe {
+ #[repr(align(4))]
+ struct RetArea([::core::mem::MaybeUninit; 32]);
+ let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 32]);
+ let Request {
+ method: method0,
+ url: url0,
+ headers: headers0,
+ body: body0,
+ } = req;
+ let result1 = match method0 {
+ Method::Get => 0i32,
+ Method::Post => 1i32,
+ Method::Put => 2i32,
+ Method::Patch => 3i32,
+ Method::Delete => 4i32,
+ };
+ let vec2 = url0;
+ let ptr2 = vec2.as_ptr().cast::();
+ let len2 = vec2.len();
+ let vec6 = headers0;
+ let len6 = vec6.len();
+ let layout6 = _rt::alloc::Layout::from_size_align_unchecked(vec6.len() * 16, 4);
+ let result6 = if layout6.size() != 0 {
+ let ptr = _rt::alloc::alloc(layout6).cast::();
+ if ptr.is_null() {
+ _rt::alloc::handle_alloc_error(layout6);
+ }
+ ptr
+ } else {
+ {
+ ::core::ptr::null_mut()
+ }
+ };
+ for (i, e) in vec6.into_iter().enumerate() {
+ let base = result6.add(i * 16);
+ {
+ let (t3_0, t3_1) = e;
+ let vec4 = t3_0;
+ let ptr4 = vec4.as_ptr().cast::();
+ let len4 = vec4.len();
+ *base.add(4).cast::() = len4;
+ *base.add(0).cast::<*mut u8>() = ptr4.cast_mut();
+ let vec5 = t3_1;
+ let ptr5 = vec5.as_ptr().cast::();
+ let len5 = vec5.len();
+ *base.add(12).cast::() = len5;
+ *base.add(8).cast::<*mut u8>() = ptr5.cast_mut();
+ }
+ }
+ let vec7 = body0;
+ let ptr7 = vec7.as_ptr().cast::();
+ let len7 = vec7.len();
+ let ptr8 = ret_area.0.as_mut_ptr().cast::();
+ #[cfg(target_arch = "wasm32")]
+ #[link(wasm_import_module = "supabase:wrappers/http@0.1.0")]
+ extern "C" {
+ #[link_name = "patch"]
+ fn wit_import(
+ _: i32,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ );
+ }
+
+ #[cfg(not(target_arch = "wasm32"))]
+ fn wit_import(
+ _: i32,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ _: usize,
+ _: *mut u8,
+ ) {
+ unreachable!()
+ }
+ wit_import(
+ result1,
+ ptr2.cast_mut(),
+ len2,
+ result6,
+ len6,
+ ptr7.cast_mut(),
+ len7,
+ ptr8,
+ );
+ let l9 = i32::from(*ptr8.add(0).cast::());
+ if layout6.size() != 0 {
+ _rt::alloc::dealloc(result6.cast(), layout6);
+ }
+ match l9 {
+ 0 => {
+ let e = {
+ let l10 = *ptr8.add(4).cast::<*mut u8>();
+ let l11 = *ptr8.add(8).cast::();
+ let len12 = l11;
+ let bytes12 = _rt::Vec::from_raw_parts(l10.cast(), len12, len12);
+ let l13 = i32::from(*ptr8.add(12).cast::());
+ let l14 = *ptr8.add(16).cast::<*mut u8>();
+ let l15 = *ptr8.add(20).cast::();
+ let base22 = l14;
+ let len22 = l15;
+ let mut result22 = _rt::Vec::with_capacity(len22);
+ for i in 0..len22 {
+ let base = base22.add(i * 16);
+ let e22 = {
+ let l16 = *base.add(0).cast::<*mut u8>();
+ let l17 = *base.add(4).cast::();
+ let len18 = l17;
+ let bytes18 =
+ _rt::Vec::from_raw_parts(l16.cast(), len18, len18);
+ let l19 = *base.add(8).cast::<*mut u8>();
+ let l20 = *base.add(12).cast::();
+ let len21 = l20;
+ let bytes21 =
+ _rt::Vec::from_raw_parts(l19.cast(), len21, len21);
+
+ (_rt::string_lift(bytes18), _rt::string_lift(bytes21))
+ };
+ result22.push(e22);
+ }
+ _rt::cabi_dealloc(base22, len22 * 16, 4);
+ let l23 = *ptr8.add(24).cast::<*mut u8>();
+ let l24 = *ptr8.add(28).cast::();
+ let len25 = l24;
+ let bytes25 = _rt::Vec::from_raw_parts(l23.cast(), len25, len25);
+
+ Response {
+ url: _rt::string_lift(bytes12),
+ status_code: l13 as u16,
+ headers: result22,
+ body: _rt::string_lift(bytes25),
+ }
+ };
+ Ok(e)
+ }
+ 1 => {
+ let e = {
+ let l26 = *ptr8.add(4).cast::<*mut u8>();
+ let l27 = *ptr8.add(8).cast::();
+ let len28 = l27;
+ let bytes28 = _rt::Vec::from_raw_parts(l26.cast(), len28, len28);
+
+ _rt::string_lift(bytes28)
+ };
+ Err(e)
+ }
+ _ => _rt::invalid_enum_discriminant(),
+ }
+ }
+ }
+ #[allow(unused_unsafe, clippy::all)]
pub fn delete(req: &Request) -> HttpResult {
unsafe {
#[repr(align(4))]
@@ -548,6 +723,9 @@ pub mod supabase {
let result1 = match method0 {
Method::Get => 0i32,
Method::Post => 1i32,
+ Method::Put => 2i32,
+ Method::Patch => 3i32,
+ Method::Delete => 4i32,
};
let vec2 = url0;
let ptr2 = vec2.as_ptr().cast::();
@@ -1191,6 +1369,54 @@ pub mod supabase {
}
}
#[allow(unused_unsafe, clippy::all)]
+ /// convert microseconds since Unix epoch to RFC3339 string
+ pub fn epoch_ms_to_rfc3339(msecs: i64) -> Result<_rt::String, TimeError> {
+ unsafe {
+ #[repr(align(4))]
+ struct RetArea([::core::mem::MaybeUninit; 12]);
+ let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 12]);
+ let ptr0 = ret_area.0.as_mut_ptr().cast::();
+ #[cfg(target_arch = "wasm32")]
+ #[link(wasm_import_module = "supabase:wrappers/time@0.1.0")]
+ extern "C" {
+ #[link_name = "epoch-ms-to-rfc3339"]
+ fn wit_import(_: i64, _: *mut u8);
+ }
+
+ #[cfg(not(target_arch = "wasm32"))]
+ fn wit_import(_: i64, _: *mut u8) {
+ unreachable!()
+ }
+ wit_import(_rt::as_i64(&msecs), ptr0);
+ let l1 = i32::from(*ptr0.add(0).cast::());
+ match l1 {
+ 0 => {
+ let e = {
+ let l2 = *ptr0.add(4).cast::<*mut u8>();
+ let l3 = *ptr0.add(8).cast::();
+ let len4 = l3;
+ let bytes4 = _rt::Vec::from_raw_parts(l2.cast(), len4, len4);
+
+ _rt::string_lift(bytes4)
+ };
+ Ok(e)
+ }
+ 1 => {
+ let e = {
+ let l5 = *ptr0.add(4).cast::<*mut u8>();
+ let l6 = *ptr0.add(8).cast::();
+ let len7 = l6;
+ let bytes7 = _rt::Vec::from_raw_parts(l5.cast(), len7, len7);
+
+ _rt::string_lift(bytes7)
+ };
+ Err(e)
+ }
+ _ => _rt::invalid_enum_discriminant(),
+ }
+ }
+ }
+ #[allow(unused_unsafe, clippy::all)]
/// sleep for a while
pub fn sleep(millis: u64) {
unsafe {
@@ -4637,88 +4863,89 @@ pub(crate) use __export_paddle_impl as export;
#[cfg(target_arch = "wasm32")]
#[link_section = "component-type:wit-bindgen:0.24.0:paddle:encoded world"]
#[doc(hidden)]
-pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 3581] = *b"\
-\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x80\x1b\x01A\x02\x01\
-A\x13\x01B\x15\x01o\x02ss\x01p\0\x04\0\x07headers\x03\0\x01\x01q\x02\x03get\0\0\x04\
-post\0\0\x04\0\x06method\x03\0\x03\x01r\x04\x06method\x04\x03urls\x07headers\x02\
-\x04bodys\x04\0\x07request\x03\0\x05\x01r\x04\x03urls\x0bstatus-code{\x07headers\
-\x02\x04bodys\x04\0\x08response\x03\0\x07\x01s\x04\0\x0ahttp-error\x03\0\x09\x01\
-j\x01\x08\x01\x0a\x04\0\x0bhttp-result\x03\0\x0b\x01@\x01\x03req\x06\0\x0c\x04\0\
-\x03get\x01\x0d\x04\0\x04post\x01\x0d\x04\0\x03put\x01\x0d\x04\0\x06delete\x01\x0d\
-\x01j\0\x01\x0a\x01@\x01\x04resp\x08\0\x0e\x04\0\x10error-for-status\x01\x0f\x03\
-\x01\x1csupabase:wrappers/http@0.1.0\x05\0\x01B\x08\x01s\x04\0\x09jwt-error\x03\0\
-\0\x01j\x01s\x01\x01\x04\0\x0ajwt-result\x03\0\x02\x01o\x02ss\x01p\x04\x01@\x04\x07\
-payload\x05\x04algos\x03keys\x09ttl-hoursy\0\x03\x04\0\x06encode\x01\x06\x03\x01\
-\x1bsupabase:wrappers/jwt@0.1.0\x05\x01\x01B\x0a\x01ks\x04\0\x08metadata\x03\0\0\
-\x01q\x05\x0ccreate-times\0\0\x07rows-in\0\0\x08rows-out\0\0\x08bytes-in\0\0\x09\
-bytes-out\0\0\x04\0\x06metric\x03\0\x02\x01@\x03\x08fdw-names\x06metric\x03\x03i\
-ncx\x01\0\x04\0\x09inc-stats\x01\x04\x01@\x01\x08fdw-names\0\x01\x04\0\x0cget-me\
-tadata\x01\x05\x01@\x02\x08fdw-names\x08metadata\x01\x01\0\x04\0\x0cset-metadata\
-\x01\x06\x03\x01\x1dsupabase:wrappers/stats@0.1.0\x05\x02\x01B\x0c\x01s\x04\0\x0a\
-time-error\x03\0\0\x01j\x01x\x01\x01\x04\0\x0btime-result\x03\0\x02\x01@\0\0x\x04\
-\0\x0aepoch-secs\x01\x04\x01@\x01\x01ss\0\x03\x04\0\x12parse-from-rfc3339\x01\x05\
-\x01@\x02\x01ss\x03fmts\0\x03\x04\0\x0eparse-from-str\x01\x06\x01@\x01\x06millis\
-w\x01\0\x04\0\x05sleep\x01\x07\x03\x01\x1csupabase:wrappers/time@0.1.0\x05\x03\x01\
-Br\x01q\x0d\x04bool\0\0\x02i8\0\0\x03i16\0\0\x03f32\0\0\x03i32\0\0\x03f64\0\0\x03\
-i64\0\0\x07numeric\0\0\x06string\0\0\x04date\0\0\x09timestamp\0\0\x0btimestamptz\
-\0\0\x04json\0\0\x04\0\x08type-oid\x03\0\0\x01q\x0d\x04bool\x01\x7f\0\x02i8\x01~\
-\0\x03i16\x01|\0\x03f32\x01v\0\x03i32\x01z\0\x03f64\x01u\0\x03i64\x01x\0\x07nume\
-ric\x01u\0\x06string\x01s\0\x04date\x01x\0\x09timestamp\x01x\0\x0btimestamptz\x01\
-x\0\x04json\x01s\0\x04\0\x04cell\x03\0\x02\x04\0\x03row\x03\x01\x04\0\x06column\x03\
-\x01\x01p\x03\x01q\x02\x04cell\x01\x03\0\x05array\x01\x06\0\x04\0\x05value\x03\0\
-\x07\x01r\x02\x02idy\x08type-oidy\x04\0\x05param\x03\0\x09\x04\0\x04qual\x03\x01\
-\x04\0\x04sort\x03\x01\x04\0\x05limit\x03\x01\x01q\x02\x06server\0\0\x05table\0\0\
-\x04\0\x0coptions-type\x03\0\x0e\x04\0\x07options\x03\x01\x04\0\x07context\x03\x01\
-\x01s\x04\0\x09fdw-error\x03\0\x12\x01j\0\x01\x13\x04\0\x0afdw-result\x03\0\x14\x01\
-i\x04\x01@\0\0\x16\x04\0\x10[constructor]row\x01\x17\x01h\x04\x01ps\x01@\x01\x04\
-self\x18\0\x19\x04\0\x10[method]row.cols\x01\x1a\x01k\x03\x01p\x1b\x01@\x01\x04s\
-elf\x18\0\x1c\x04\0\x11[method]row.cells\x01\x1d\x01@\x02\x04self\x18\x04cell\x1b\
-\x01\0\x04\0\x10[method]row.push\x01\x1e\x01i\x05\x01@\x01\x05indexy\0\x1f\x04\0\
-\x13[constructor]column\x01\x20\x01h\x05\x01@\x01\x04self!\0s\x04\0\x13[method]c\
-olumn.name\x01\"\x01@\x01\x04self!\0y\x04\0\x12[method]column.num\x01#\x01@\x01\x04\
-self!\0\x01\x04\0\x17[method]column.type-oid\x01$\x01i\x0b\x01@\x01\x05indexy\0%\
-\x04\0\x11[constructor]qual\x01&\x01h\x0b\x01@\x01\x04self'\0s\x04\0\x12[method]\
-qual.field\x01(\x04\0\x15[method]qual.operator\x01(\x01@\x01\x04self'\0\x08\x04\0\
-\x12[method]qual.value\x01)\x01@\x01\x04self'\0\x7f\x04\0\x13[method]qual.use-or\
-\x01*\x01k\x0a\x01@\x01\x04self'\0+\x04\0\x12[method]qual.param\x01,\x04\0\x14[m\
-ethod]qual.deparse\x01(\x01i\x0c\x01@\x01\x05indexy\0-\x04\0\x11[constructor]sor\
-t\x01.\x01h\x0c\x01@\x01\x04self/\0s\x04\0\x12[method]sort.field\x010\x01@\x01\x04\
-self/\0y\x04\0\x15[method]sort.field-no\x011\x01@\x01\x04self/\0\x7f\x04\0\x15[m\
-ethod]sort.reversed\x012\x04\0\x18[method]sort.nulls-first\x012\x01ks\x01@\x01\x04\
-self/\03\x04\0\x14[method]sort.collate\x014\x04\0\x14[method]sort.deparse\x010\x04\
-\0![method]sort.deparse-with-collate\x010\x01i\x0d\x01@\0\05\x04\0\x12[construct\
-or]limit\x016\x01h\x0d\x01@\x01\x04self7\0x\x04\0\x13[method]limit.count\x018\x04\
-\0\x14[method]limit.offset\x018\x01@\x01\x04self7\0s\x04\0\x15[method]limit.depa\
-rse\x019\x01i\x10\x01@\x01\x0coptions-type\x0f\0:\x04\0\x14[constructor]options\x01\
-;\x01h\x10\x01@\x02\x04self<\x03keys\03\x04\0\x13[method]options.get\x01=\x01j\x01\
-s\x01\x13\x01@\x02\x04self<\x03keys\0>\x04\0\x17[method]options.require\x01?\x01\
-@\x03\x04self<\x03keys\x07defaults\0s\x04\0\x1a[method]options.require-or\x01@\x01\
-i\x11\x01@\0\0\xc1\0\x04\0\x14[constructor]context\x01B\x01h\x11\x01@\x02\x04sel\
-f\xc3\0\x0coptions-type\x0f\0:\x04\0\x1b[method]context.get-options\x01D\x01p%\x01\
-@\x01\x04self\xc3\0\0\xc5\0\x04\0\x19[method]context.get-quals\x01F\x01p\x1f\x01\
-@\x01\x04self\xc3\0\0\xc7\0\x04\0\x1b[method]context.get-columns\x01H\x01p-\x01@\
-\x01\x04self\xc3\0\0\xc9\0\x04\0\x19[method]context.get-sorts\x01J\x01k5\x01@\x01\
-\x04self\xc3\0\0\xcb\0\x04\0\x19[method]context.get-limit\x01L\x03\x01\x1dsupaba\
-se:wrappers/types@0.1.0\x05\x04\x02\x03\0\x04\x04cell\x01B\x0d\x02\x03\x02\x01\x05\
-\x04\0\x04cell\x03\0\0\x01@\x01\x03msgs\x01\0\x04\0\x0breport-info\x01\x02\x04\0\
-\x0dreport-notice\x01\x02\x04\0\x0ereport-warning\x01\x02\x04\0\x0creport-error\x01\
-\x02\x01k\x01\x01@\x01\x04cell\x03\0s\x04\0\x0ecell-to-string\x01\x04\x01ks\x01@\
-\x01\x09secret-ids\0\x05\x04\0\x10get-vault-secret\x01\x06\x03\x01\x1dsupabase:w\
-rappers/utils@0.1.0\x05\x06\x02\x03\0\x04\x03row\x02\x03\0\x04\x07context\x02\x03\
-\0\x04\x09fdw-error\x02\x03\0\x04\x0afdw-result\x01B\x1f\x02\x03\x02\x01\x05\x04\
-\0\x04cell\x03\0\0\x02\x03\x02\x01\x07\x04\0\x03row\x03\0\x02\x02\x03\x02\x01\x08\
-\x04\0\x07context\x03\0\x04\x02\x03\x02\x01\x09\x04\0\x09fdw-error\x03\0\x06\x02\
-\x03\x02\x01\x0a\x04\0\x0afdw-result\x03\0\x08\x01@\0\0s\x04\0\x18host-version-r\
-equirement\x01\x0a\x01h\x05\x01@\x01\x03ctx\x0b\0\x09\x04\0\x04init\x01\x0c\x04\0\
-\x0abegin-scan\x01\x0c\x01h\x03\x01ky\x01j\x01\x0e\x01\x07\x01@\x02\x03ctx\x0b\x03\
-row\x0d\0\x0f\x04\0\x09iter-scan\x01\x10\x04\0\x07re-scan\x01\x0c\x04\0\x08end-s\
-can\x01\x0c\x04\0\x0cbegin-modify\x01\x0c\x01@\x02\x03ctx\x0b\x03row\x0d\0\x09\x04\
-\0\x06insert\x01\x11\x01@\x03\x03ctx\x0b\x05rowid\x01\x07new-row\x0d\0\x09\x04\0\
-\x06update\x01\x12\x01@\x02\x03ctx\x0b\x05rowid\x01\0\x09\x04\0\x06delete\x01\x13\
-\x04\0\x0aend-modify\x01\x0c\x04\x01\x20supabase:wrappers/routines@0.1.0\x05\x0b\
-\x04\x01\x20supabase:paddle-fdw/paddle@0.1.0\x04\0\x0b\x0c\x01\0\x06paddle\x03\0\
-\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10wit-bi\
-ndgen-rust\x060.24.0";
+pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 3656] = *b"\
+\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xcb\x1b\x01A\x02\x01\
+A\x13\x01B\x16\x01o\x02ss\x01p\0\x04\0\x07headers\x03\0\x01\x01q\x05\x03get\0\0\x04\
+post\0\0\x03put\0\0\x05patch\0\0\x06delete\0\0\x04\0\x06method\x03\0\x03\x01r\x04\
+\x06method\x04\x03urls\x07headers\x02\x04bodys\x04\0\x07request\x03\0\x05\x01r\x04\
+\x03urls\x0bstatus-code{\x07headers\x02\x04bodys\x04\0\x08response\x03\0\x07\x01\
+s\x04\0\x0ahttp-error\x03\0\x09\x01j\x01\x08\x01\x0a\x04\0\x0bhttp-result\x03\0\x0b\
+\x01@\x01\x03req\x06\0\x0c\x04\0\x03get\x01\x0d\x04\0\x04post\x01\x0d\x04\0\x03p\
+ut\x01\x0d\x04\0\x05patch\x01\x0d\x04\0\x06delete\x01\x0d\x01j\0\x01\x0a\x01@\x01\
+\x04resp\x08\0\x0e\x04\0\x10error-for-status\x01\x0f\x03\x01\x1csupabase:wrapper\
+s/http@0.1.0\x05\0\x01B\x08\x01s\x04\0\x09jwt-error\x03\0\0\x01j\x01s\x01\x01\x04\
+\0\x0ajwt-result\x03\0\x02\x01o\x02ss\x01p\x04\x01@\x04\x07payload\x05\x04algos\x03\
+keys\x09ttl-hoursy\0\x03\x04\0\x06encode\x01\x06\x03\x01\x1bsupabase:wrappers/jw\
+t@0.1.0\x05\x01\x01B\x0a\x01ks\x04\0\x08metadata\x03\0\0\x01q\x05\x0ccreate-time\
+s\0\0\x07rows-in\0\0\x08rows-out\0\0\x08bytes-in\0\0\x09bytes-out\0\0\x04\0\x06m\
+etric\x03\0\x02\x01@\x03\x08fdw-names\x06metric\x03\x03incx\x01\0\x04\0\x09inc-s\
+tats\x01\x04\x01@\x01\x08fdw-names\0\x01\x04\0\x0cget-metadata\x01\x05\x01@\x02\x08\
+fdw-names\x08metadata\x01\x01\0\x04\0\x0cset-metadata\x01\x06\x03\x01\x1dsupabas\
+e:wrappers/stats@0.1.0\x05\x02\x01B\x0f\x01s\x04\0\x0atime-error\x03\0\0\x01j\x01\
+x\x01\x01\x04\0\x0btime-result\x03\0\x02\x01@\0\0x\x04\0\x0aepoch-secs\x01\x04\x01\
+@\x01\x01ss\0\x03\x04\0\x12parse-from-rfc3339\x01\x05\x01@\x02\x01ss\x03fmts\0\x03\
+\x04\0\x0eparse-from-str\x01\x06\x01j\x01s\x01\x01\x01@\x01\x05msecsx\0\x07\x04\0\
+\x13epoch-ms-to-rfc3339\x01\x08\x01@\x01\x06millisw\x01\0\x04\0\x05sleep\x01\x09\
+\x03\x01\x1csupabase:wrappers/time@0.1.0\x05\x03\x01Br\x01q\x0d\x04bool\0\0\x02i\
+8\0\0\x03i16\0\0\x03f32\0\0\x03i32\0\0\x03f64\0\0\x03i64\0\0\x07numeric\0\0\x06s\
+tring\0\0\x04date\0\0\x09timestamp\0\0\x0btimestamptz\0\0\x04json\0\0\x04\0\x08t\
+ype-oid\x03\0\0\x01q\x0d\x04bool\x01\x7f\0\x02i8\x01~\0\x03i16\x01|\0\x03f32\x01\
+v\0\x03i32\x01z\0\x03f64\x01u\0\x03i64\x01x\0\x07numeric\x01u\0\x06string\x01s\0\
+\x04date\x01x\0\x09timestamp\x01x\0\x0btimestamptz\x01x\0\x04json\x01s\0\x04\0\x04\
+cell\x03\0\x02\x04\0\x03row\x03\x01\x04\0\x06column\x03\x01\x01p\x03\x01q\x02\x04\
+cell\x01\x03\0\x05array\x01\x06\0\x04\0\x05value\x03\0\x07\x01r\x02\x02idy\x08ty\
+pe-oidy\x04\0\x05param\x03\0\x09\x04\0\x04qual\x03\x01\x04\0\x04sort\x03\x01\x04\
+\0\x05limit\x03\x01\x01q\x02\x06server\0\0\x05table\0\0\x04\0\x0coptions-type\x03\
+\0\x0e\x04\0\x07options\x03\x01\x04\0\x07context\x03\x01\x01s\x04\0\x09fdw-error\
+\x03\0\x12\x01j\0\x01\x13\x04\0\x0afdw-result\x03\0\x14\x01i\x04\x01@\0\0\x16\x04\
+\0\x10[constructor]row\x01\x17\x01h\x04\x01ps\x01@\x01\x04self\x18\0\x19\x04\0\x10\
+[method]row.cols\x01\x1a\x01k\x03\x01p\x1b\x01@\x01\x04self\x18\0\x1c\x04\0\x11[\
+method]row.cells\x01\x1d\x01@\x02\x04self\x18\x04cell\x1b\x01\0\x04\0\x10[method\
+]row.push\x01\x1e\x01i\x05\x01@\x01\x05indexy\0\x1f\x04\0\x13[constructor]column\
+\x01\x20\x01h\x05\x01@\x01\x04self!\0s\x04\0\x13[method]column.name\x01\"\x01@\x01\
+\x04self!\0y\x04\0\x12[method]column.num\x01#\x01@\x01\x04self!\0\x01\x04\0\x17[\
+method]column.type-oid\x01$\x01i\x0b\x01@\x01\x05indexy\0%\x04\0\x11[constructor\
+]qual\x01&\x01h\x0b\x01@\x01\x04self'\0s\x04\0\x12[method]qual.field\x01(\x04\0\x15\
+[method]qual.operator\x01(\x01@\x01\x04self'\0\x08\x04\0\x12[method]qual.value\x01\
+)\x01@\x01\x04self'\0\x7f\x04\0\x13[method]qual.use-or\x01*\x01k\x0a\x01@\x01\x04\
+self'\0+\x04\0\x12[method]qual.param\x01,\x04\0\x14[method]qual.deparse\x01(\x01\
+i\x0c\x01@\x01\x05indexy\0-\x04\0\x11[constructor]sort\x01.\x01h\x0c\x01@\x01\x04\
+self/\0s\x04\0\x12[method]sort.field\x010\x01@\x01\x04self/\0y\x04\0\x15[method]\
+sort.field-no\x011\x01@\x01\x04self/\0\x7f\x04\0\x15[method]sort.reversed\x012\x04\
+\0\x18[method]sort.nulls-first\x012\x01ks\x01@\x01\x04self/\03\x04\0\x14[method]\
+sort.collate\x014\x04\0\x14[method]sort.deparse\x010\x04\0![method]sort.deparse-\
+with-collate\x010\x01i\x0d\x01@\0\05\x04\0\x12[constructor]limit\x016\x01h\x0d\x01\
+@\x01\x04self7\0x\x04\0\x13[method]limit.count\x018\x04\0\x14[method]limit.offse\
+t\x018\x01@\x01\x04self7\0s\x04\0\x15[method]limit.deparse\x019\x01i\x10\x01@\x01\
+\x0coptions-type\x0f\0:\x04\0\x14[constructor]options\x01;\x01h\x10\x01@\x02\x04\
+self<\x03keys\03\x04\0\x13[method]options.get\x01=\x01j\x01s\x01\x13\x01@\x02\x04\
+self<\x03keys\0>\x04\0\x17[method]options.require\x01?\x01@\x03\x04self<\x03keys\
+\x07defaults\0s\x04\0\x1a[method]options.require-or\x01@\x01i\x11\x01@\0\0\xc1\0\
+\x04\0\x14[constructor]context\x01B\x01h\x11\x01@\x02\x04self\xc3\0\x0coptions-t\
+ype\x0f\0:\x04\0\x1b[method]context.get-options\x01D\x01p%\x01@\x01\x04self\xc3\0\
+\0\xc5\0\x04\0\x19[method]context.get-quals\x01F\x01p\x1f\x01@\x01\x04self\xc3\0\
+\0\xc7\0\x04\0\x1b[method]context.get-columns\x01H\x01p-\x01@\x01\x04self\xc3\0\0\
+\xc9\0\x04\0\x19[method]context.get-sorts\x01J\x01k5\x01@\x01\x04self\xc3\0\0\xcb\
+\0\x04\0\x19[method]context.get-limit\x01L\x03\x01\x1dsupabase:wrappers/types@0.\
+1.0\x05\x04\x02\x03\0\x04\x04cell\x01B\x0d\x02\x03\x02\x01\x05\x04\0\x04cell\x03\
+\0\0\x01@\x01\x03msgs\x01\0\x04\0\x0breport-info\x01\x02\x04\0\x0dreport-notice\x01\
+\x02\x04\0\x0ereport-warning\x01\x02\x04\0\x0creport-error\x01\x02\x01k\x01\x01@\
+\x01\x04cell\x03\0s\x04\0\x0ecell-to-string\x01\x04\x01ks\x01@\x01\x09secret-ids\
+\0\x05\x04\0\x10get-vault-secret\x01\x06\x03\x01\x1dsupabase:wrappers/utils@0.1.\
+0\x05\x06\x02\x03\0\x04\x03row\x02\x03\0\x04\x07context\x02\x03\0\x04\x09fdw-err\
+or\x02\x03\0\x04\x0afdw-result\x01B\x1f\x02\x03\x02\x01\x05\x04\0\x04cell\x03\0\0\
+\x02\x03\x02\x01\x07\x04\0\x03row\x03\0\x02\x02\x03\x02\x01\x08\x04\0\x07context\
+\x03\0\x04\x02\x03\x02\x01\x09\x04\0\x09fdw-error\x03\0\x06\x02\x03\x02\x01\x0a\x04\
+\0\x0afdw-result\x03\0\x08\x01@\0\0s\x04\0\x18host-version-requirement\x01\x0a\x01\
+h\x05\x01@\x01\x03ctx\x0b\0\x09\x04\0\x04init\x01\x0c\x04\0\x0abegin-scan\x01\x0c\
+\x01h\x03\x01ky\x01j\x01\x0e\x01\x07\x01@\x02\x03ctx\x0b\x03row\x0d\0\x0f\x04\0\x09\
+iter-scan\x01\x10\x04\0\x07re-scan\x01\x0c\x04\0\x08end-scan\x01\x0c\x04\0\x0cbe\
+gin-modify\x01\x0c\x01@\x02\x03ctx\x0b\x03row\x0d\0\x09\x04\0\x06insert\x01\x11\x01\
+@\x03\x03ctx\x0b\x05rowid\x01\x07new-row\x0d\0\x09\x04\0\x06update\x01\x12\x01@\x02\
+\x03ctx\x0b\x05rowid\x01\0\x09\x04\0\x06delete\x01\x13\x04\0\x0aend-modify\x01\x0c\
+\x04\x01\x20supabase:wrappers/routines@0.1.0\x05\x0b\x04\x01\x20supabase:paddle-\
+fdw/paddle@0.1.0\x04\0\x0b\x0c\x01\0\x06paddle\x03\0\0\0G\x09producers\x01\x0cpr\
+ocessed-by\x02\x0dwit-component\x070.202.0\x10wit-bindgen-rust\x060.24.0";
#[inline(never)]
#[doc(hidden)]
diff --git a/wasm-wrappers/fdw/paddle_fdw/src/lib.rs b/wasm-wrappers/fdw/paddle_fdw/src/lib.rs
index 044f5bfc..da266c9a 100644
--- a/wasm-wrappers/fdw/paddle_fdw/src/lib.rs
+++ b/wasm-wrappers/fdw/paddle_fdw/src/lib.rs
@@ -1,6 +1,6 @@
#[allow(warnings)]
mod bindings;
-use serde_json::{json, Value as JsonValue};
+use serde_json::{json, Map as JsonMap, Value as JsonValue};
use bindings::{
exports::supabase::wrappers::routines::Guest,
@@ -19,6 +19,7 @@ struct PaddleFdw {
object: String,
src_rows: Vec,
src_idx: usize,
+ rowid_col: String,
}
static mut INSTANCE: *mut PaddleFdw = std::ptr::null_mut::();
@@ -100,7 +101,7 @@ impl PaddleFdw {
return Ok(());
}
- http::error_for_status(&resp)?;
+ http::error_for_status(&resp).map_err(|err| format!("{}: {}", err, resp.body))?;
// save source rows
self.src_rows = resp_json
@@ -189,11 +190,38 @@ impl PaddleFdw {
None
}
}
- TypeOid::Json => src.as_str().map(|v| Cell::Json(v.to_owned())),
+ TypeOid::Json => src.as_object().map(|_| Cell::Json(src.to_string())),
};
Ok(cell)
}
+
+ // convert a row to JSON string, which is used as request body for row update
+ fn row_to_body(&self, row: &Row) -> Result {
+ let mut map = JsonMap::new();
+
+ for (col_name, cell) in row.cols().iter().zip(row.cells().iter()) {
+ if let Some(cell) = cell {
+ let value = match cell {
+ Cell::Bool(v) => JsonValue::Bool(*v),
+ Cell::I64(v) => JsonValue::String(v.to_string()),
+ Cell::String(v) => JsonValue::String(v.to_string()),
+ Cell::Date(v) => JsonValue::String(time::epoch_ms_to_rfc3339(v * 1_000_000)?),
+ Cell::Timestamp(v) => JsonValue::String(time::epoch_ms_to_rfc3339(*v)?),
+ Cell::Timestamptz(v) => JsonValue::String(time::epoch_ms_to_rfc3339(*v)?),
+ Cell::Json(v) => {
+ serde_json::from_str::(v).map_err(|e| e.to_string())?
+ }
+ _ => {
+ return Err(format!("column '{}' type is not supported", col_name));
+ }
+ };
+ map.insert(col_name.to_owned(), value);
+ }
+ }
+
+ Ok(JsonValue::Object(map).to_string())
+ }
}
impl Guest for PaddleFdw {
@@ -283,24 +311,56 @@ impl Guest for PaddleFdw {
Ok(())
}
- fn begin_modify(_ctx: &Context) -> FdwResult {
- unimplemented!("update on foreign table is not supported");
+ fn begin_modify(ctx: &Context) -> FdwResult {
+ let this = Self::this_mut();
+ let opts = ctx.get_options(OptionsType::Table);
+ this.object = opts.require("object")?;
+ this.rowid_col = opts.require("rowid_column")?;
+ Ok(())
}
- fn insert(_ctx: &Context, _row: &Row) -> FdwResult {
- unimplemented!("update on foreign table is not supported");
+ fn insert(_ctx: &Context, row: &Row) -> FdwResult {
+ let this = Self::this_mut();
+ let url = format!("{}/{}", this.base_url, this.object);
+ let body = this.row_to_body(row)?;
+ let req = http::Request {
+ method: http::Method::Post,
+ url,
+ headers: this.headers.clone(),
+ body,
+ };
+ let resp = http::post(&req)?;
+ http::error_for_status(&resp).map_err(|err| format!("{}: {}", err, resp.body))?;
+ stats::inc_stats(FDW_NAME, stats::Metric::RowsOut, 1);
+ Ok(())
}
- fn update(_ctx: &Context, _rowid: Cell, _row: &Row) -> FdwResult {
- unimplemented!("update on foreign table is not supported");
+ fn update(_ctx: &Context, rowid: Cell, row: &Row) -> FdwResult {
+ let this = Self::this_mut();
+ let id = match rowid {
+ Cell::String(s) => s.clone(),
+ _ => return Err("invalid rowid column value".to_string()),
+ };
+ let url = format!("{}/{}/{}", this.base_url, this.object, id);
+ let body = this.row_to_body(row)?;
+ let req = http::Request {
+ method: http::Method::Patch,
+ url,
+ headers: this.headers.clone(),
+ body,
+ };
+ let resp = http::patch(&req)?;
+ http::error_for_status(&resp).map_err(|err| format!("{}: {}", err, resp.body))?;
+ stats::inc_stats(FDW_NAME, stats::Metric::RowsOut, 1);
+ Ok(())
}
fn delete(_ctx: &Context, _rowid: Cell) -> FdwResult {
- unimplemented!("update on foreign table is not supported");
+ unimplemented!("delete on foreign table is not supported");
}
fn end_modify(_ctx: &Context) -> FdwResult {
- unimplemented!("update on foreign table is not supported");
+ Ok(())
}
}
diff --git a/wasm-wrappers/wit/http.wit b/wasm-wrappers/wit/http.wit
index 974c88df..afd8bebe 100644
--- a/wasm-wrappers/wit/http.wit
+++ b/wasm-wrappers/wit/http.wit
@@ -4,6 +4,9 @@ interface http {
variant method {
get,
post,
+ put,
+ patch,
+ delete,
}
record request {
@@ -26,6 +29,7 @@ interface http {
get: func(req: request) -> http-result;
post: func(req: request) -> http-result;
put: func(req: request) -> http-result;
+ patch: func(req: request) -> http-result;
delete: func(req: request) -> http-result;
error-for-status: func(resp: response) -> result<_, http-error>;
diff --git a/wasm-wrappers/wit/time.wit b/wasm-wrappers/wit/time.wit
index 7ba9249c..4200f4f8 100644
--- a/wasm-wrappers/wit/time.wit
+++ b/wasm-wrappers/wit/time.wit
@@ -11,6 +11,9 @@ interface time {
// parse string from an user-specified format to microseconds since Unix epoch
parse-from-str: func(s: string, fmt: string) -> time-result;
+ // convert microseconds since Unix epoch to RFC3339 string
+ epoch-ms-to-rfc3339: func(msecs: s64) -> result;
+
// sleep for a while
sleep: func(millis: u64);
}
diff --git a/wrappers/src/fdw/wasm_fdw/host/http.rs b/wrappers/src/fdw/wasm_fdw/host/http.rs
index 7e174140..e33b57bd 100644
--- a/wrappers/src/fdw/wasm_fdw/host/http.rs
+++ b/wrappers/src/fdw/wasm_fdw/host/http.rs
@@ -48,6 +48,27 @@ fn create_client(req: &http::Request) -> Result {
}
impl FdwHost {
+ // make a http request
+ fn http_request(&mut self, req: http::Request) -> http::HttpResult {
+ supabase_wrappers::prelude::report_info(&format!("req: {:?}", req));
+ let client = create_client(&req)?;
+ let resp = self
+ .rt
+ .block_on(
+ match req.method {
+ http::Method::Get => client.get(req.url),
+ http::Method::Post => client.post(req.url),
+ http::Method::Put => client.put(req.url),
+ http::Method::Patch => client.patch(req.url),
+ http::Method::Delete => client.delete(req.url),
+ }
+ .body(req.body)
+ .send(),
+ )
+ .map_err(|e| e.to_string())?;
+ self.convert_to_guest_response(resp)
+ }
+
// convert reqwest response to guest response
fn convert_to_guest_response(&mut self, resp: Response) -> http::HttpResult {
let url = resp.url().to_string();
@@ -64,40 +85,29 @@ impl FdwHost {
}
impl http::Host for FdwHost {
+ #[inline]
fn get(&mut self, req: http::Request) -> http::HttpResult {
- let client = create_client(&req)?;
- let resp = self
- .rt
- .block_on(client.get(req.url).send())
- .map_err(|e| e.to_string())?;
- self.convert_to_guest_response(resp)
+ self.http_request(req)
}
+ #[inline]
fn post(&mut self, req: http::Request) -> http::HttpResult {
- let client = create_client(&req)?;
- let resp = self
- .rt
- .block_on(client.post(req.url).body(req.body).send())
- .map_err(|e| e.to_string())?;
- self.convert_to_guest_response(resp)
+ self.http_request(req)
}
+ #[inline]
fn put(&mut self, req: http::Request) -> http::HttpResult {
- let client = create_client(&req)?;
- let resp = self
- .rt
- .block_on(client.put(req.url).body(req.body).send())
- .map_err(|e| e.to_string())?;
- self.convert_to_guest_response(resp)
+ self.http_request(req)
}
+ #[inline]
+ fn patch(&mut self, req: http::Request) -> http::HttpResult {
+ self.http_request(req)
+ }
+
+ #[inline]
fn delete(&mut self, req: http::Request) -> http::HttpResult {
- let client = create_client(&req)?;
- let resp = self
- .rt
- .block_on(client.delete(req.url).send())
- .map_err(|e| e.to_string())?;
- self.convert_to_guest_response(resp)
+ self.http_request(req)
}
fn error_for_status(&mut self, resp: http::Response) -> Result<(), http::HttpError> {
diff --git a/wrappers/src/fdw/wasm_fdw/host/time.rs b/wrappers/src/fdw/wasm_fdw/host/time.rs
index 9f0cc0fd..d37e4106 100644
--- a/wrappers/src/fdw/wasm_fdw/host/time.rs
+++ b/wrappers/src/fdw/wasm_fdw/host/time.rs
@@ -24,6 +24,12 @@ impl time::Host for FdwHost {
.map_err(|e| e.to_string())
}
+ fn epoch_ms_to_rfc3339(&mut self, msecs: i64) -> Result {
+ DateTime::from_timestamp_micros(msecs)
+ .map(|ts| ts.to_rfc3339())
+ .ok_or("invalid microseconds since Unix Epoch".to_string())
+ }
+
fn sleep(&mut self, millis: u64) {
std::thread::sleep(std::time::Duration::from_millis(millis));
}