mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
9e9d5cd615
commit
68b4e2052c
@ -586,6 +586,101 @@ var _ = Describe("Generator", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GenerateClientGo", func() {
|
||||
It("should include errors import when service has methods with errors", func() {
|
||||
svc := Service{
|
||||
Name: "Cache",
|
||||
Permission: "cache",
|
||||
Interface: "CacheService",
|
||||
Methods: []Method{
|
||||
{
|
||||
Name: "Get",
|
||||
HasError: true,
|
||||
Params: []Param{NewParam("key", "string")},
|
||||
Returns: []Param{NewParam("value", "string")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
code, err := GenerateClientGo(svc, "host")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Verify the code is valid Go (can't actually compile without wasip1)
|
||||
codeStr := string(code)
|
||||
|
||||
// Check for errors import when methods have errors
|
||||
Expect(codeStr).To(ContainSubstring(`"errors"`))
|
||||
Expect(codeStr).To(ContainSubstring("errors.New"))
|
||||
})
|
||||
|
||||
It("should not include errors import when service has no methods with errors", func() {
|
||||
svc := Service{
|
||||
Name: "Config",
|
||||
Permission: "config",
|
||||
Interface: "ConfigService",
|
||||
Methods: []Method{
|
||||
{
|
||||
Name: "Get",
|
||||
HasError: false,
|
||||
Params: []Param{NewParam("key", "string")},
|
||||
Returns: []Param{NewParam("value", "string"), NewParam("exists", "bool")},
|
||||
},
|
||||
{
|
||||
Name: "List",
|
||||
HasError: false,
|
||||
Params: []Param{NewParam("prefix", "string")},
|
||||
Returns: []Param{NewParam("keys", "[]string")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
code, err := GenerateClientGo(svc, "host")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
codeStr := string(code)
|
||||
|
||||
// Check that errors is NOT imported when no methods have errors
|
||||
Expect(codeStr).NotTo(ContainSubstring(`"errors"`))
|
||||
Expect(codeStr).NotTo(ContainSubstring("errors.New"))
|
||||
})
|
||||
|
||||
It("should generate valid Go code structure", func() {
|
||||
svc := Service{
|
||||
Name: "SubsonicAPI",
|
||||
Permission: "subsonicapi",
|
||||
Interface: "SubsonicAPIService",
|
||||
Methods: []Method{
|
||||
{
|
||||
Name: "Call",
|
||||
HasError: true,
|
||||
Params: []Param{NewParam("uri", "string")},
|
||||
Returns: []Param{NewParam("response", "string")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
code, err := GenerateClientGo(svc, "host")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
codeStr := string(code)
|
||||
|
||||
// Check for generated header
|
||||
Expect(codeStr).To(ContainSubstring("Code generated by ndpgen. DO NOT EDIT."))
|
||||
|
||||
// Check for build tag
|
||||
Expect(codeStr).To(ContainSubstring("//go:build wasip1"))
|
||||
|
||||
// Check for package declaration
|
||||
Expect(codeStr).To(ContainSubstring("package host"))
|
||||
|
||||
// Check for wasmimport directive
|
||||
Expect(codeStr).To(ContainSubstring("//go:wasmimport extism:host/user"))
|
||||
|
||||
// Check for PDK import
|
||||
Expect(codeStr).To(ContainSubstring("github.com/navidrome/navidrome/plugins/pdk/go/pdk"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GenerateClientGoStub", func() {
|
||||
It("should generate valid mock code with testify/mock", func() {
|
||||
svc := Service{
|
||||
|
||||
@ -9,7 +9,9 @@ package {{.Package}}
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
{{- if .Service.HasErrors}}
|
||||
"errors"
|
||||
{{- end}}
|
||||
|
||||
"github.com/navidrome/navidrome/plugins/pdk/go/pdk"
|
||||
)
|
||||
@ -53,7 +55,9 @@ type {{responseType .}} struct {
|
||||
{{- range .Returns}}
|
||||
{{title .Name}} {{.Type}} `json:"{{.JSONName}},omitempty"`
|
||||
{{- end}}
|
||||
{{- if .HasError}}
|
||||
Error string `json:"error,omitempty"`
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
@ -80,10 +80,11 @@ def {{pythonFunc .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{$p.PythonNam
|
||||
response_offset = _{{exportName .}}(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
{{if .HasError}}
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
{{if .NeedsResultClass}}
|
||||
{{end}}
|
||||
{{- if .NeedsResultClass}}
|
||||
return {{pythonResultType .}}(
|
||||
{{- range .Returns}}
|
||||
{{.PythonName}}=response.get("{{.JSONName}}"{{pythonDefault .}}),
|
||||
|
||||
@ -41,8 +41,10 @@ struct {{responseType .}} {
|
||||
#[serde(default)]
|
||||
{{.RustName}}: {{rustType .}},
|
||||
{{- end}}
|
||||
{{- if .HasError}}
|
||||
#[serde(default)]
|
||||
error: Option<String>,
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
@ -88,11 +90,12 @@ pub fn {{rustFunc .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{$p.RustName
|
||||
{{exportName .}}(Json(serde_json::json!({})))?
|
||||
{{- end}}
|
||||
};
|
||||
|
||||
{{if .HasError}}
|
||||
if let Some(err) = response.0.error {
|
||||
return Err(Error::msg(err));
|
||||
}
|
||||
{{if eq (len .Returns) 0}}
|
||||
{{end}}
|
||||
{{- if eq (len .Returns) 0}}
|
||||
Ok(())
|
||||
{{- else if eq (len .Returns) 1}}
|
||||
Ok(response.0.{{(index .Returns 0).RustName}})
|
||||
|
||||
@ -26,7 +26,9 @@ type {{responseType .}} struct {
|
||||
{{- range .Returns}}
|
||||
{{title .Name}} {{.Type}} `json:"{{.JSONName}},omitempty"`
|
||||
{{- end}}
|
||||
{{- if .HasError}}
|
||||
Error string `json:"error,omitempty"`
|
||||
{{- end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
|
||||
@ -163,6 +163,16 @@ func (s Service) KnownStructs() map[string]bool {
|
||||
return result
|
||||
}
|
||||
|
||||
// HasErrors returns true if any method in the service returns an error.
|
||||
func (s Service) HasErrors() bool {
|
||||
for _, m := range s.Methods {
|
||||
if m.HasError {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Method represents a host function method within a service.
|
||||
type Method struct {
|
||||
Name string // Go method name (e.g., "Call")
|
||||
|
||||
@ -9,7 +9,6 @@ package ndhost
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/navidrome/navidrome/plugins/pdk/go/pdk"
|
||||
)
|
||||
@ -24,8 +23,7 @@ type counterCountRequest struct {
|
||||
}
|
||||
|
||||
type counterCountResponse struct {
|
||||
Value int32 `json:"value,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Value int32 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// CounterCount calls the counter_count host function.
|
||||
|
||||
@ -46,7 +46,4 @@ def counter_count(name: str) -> int:
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
|
||||
return response.get("value", 0)
|
||||
|
||||
@ -17,8 +17,6 @@ struct CounterCountRequest {
|
||||
struct CounterCountResponse {
|
||||
#[serde(default)]
|
||||
value: i32,
|
||||
#[serde(default)]
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
#[host_fn]
|
||||
@ -43,9 +41,5 @@ pub fn count(name: &str) -> Result<i32, Error> {
|
||||
}))?
|
||||
};
|
||||
|
||||
if let Some(err) = response.0.error {
|
||||
return Err(Error::msg(err));
|
||||
}
|
||||
|
||||
Ok(response.0.value)
|
||||
}
|
||||
|
||||
@ -16,8 +16,7 @@ type CounterCountRequest struct {
|
||||
|
||||
// CounterCountResponse is the response type for Counter.Count.
|
||||
type CounterCountResponse struct {
|
||||
Value int32 `json:"value,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Value int32 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterCounterHostFunctions registers Counter service host functions.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user