Skip to content

Commit 071f049

Browse files
committed
Use functional options for optional arguments
In order to implement equivalent of optional arguments, functional optionals are used.
1 parent 0996a7c commit 071f049

File tree

7 files changed

+159
-31
lines changed

7 files changed

+159
-31
lines changed

src/SDK/Language/Go.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,19 @@ public function getFiles(): array
115115
],
116116
[
117117
'scope' => 'service',
118-
'destination' => '{{ spec.title | caseLower}}/{{service.name | caseDash}}.go',
118+
'destination' => '{{ service.name | caseLower}}/{{service.name | caseDash}}.go',
119119
'template' => 'go/services/service.go.twig',
120120
],
121121
[
122122
'scope' => 'method',
123123
'destination' => 'docs/examples/{{service.name | caseLower}}/{{method.name | caseDash}}.md',
124124
'template' => 'go/docs/example.md.twig',
125125
],
126+
[
127+
'scope' => 'definition',
128+
'destination' => '{{ spec.title | caseLower}}models/{{ definition.name | caseLower }}.go',
129+
'template' => 'go/models/model.go.twig',
130+
],
126131
];
127132
}
128133

@@ -139,7 +144,7 @@ public function getTypeName(array $parameter): string
139144
case self::TYPE_NUMBER:
140145
return 'float64';
141146
case self::TYPE_FILE:
142-
return 'InputFile';
147+
return 'appwrite.InputFile';
143148
case self::TYPE_STRING:
144149
return 'string';
145150
case self::TYPE_BOOLEAN:
@@ -275,6 +280,41 @@ public function getFilters(): array
275280
}
276281
return implode("\n" . $indent, $value);
277282
}, ['is_safe' => ['html']]),
283+
new TwigFilter('propertyType', function (array $property, array $spec, string $generic = 'interface{}') {
284+
return $this->getPropertyType($property, $spec, $generic);
285+
}),
286+
new TwigFilter('returnType', function (array $method, array $spec, string $namespace, string $generic = 'T') {
287+
return $this->getReturnType($method, $spec, $namespace, $generic);
288+
}),
278289
];
279290
}
291+
292+
protected function getPropertyType(array $property, array $spec, string $generic = 'interface{}'): string
293+
{
294+
$type = $this->getTypeName($property);
295+
return $type;
296+
}
297+
298+
protected function getReturnType(array $method, array $spec, string $namespace, string $generic = 'T'): string
299+
{
300+
if ($method['type'] === 'webAuth') {
301+
return 'bool';
302+
}
303+
if ($method['type'] === 'location') {
304+
return '[]byte';
305+
}
306+
307+
if (
308+
!\array_key_exists('responseModel', $method)
309+
|| empty($method['responseModel'])
310+
|| $method['responseModel'] === 'any'
311+
) {
312+
return 'interface{}';
313+
}
314+
315+
$ret = ucfirst($method['responseModel']);
316+
317+
318+
return $namespace . 'Model.' . $ret;
319+
}
280320
}

templates/go/base/params.twig

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
params := map[string]interface{}{
2-
{% for parameter in method.parameters.query %}
3-
"{{ parameter.name }}": {{ parameter.name | caseUcfirst }},
4-
{% endfor %}
5-
{% for parameter in method.parameters.body %}
6-
"{{ parameter.name }}": {{ parameter.name | caseUcfirst }},
7-
{% endfor %}
1+
{% if method.parameters.all|filter(v => not v.required)|length > 0 %}
2+
options := &{{(method.name ~ "Options") | caseUcfirst}}{}
3+
for _, opt := range optionalSetters {
4+
opt(options)
85
}
9-
6+
{% endif %}
7+
params := map[string]interface{}{}
8+
{% for parameter in method.parameters.all %}
9+
{% if parameter.required %}
10+
params["{{ parameter.name }}"] = {{ parameter.name | caseUcfirst }}
11+
{% else %}
12+
params["{{ parameter.name }}"] = options.{{ parameter.name | caseUcfirst }}
13+
{% endif %}
14+
{% endfor %}
1015
headers := map[string]interface{}{
1116
{% for key, header in method.headers %}
1217
"{{ key }}": "{{ header }}",
1318
{% endfor %}
14-
}
19+
}

