Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: mysql fixes in WASM plugin
Browse files Browse the repository at this point in the history
worstell committed Jan 7, 2025
1 parent bb68bd8 commit 63690ea
Showing 17 changed files with 2,111 additions and 78 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ jobs:
- name: Build Cache
uses: ./.github/actions/build-cache
- name: Test WASM
run: cd sqlc-gen-ftl && cargo test --features ci --test sqlc_gen_ftl_test -- --nocapture
run: just test-sqlc-gen-ftl
- name: Check for uncommitted changes
run: |
if [[ -n $(git status -s) ]]; then
3 changes: 3 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -199,6 +199,9 @@ build-sqlc-gen-ftl: build-rust-protos
"cd sqlc-gen-ftl && \
cargo build --target wasm32-wasip1 --release"

test-sqlc-gen-ftl:
@cargo test --manifest-path sqlc-gen-ftl/Cargo.toml --features ci --test sqlc_gen_ftl_test -- --nocapture

# Generate Rust protos
build-rust-protos:
@mk sqlc-gen-ftl/src/protos : backend/protos -- \
174 changes: 174 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.console.v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Config {
#[prost(message, optional, tag="1")]
pub config: ::core::option::Option<super::super::schema::v1::Config>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Data {
#[prost(message, optional, tag="1")]
pub data: ::core::option::Option<super::super::schema::v1::Data>,
#[prost(string, tag="2")]
pub schema: ::prost::alloc::string::String,
#[prost(message, repeated, tag="3")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Database {
#[prost(message, optional, tag="1")]
pub database: ::core::option::Option<super::super::schema::v1::Database>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Enum {
#[prost(message, optional, tag="1")]
pub r#enum: ::core::option::Option<super::super::schema::v1::Enum>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Topic {
#[prost(message, optional, tag="1")]
pub topic: ::core::option::Option<super::super::schema::v1::Topic>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TypeAlias {
#[prost(message, optional, tag="1")]
pub typealias: ::core::option::Option<super::super::schema::v1::TypeAlias>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Secret {
#[prost(message, optional, tag="1")]
pub secret: ::core::option::Option<super::super::schema::v1::Secret>,
#[prost(message, repeated, tag="2")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Verb {
#[prost(message, optional, tag="1")]
pub verb: ::core::option::Option<super::super::schema::v1::Verb>,
#[prost(string, tag="2")]
pub schema: ::prost::alloc::string::String,
#[prost(string, tag="3")]
pub json_request_schema: ::prost::alloc::string::String,
#[prost(message, repeated, tag="4")]
pub references: ::prost::alloc::vec::Vec<super::super::schema::v1::Ref>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Module {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(string, tag="2")]
pub deployment_key: ::prost::alloc::string::String,
#[prost(string, tag="3")]
pub language: ::prost::alloc::string::String,
#[prost(string, tag="4")]
pub schema: ::prost::alloc::string::String,
#[prost(message, repeated, tag="5")]
pub verbs: ::prost::alloc::vec::Vec<Verb>,
#[prost(message, repeated, tag="6")]
pub data: ::prost::alloc::vec::Vec<Data>,
#[prost(message, repeated, tag="7")]
pub secrets: ::prost::alloc::vec::Vec<Secret>,
#[prost(message, repeated, tag="8")]
pub configs: ::prost::alloc::vec::Vec<Config>,
#[prost(message, repeated, tag="9")]
pub databases: ::prost::alloc::vec::Vec<Database>,
#[prost(message, repeated, tag="10")]
pub enums: ::prost::alloc::vec::Vec<Enum>,
#[prost(message, repeated, tag="11")]
pub topics: ::prost::alloc::vec::Vec<Topic>,
#[prost(message, repeated, tag="12")]
pub typealiases: ::prost::alloc::vec::Vec<TypeAlias>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TopologyGroup {
#[prost(string, repeated, tag="1")]
pub modules: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Topology {
#[prost(message, repeated, tag="1")]
pub levels: ::prost::alloc::vec::Vec<TopologyGroup>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct GetModulesRequest {
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetModulesResponse {
#[prost(message, repeated, tag="1")]
pub modules: ::prost::alloc::vec::Vec<Module>,
#[prost(message, optional, tag="2")]
pub topology: ::core::option::Option<Topology>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct StreamModulesRequest {
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StreamModulesResponse {
#[prost(message, repeated, tag="1")]
pub modules: ::prost::alloc::vec::Vec<Module>,
#[prost(message, optional, tag="2")]
pub topology: ::core::option::Option<Topology>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetConfigRequest {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(string, optional, tag="2")]
pub module: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetConfigResponse {
#[prost(bytes="bytes", tag="1")]
pub value: ::prost::bytes::Bytes,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SetConfigRequest {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(string, optional, tag="2")]
pub module: ::core::option::Option<::prost::alloc::string::String>,
#[prost(bytes="bytes", tag="3")]
pub value: ::prost::bytes::Bytes,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SetConfigResponse {
#[prost(bytes="bytes", tag="1")]
pub value: ::prost::bytes::Bytes,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetSecretRequest {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(string, optional, tag="2")]
pub module: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetSecretResponse {
#[prost(bytes="bytes", tag="1")]
pub value: ::prost::bytes::Bytes,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SetSecretRequest {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(string, optional, tag="2")]
pub module: ::core::option::Option<::prost::alloc::string::String>,
#[prost(bytes="bytes", tag="3")]
pub value: ::prost::bytes::Bytes,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SetSecretResponse {
#[prost(bytes="bytes", tag="1")]
pub value: ::prost::bytes::Bytes,
}
// @@protoc_insertion_point(module)
71 changes: 71 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.deployment.v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetDeploymentContextRequest {
#[prost(string, tag="1")]
pub deployment: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetDeploymentContextResponse {
#[prost(string, tag="1")]
pub module: ::prost::alloc::string::String,
#[prost(string, tag="2")]
pub deployment: ::prost::alloc::string::String,
#[prost(map="string, bytes", tag="3")]
pub configs: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::bytes::Bytes>,
#[prost(map="string, bytes", tag="4")]
pub secrets: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::bytes::Bytes>,
#[prost(message, repeated, tag="5")]
pub databases: ::prost::alloc::vec::Vec<get_deployment_context_response::Dsn>,
#[prost(message, repeated, tag="6")]
pub routes: ::prost::alloc::vec::Vec<get_deployment_context_response::Route>,
}
/// Nested message and enum types in `GetDeploymentContextResponse`.
pub mod get_deployment_context_response {
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Dsn {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
#[prost(enumeration="DbType", tag="2")]
pub r#type: i32,
#[prost(string, tag="3")]
pub dsn: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Route {
#[prost(string, tag="1")]
pub deployment: ::prost::alloc::string::String,
#[prost(string, tag="2")]
pub uri: ::prost::alloc::string::String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum DbType {
Unspecified = 0,
Postgres = 1,
Mysql = 2,
}
impl DbType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "DB_TYPE_UNSPECIFIED",
Self::Postgres => "DB_TYPE_POSTGRES",
Self::Mysql => "DB_TYPE_MYSQL",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"DB_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
"DB_TYPE_POSTGRES" => Some(Self::Postgres),
"DB_TYPE_MYSQL" => Some(Self::Mysql),
_ => None,
}
}
}
}
// @@protoc_insertion_point(module)
408 changes: 408 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.language.v1.rs

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.lease.v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AcquireLeaseRequest {
#[prost(string, repeated, tag="1")]
pub key: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
#[prost(message, optional, tag="3")]
pub ttl: ::core::option::Option<::prost_types::Duration>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct AcquireLeaseResponse {
}
// @@protoc_insertion_point(module)
105 changes: 105 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.provisioner.v1beta1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProvisionRequest {
#[prost(string, tag="1")]
pub ftl_cluster_id: ::prost::alloc::string::String,
#[prost(message, optional, tag="2")]
pub desired_module: ::core::option::Option<super::super::schema::v1::Module>,
#[prost(message, optional, tag="3")]
pub previous_module: ::core::option::Option<super::super::schema::v1::Module>,
#[prost(string, repeated, tag="4")]
pub kinds: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProvisionResponse {
#[prost(string, tag="1")]
pub provisioning_token: ::prost::alloc::string::String,
#[prost(enumeration="provision_response::ProvisionResponseStatus", tag="2")]
pub status: i32,
}
/// Nested message and enum types in `ProvisionResponse`.
pub mod provision_response {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ProvisionResponseStatus {
Unspecified = 0,
Submitted = 1,
}
impl ProvisionResponseStatus {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "PROVISION_RESPONSE_STATUS_UNSPECIFIED",
Self::Submitted => "PROVISION_RESPONSE_STATUS_SUBMITTED",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"PROVISION_RESPONSE_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
"PROVISION_RESPONSE_STATUS_SUBMITTED" => Some(Self::Submitted),
_ => None,
}
}
}
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StatusRequest {
#[prost(string, tag="1")]
pub provisioning_token: ::prost::alloc::string::String,
/// The outputs of this module are updated if the the status is a success
#[prost(message, optional, tag="2")]
pub desired_module: ::core::option::Option<super::super::schema::v1::Module>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProvisioningEvent {
#[prost(oneof="provisioning_event::Value", tags="1, 2, 3, 4")]
pub value: ::core::option::Option<provisioning_event::Value>,
}
/// Nested message and enum types in `ProvisioningEvent`.
pub mod provisioning_event {
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Value {
#[prost(message, tag="1")]
ModuleRuntimeEvent(super::super::super::schema::v1::ModuleRuntimeEvent),
#[prost(message, tag="2")]
DatabaseRuntimeEvent(super::super::super::schema::v1::DatabaseRuntimeEvent),
#[prost(message, tag="3")]
TopicRuntimeEvent(super::super::super::schema::v1::TopicRuntimeEvent),
#[prost(message, tag="4")]
VerbRuntimeEvent(super::super::super::schema::v1::VerbRuntimeEvent),
}
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StatusResponse {
#[prost(oneof="status_response::Status", tags="1, 2")]
pub status: ::core::option::Option<status_response::Status>,
}
/// Nested message and enum types in `StatusResponse`.
pub mod status_response {
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct ProvisioningRunning {
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProvisioningFailed {
#[prost(string, tag="1")]
pub error_message: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProvisioningSuccess {
#[prost(message, repeated, tag="1")]
pub events: ::prost::alloc::vec::Vec<super::ProvisioningEvent>,
}
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Status {
#[prost(message, tag="1")]
Running(ProvisioningRunning),
#[prost(message, tag="2")]
Success(ProvisioningSuccess),
}
}
// @@protoc_insertion_point(module)
18 changes: 18 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.publish.v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PublishEventRequest {
#[prost(message, optional, tag="1")]
pub topic: ::core::option::Option<super::super::schema::v1::Ref>,
#[prost(bytes="bytes", tag="2")]
pub body: ::prost::bytes::Bytes,
#[prost(string, tag="3")]
pub key: ::prost::alloc::string::String,
/// Only verb name is included because this verb will be in the same module as topic
#[prost(string, tag="4")]
pub caller: ::prost::alloc::string::String,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct PublishEventResponse {
}
// @@protoc_insertion_point(module)
15 changes: 15 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.raft.v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @generated
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AddMemberRequest {
#[prost(string, tag="1")]
pub address: ::prost::alloc::string::String,
#[prost(uint64, tag="2")]
pub replica_id: u64,
#[prost(uint64, repeated, tag="3")]
pub shard_ids: ::prost::alloc::vec::Vec<u64>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct AddMemberResponse {
}
// @@protoc_insertion_point(module)
534 changes: 534 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.timeline.v1.rs

Large diffs are not rendered by default.

547 changes: 547 additions & 0 deletions backend/protos/src/protos/xyz.block.ftl.v1.rs

Large diffs are not rendered by default.

33 changes: 25 additions & 8 deletions sqlc-gen-ftl/src/plugin/mod.rs
Original file line number Diff line number Diff line change
@@ -57,13 +57,19 @@ fn to_verb(query: &pluginpb::Query, module_name: &str) -> schemapb::Decl {
let request_type = if !query.params.is_empty() {
Some(to_schema_ref(module_name, &format!("{}Query", query.name)))
} else {
None
Some(to_schema_unit())
};

let response_type = if query.cmd == ":exec" {
None
} else {
Some(to_schema_ref(module_name, &format!("{}Result", query.name)))
let response_type = match query.cmd.as_str() {
":exec" => Some(to_schema_unit()),
":one" => Some(to_schema_ref(module_name, &format!("{}Result", query.name))),
":many" => Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Array(Box::new(schemapb::Array {
pos: None,
element: Some(Box::new(to_schema_ref(module_name, &format!("{}Result", query.name)))),
}))),
}),
_ => Some(to_schema_unit()),
};

schemapb::Decl {
@@ -87,9 +93,12 @@ fn to_verb_request(query: &pluginpb::Query) -> schemapb::Decl {
export: false,
type_parameters: Vec::new(),
fields: query.params.iter().map(|param| {
let name = param.column.as_ref()
.map(|col| col.name.clone())
.unwrap_or_else(|| format!("param{}", param.number));
let name = if let Some(col) = &param.column {
col.name.clone()
} else {
format!("arg{}", param.number)
};

let sql_type = param.column.as_ref().and_then(|col| col.r#type.as_ref());
to_schema_field(name, sql_type)
}).collect(),
@@ -142,6 +151,14 @@ fn to_schema_ref(module_name: &str, name: &str) -> schemapb::Type {
}
}

fn to_schema_unit() -> schemapb::Type {
schemapb::Type {
value: Some(schemapb::r#type::Value::Unit(schemapb::Unit {
pos: None,
}))
}
}

fn to_schema_type(sql_type: &pluginpb::Identifier) -> schemapb::Type {
let value = match sql_type.name.as_str() {
"integer" | "bigint" | "smallint" | "serial" | "bigserial" =>
220 changes: 151 additions & 69 deletions sqlc-gen-ftl/test/sqlc_gen_ftl_test.rs
Original file line number Diff line number Diff line change
@@ -40,9 +40,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "id".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Int(schemapb::Int {
pos: None,
}))
value: Some(schemapb::r#type::Value::Int(schemapb::Int { pos: None }))
}),
pos: None,
comments: vec![],
@@ -63,9 +61,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "id".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Int(schemapb::Int {
pos: None,
}))
value: Some(schemapb::r#type::Value::Int(schemapb::Int { pos: None }))
}),
pos: None,
comments: vec![],
@@ -74,9 +70,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "name".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String {
pos: None,
}))
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
@@ -85,9 +79,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "email".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String {
pos: None,
}))
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
@@ -134,9 +126,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "name".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String {
pos: None,
}))
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
@@ -145,9 +135,7 @@ fn expected_module_schema() -> schemapb::Module {
schemapb::Field {
name: "email".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String {
pos: None,
}))
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
@@ -172,7 +160,98 @@ fn expected_module_schema() -> schemapb::Module {
type_parameters: vec![],
}))
}),
response: None,
response: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Unit(schemapb::Unit { pos: None }))
}),
pos: None,
comments: vec![],
metadata: vec![],
})),
},
schemapb::Decl {
value: Some(schemapb::decl::Value::Data(schemapb::Data {
name: "GetRequestDataResult".to_string(),
export: false,
type_parameters: vec![],
fields: vec![
schemapb::Field {
name: "data".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
metadata: vec![],
}
],
pos: None,
comments: vec![],
metadata: vec![],
})),
},
schemapb::Decl {
value: Some(schemapb::decl::Value::Verb(schemapb::Verb {
name: "GetRequestData".to_string(),
export: false,
runtime: None,
request: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Unit(schemapb::Unit { pos: None }))
}),
response: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Array(Box::new(schemapb::Array {
pos: None,
element: Some(Box::new(schemapb::Type {
value: Some(schemapb::r#type::Value::Ref(schemapb::Ref {
module: "echo".to_string(),
name: "GetRequestDataResult".to_string(),
pos: None,
type_parameters: vec![],
}))
})),
})))
}),
pos: None,
comments: vec![],
metadata: vec![],
})),
},
schemapb::Decl {
value: Some(schemapb::decl::Value::Data(schemapb::Data {
name: "CreateRequestQuery".to_string(),
export: false,
type_parameters: vec![],
fields: vec![
schemapb::Field {
name: "data".to_string(),
r#type: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::String(schemapb::String { pos: None }))
}),
pos: None,
comments: vec![],
metadata: vec![],
}
],
pos: None,
comments: vec![],
metadata: vec![],
})),
},
schemapb::Decl {
value: Some(schemapb::decl::Value::Verb(schemapb::Verb {
name: "CreateRequest".to_string(),
export: false,
runtime: None,
request: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Ref(schemapb::Ref {
module: "echo".to_string(),
name: "CreateRequestQuery".to_string(),
pos: None,
type_parameters: vec![],
}))
}),
response: Some(schemapb::Type {
value: Some(schemapb::r#type::Value::Unit(schemapb::Unit { pos: None }))
}),
pos: None,
comments: vec![],
metadata: vec![],
@@ -182,7 +261,7 @@ fn expected_module_schema() -> schemapb::Module {
}
}

fn get_sqlc_config(wasm_path: &PathBuf) -> Result<String, Box<dyn std::error::Error>> {
fn get_sqlc_config(wasm_path: &PathBuf, engine: &str) -> Result<String, Box<dyn std::error::Error>> {
let wasm_contents = fs::read(wasm_path)?;
let mut hasher = Sha256::new();
hasher.update(&wasm_contents);
@@ -198,13 +277,14 @@ plugins:
sql:
- schema: schema.sql
queries: queries.sql
engine: postgresql
engine: {}
codegen:
- out: gen
plugin: ftl
options:
module: echo"#,
sha256_hash,
engine,
))
}