templates/go/base/requests/api.twig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1-
return srv.client.Call("{{ method.method | caseUpper }}", path, headers, params)
1+
resp, err := srv.client.Call("{{ method.method | caseUpper }}", path, headers, params)
2+
if err != nil {
3+
return nil, err
4+
}
5+
var parsed {{ method | returnType(spec, spec.title | caseLower) }}
6+
if strings.HasPrefix(resp.Type, "application/json") {
7+
err = json.Unmarshal([]byte(resp.Result.(string)), &parsed)
8+
if err != nil {
9+
return nil, err
10+
}
11+
return &parsed, nil
12+
}
13+
parsed, ok := resp.Result.({{ method | returnType(spec, spec.title | caseLower) }})
14+
if !ok {
15+
return nil, errors.New("unexpected response type")
16+
}
17+
return &parsed, nil

templates/go/base/requests/file.twig

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,12 @@
1212
{% endif %}
1313
{% endfor %}
1414

15-
return srv.client.FileUpload(path, headers, params, paramName, uploadId)
15+
resp, err := srv.client.FileUpload(path, headers, params, paramName, uploadId)
16+
if err != nil {
17+
return nil, err
18+
}
19+
parsed, ok := resp.Result.({{ method | returnType(spec, spec.title | caseLower) }})
20+
if !ok {
21+
return nil, errors.New("Unexpected response type")
22+
}
23+
return &parsed, nil

templates/go/client.go.twig

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type ClientResponse struct {
3737
StatusCode int
3838
Header http.Header
3939
Result interface{}
40+
Type string
4041
}
4142