@@ -219,59 +299,61 @@ mod tests {
return Err(format!("Failed to build WASM: {}", e).into());
}

let temp_dir = TempDir::new()?;
let gen_dir = temp_dir.path().join("gen");
std::fs::create_dir(&gen_dir)?;

let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let test_dir = root_dir.join("test");
let wasm_path = temp_dir.path().join("sqlc-gen-ftl.wasm");
for engine in ["mysql", "postgresql"] {
let temp_dir = TempDir::new()?;
let gen_dir = temp_dir.path().join("gen");
std::fs::create_dir(&gen_dir)?;

let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let test_dir = root_dir.join("test");
let wasm_path = temp_dir.path().join("sqlc-gen-ftl.wasm");

std::fs::copy(
test_dir.join("testdata/schema.sql"),
temp_dir.path().join("schema.sql")
)?;
std::fs::copy(
test_dir.join("testdata/queries.sql"),
temp_dir.path().join("queries.sql")
)?;
std::fs::copy(
root_dir.join("target/wasm32-wasip1/release/sqlc-gen-ftl.wasm"),
&wasm_path
)?;

let config_contents = get_sqlc_config(&wasm_path)?;
let config_path = temp_dir.path().join("sqlc.yaml");
std::fs::write(&config_path, config_contents)?;
std::fs::copy(
test_dir.join(format!("testdata/{}/schema.sql", engine)),
temp_dir.path().join("schema.sql")
)?;
std::fs::copy(
test_dir.join(format!("testdata/{}/queries.sql", engine)),
temp_dir.path().join("queries.sql")
)?;
std::fs::copy(
root_dir.join("target/wasm32-wasip1/release/sqlc-gen-ftl.wasm"),
&wasm_path
)?;
let config_contents = get_sqlc_config(&wasm_path, engine)?;
let config_path = temp_dir.path().join("sqlc.yaml");
std::fs::write(&config_path, config_contents)?;

let output = Command::new("sqlc")
.arg("generate")
.arg("--file")
.arg(&config_path)
.current_dir(temp_dir.path())
.env("SQLC_VERSION", "dev")
.env("SQLCDEBUG", "true")
.output()?;
let output = Command::new("sqlc-dev")
.arg("generate")
.arg("--file")
.arg(&config_path)
.current_dir(temp_dir.path())
.output()?;

if !output.status.success() {
return Err(format!(
"sqlc generate failed with status: {}\nstderr: {}",
output.status,
String::from_utf8_lossy(&output.stderr)
).into());
}
if !output.status.success() {
return Err(format!(
"sqlc generate failed for {} with status: {}\nstderr: {}",
engine,
output.status,
String::from_utf8_lossy(&output.stderr)
).into());
}

let pb_contents = std::fs::read(gen_dir.join("queries.pb"))?;
let actual_module = schemapb::Module::decode(&*pb_contents)?;
let expected_module = expected_module_schema();
let pb_contents = std::fs::read(gen_dir.join("queries.pb"))?;
let actual_module = schemapb::Module::decode(&*pb_contents)?;
let expected_module = expected_module_schema();

assert_eq!(
&actual_module,
&expected_module,
"Schema mismatch.\nActual: {:#?}\nExpected: {:#?}",
actual_module,
expected_module
);
assert_eq!(
&actual_module,
&expected_module,
"Schema mismatch for {}.\nActual: {:#?}\nExpected: {:#?}",
engine,
actual_module,
expected_module
);
}

Ok(())
}
12 changes: 12 additions & 0 deletions sqlc-gen-ftl/test/testdata/mysql/queries.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- name: GetUserByID :one
SELECT id, name, email FROM users WHERE id = ?;

-- name: CreateUser :exec
INSERT INTO users (name, email) VALUES (?, ?);

-- name: GetRequestData :many
SELECT data FROM requests;

-- name: CreateRequest :exec
INSERT INTO requests (data) VALUES (?);

11 changes: 11 additions & 0 deletions sqlc-gen-ftl/test/testdata/mysql/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT
);

CREATE TABLE requests
(
data TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
12 changes: 12 additions & 0 deletions sqlc-gen-ftl/test/testdata/postgresql/queries.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- name: GetUserByID :one
SELECT id, name, email FROM users WHERE id = $1;

-- name: CreateUser :exec
INSERT INTO users (name, email) VALUES ($1, $2);

-- name: GetRequestData :many
SELECT data FROM requests;

-- name: CreateRequest :exec
INSERT INTO requests (data) VALUES ($1);

11 changes: 11 additions & 0 deletions sqlc-gen-ftl/test/testdata/postgresql/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT
);

CREATE TABLE requests
(
data TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

0 comments on commit 63690ea

Please sign in to comment.