4243
func (ce *{{ spec.title | caseUcfirst }}Error) Error() string {
@@ -347,11 +348,12 @@ func (clt *Client) Call(method string, path string, headers map[string]interface
347348
return nil, err
348349
}
349350

350-
var isJson = strings.HasPrefix(resp.Header.Get("content-type"), "application/json")
351+
contentType := resp.Header.Get("content-type")
352+
var isJson = strings.HasPrefix(contentType, "application/json")
351353
if isJson {
352-
var jsonResponse map[string]interface{}
353-
json.Unmarshal(responseData, &jsonResponse)
354354
if resp.StatusCode < 200 || resp.StatusCode > 399 {
355+
var jsonResponse map[string]interface{}
356+
json.Unmarshal(responseData, &jsonResponse)
355357
message, ok := jsonResponse["message"].(string)
356358
if !ok {
357359
message = "N/A"
@@ -365,10 +367,11 @@ func (clt *Client) Call(method string, path string, headers map[string]interface
365367
Status: resp.Status,
366368
StatusCode: resp.StatusCode,
367369
Header: resp.Header,
368-
Result: jsonResponse,
370+
Result: string(responseData),
371+
Type: contentType,
369372
}, nil
370373
}
371-
output, err := getOutput(params, fileNameKey, responseData, resp.Header.Get("content-type"))
374+
output, err := getOutput(params, fileNameKey, responseData, contentType)
372375
if err != nil {
373376
return nil, err
374377
}
@@ -383,6 +386,7 @@ func (clt *Client) Call(method string, path string, headers map[string]interface
383386
StatusCode: resp.StatusCode,
384387
Header: resp.Header,
385388
Result: output,
389+
Type: contentType,
386390
}, nil
387391
}
388392

templates/go/models/model.go.twig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package {{ spec.title | caseLower }}Model
2+
3+
4+
{{ ((definition.description | caseUcfirst) ~ " Model") | godocComment }}
5+
type {{ definition.name | caseUcfirst }} struct {
6+
{%~ for property in definition.properties %}
7+
{{ property.description | godocComment(4) }}
8+
{{ property.name | caseUcfirst }} {{ property | propertyType(spec) }} `json:"{{ property.name | escapeKeyword }}"`
9+
{%~ endfor %}
10+
11+
{%~ if definition.additionalProperties %}
12+
// Additional properties
13+
data interface{}
14+
{%~ endif %}
15+
}

templates/go/services/service.go.twig

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,79 @@
1-
{%- set requireStringsPkg = false -%}
1+
{%- set requireModelsPkg = false -%}
22
{%- for method in service.methods -%}
3-
{%- if method.parameters.path|length > 0 -%}
4-
{%- set requireStringsPkg = true -%}
5-
{%- endif -%}
3+
{%- if (method | returnType(spec, spec.title | caseLower)) starts with (spec.title | caseLower ~ "Model") -%}
4+
{%- set requireModelsPkg = true -%}
5+
{%- endif -%}
66
{%- endfor -%}
7-
package {{ spec.title | caseLower }}
7+
package {{ service.name | caseLower }}
88

99
import (
10-
{% if requireStringsPkg %}
11-
"strings"
10+
"encoding/json"
11+
"errors"
12+
{% if requireModelsPkg %}
13+
"github.com/{{sdk.gitUserName}}/sdk-for-go/{{ spec.title | caseLower }}models"
1214
{% endif %}
15+
"strings"
16+
"github.com/{{sdk.gitUserName}}/sdk-for-go/{{ spec.title | caseLower }}"
1317
)
1418

1519
{{ ((service.name | caseUcfirst) ~ " service") | godocComment }}
1620
type {{ service.name | caseUcfirst }} struct {
17-
client Client
21+
client {{ spec.title | caseLower }}.Client
1822
}
1923

20-
func New{{ service.name | caseUcfirst }}(clt Client) *{{ service.name | caseUcfirst }} {
24+
func New{{ service.name | caseUcfirst }}(clt {{ spec.title | caseLower }}.Client) *{{ service.name | caseUcfirst }} {
2125
return &{{ service.name | caseUcfirst }}{
2226
client: clt,
2327
}
2428
}
25-
{% for method in service.methods %}
2629

30+
{% for method in service.methods %}
2731
{% if method.description %}{{ ((method.name | caseUcfirst) ~ ' ' ~ method.description | caseLcfirst) | godocComment }}{% else %}// {{ method.name | caseUcfirst }}{% endif %}
2832

29-
func (srv *{{ service.name | caseUcfirst }}) {{ method.name | caseUcfirst }}({% if method.parameters.all|length > 0 %}{% for parameter in method.parameters.all %}{{ parameter.name | caseUcfirst }} {{ parameter | typeName }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}) (*ClientResponse, error) {
33+
type {{ (method.name ~ "Options") | caseUcfirst }} struct {
34+
{% for parameter in method.parameters.all %}
35+
{% if not parameter.required %}
36+
{{ parameter.name | caseUcfirst }} {{ (parameter | typeName) }}
37+
{% endif %}
38+
{% endfor %}
39+
}
40+
41+
type {{ (method.name ~ "Option" ) | caseUcfirst }} func(*{{ (method.name ~ "Options") | caseUcfirst }})
42+
43+
{% if method.parameters.all|filter(v => not v.required)|length > 0 %}
44+
{% for parameter in method.parameters.all|filter(v => not v.required) %}
45+
func With{{ method.name | caseUcfirst }}{{ parameter.name | caseUcfirst }}(v {{ (parameter | typeName) }}) {{ (method.name ~ "Option") | caseUcfirst }} {
46+
return func(o *{{ (method.name ~ "Options") | caseUcfirst }}) {
47+
o.{{ parameter.name | caseUcfirst }} = v
48+
}
49+
}
50+
{% endfor %}
51+
{% endif %}
52+
53+
{% set params="" %}
54+
{% if method.parameters.all|filter(v => v.required)|length > 0 %}
55+
{% for parameter in method.parameters.all|filter(v => v.required) %}
56+
{% set params = params ~ (parameter.name | caseUcfirst) ~ " " ~ (parameter | typeName) %}
57+
{% if not loop.last %}
58+
{% set params = params ~ ", " %}
59+
{% endif %}
60+
{% endfor %}
61+
{% if method.parameters.all|filter(v => not v.required)|length > 0 %}
62+
{% set params = params ~ ", " %}
63+
{% endif %}
64+
{% endif %}
65+
{% if method.parameters.all|filter(v => not v.required)|length > 0 %}
66+
{% set params = params ~ "optionalSetters ..." ~ ((method.name ~ "Option") | caseUcfirst) %}
67+
{% endif %}
68+
69+
func (srv *{{ service.name | caseUcfirst }}) {{ method.name | caseUcfirst }}({{ params }}) (*{{ method | returnType(spec, spec.title | caseLower) }}, error) {
3070
{% if method.parameters.path|length > 0 %}
3171
r := strings.NewReplacer({% for parameter in method.parameters.path %}"{{ '{' }}{{ parameter.name | caseCamel }}{{ '}' }}", {{ parameter.name | caseUcfirst }}{% if not loop.last %}, {% endif %}{% endfor %})
3272
path := r.Replace("{{ method.path }}")
3373

3474
{% else %}
3575
path := "{{ method.path }}"
36-
76+
3777
{% endif %}
3878
{{include('go/base/params.twig')}}
3979
{% if 'multipart/form-data' in method.consumes %}
@@ -42,4 +82,4 @@ func (srv *{{ service.name | caseUcfirst }}) {{ method.name | caseUcfirst }}({%
4282
{{ include('go/base/requests/api.twig') }}
4383
{% endif %}
4484
}
45-
{% endfor %}
85+
{% endfor %}

0 commit comments

Comments
 (0)