Skip to content

[swift][client] make QueryStringEncodable return any Sendable #21142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion docs/generators/swift6.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useBacktickEscapes|Escape reserved words using backticks (default: false)| |false|
|useClasses|Use final classes for models instead of structs (default: false)| |false|
|useCustomDateWithoutTime|Uses a custom type to decode and encode dates without time information to support OpenAPIs date format (default: false)| |false|
|useJsonEncodable|Make models conform to JSONEncodable protocol (default: true)| |true|
|useParameterConvertible|Make models conform to ParameterConvertible protocol (default: true)| |true|
|useSPMFileStructure|Use SPM file structure and set the source path to Sources/{{projectName}} (default: true).| |null|
|validatable|Make validation rules and validator for model properties (default: true)| |true|

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
public static final String GENERATE_MODEL_ADDITIONAL_PROPERTIES = "generateModelAdditionalProperties";
public static final String HASHABLE_MODELS = "hashableModels";
public static final String IDENTIFIABLE_MODELS = "identifiableModels";
public static final String USE_JSON_ENCODABLE = "useJsonEncodable";
public static final String USE_PARAMETER_CONVERTIBLE = "useParameterConvertible";
public static final String MAP_FILE_BINARY_TO_DATA = "mapFileBinaryToData";
public static final String USE_CUSTOM_DATE_WITHOUT_TIME = "useCustomDateWithoutTime";
public static final String VALIDATABLE = "validatable";
Expand Down Expand Up @@ -115,7 +115,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
@Setter
protected boolean identifiableModels = true;
@Setter
protected boolean useJsonEncodable = true;
protected boolean useParameterConvertible = true;
@Getter
@Setter
protected boolean mapFileBinaryToData = false;
Expand Down Expand Up @@ -335,8 +335,8 @@ public Swift6ClientCodegen() {
"Make models conform to Identifiable when an id is present (default: true)")
.defaultValue(Boolean.TRUE.toString()));

cliOptions.add(new CliOption(USE_JSON_ENCODABLE,
"Make models conform to JSONEncodable protocol (default: true)")
cliOptions.add(new CliOption(USE_PARAMETER_CONVERTIBLE,
"Make models conform to ParameterConvertible protocol (default: true)")
.defaultValue(Boolean.TRUE.toString()));

cliOptions.add(new CliOption(MAP_FILE_BINARY_TO_DATA,
Expand Down Expand Up @@ -560,10 +560,10 @@ public void processOpts() {
}
additionalProperties.put(IDENTIFIABLE_MODELS, identifiableModels);

if (additionalProperties.containsKey(USE_JSON_ENCODABLE)) {
setUseJsonEncodable(convertPropertyToBooleanAndWriteBack(USE_JSON_ENCODABLE));
if (additionalProperties.containsKey(USE_PARAMETER_CONVERTIBLE)) {
setUseParameterConvertible(convertPropertyToBooleanAndWriteBack(USE_PARAMETER_CONVERTIBLE));
}
additionalProperties.put(USE_JSON_ENCODABLE, useJsonEncodable);
additionalProperties.put(USE_PARAMETER_CONVERTIBLE, useParameterConvertible);

if (additionalProperties.containsKey(MAP_FILE_BINARY_TO_DATA)) {
setMapFileBinaryToData(convertPropertyToBooleanAndWriteBack(MAP_FILE_BINARY_TO_DATA));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,103 +11,98 @@ import FoundationNetworking
@preconcurrency import PromiseKit{{/usePromiseKit}}{{#useVapor}}
import Vapor{{/useVapor}}{{^useVapor}}

extension QueryStringEncodable {
@_disfavoredOverload
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Bool: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Bool: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Float: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Float: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Int: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Int: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Int32: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Int32: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Int64: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Int64: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Double: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Double: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension Decimal: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension Decimal: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension String: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension String: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension URL: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension URL: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension UUID: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable { self }
}

extension UUID: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: self) }
extension RawRepresentable where RawValue: ParameterConvertible, RawValue: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable { return self.rawValue }
}

extension RawRepresentable where RawValue: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String { String(describing: rawValue) }
}

private func encodeIfPossible<T>(_ object: T, codableHelper: CodableHelper) -> String {
if let encodableObject = object as? QueryStringEncodable {
return encodableObject.encodeToQueryString(codableHelper: codableHelper)
private func encodeIfPossible<T: Sendable>(_ object: T, codableHelper: CodableHelper) -> any Sendable {
if let encodableObject = object as? ParameterConvertible {
return encodableObject.asParameter(codableHelper: codableHelper)
} else {
return String(describing: object)
return object
}
}

extension Array {
func encodeToQueryString(codableHelper: CodableHelper) -> [String] {
extension Array where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.map { encodeIfPossible($0, codableHelper: codableHelper) }
}
}

extension Set {
func encodeToQueryString(codableHelper: CodableHelper) -> [String] {
return Array(self).encodeToQueryString(codableHelper: codableHelper)
extension Set where Element: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return Array(self).asParameter(codableHelper: codableHelper)
}
}

extension Dictionary {
func encodeToQueryString(codableHelper: CodableHelper) -> [Key: String] {
var dictionary = [Key: String]()
extension Dictionary where Key: Sendable, Value: Sendable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
var dictionary = [Key: any Sendable]()
for (key, value) in self {
dictionary[key] = encodeIfPossible(value, codableHelper: codableHelper)
}
return dictionary
}
}

extension Data: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String {
extension Data: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return self.base64EncodedString(options: Data.Base64EncodingOptions())
}
}

extension Date: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String {
extension Date: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return codableHelper.dateFormatter.string(from: self)
}
}

extension QueryStringEncodable where Self: Encodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String {
extension ParameterConvertible where Self: Encodable {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
guard let data = try? codableHelper.jsonEncoder.encode(self) else {
fatalError("Could not encode to json: \(self)")
}
return data.encodeToQueryString(codableHelper: codableHelper)
return data.asParameter(codableHelper: codableHelper)
}
}{{/useVapor}}{{#generateModelAdditionalProperties}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import FoundationNetworking
#endif{{#useAlamofire}}
import Alamofire{{/useAlamofire}}

protocol QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String
protocol ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable
}

/// An enum where the last case value can be used as a default catch-all.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ import Foundation
}
}

extension OpenAPIDateWithoutTime: QueryStringEncodable {
func encodeToQueryString(codableHelper: CodableHelper) -> String {
extension OpenAPIDateWithoutTime: ParameterConvertible {
func asParameter(codableHelper: CodableHelper) -> any Sendable {
return OpenISO8601DateFormatter.withoutTime.string(from: self.normalizedWrappedDate())
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"{{baseName}}": {{#isQueryParam}}(wrappedValue: {{/isQueryParam}}{{paramName}}{{^required}}?{{/required}}.encodeToQueryString(codableHelper: apiConfiguration.codableHelper){{#isQueryParam}}, isExplode: {{isExplode}}){{/isQueryParam}}
"{{baseName}}": {{#isQueryParam}}(wrappedValue: {{/isQueryParam}}{{paramName}}{{^required}}?{{/required}}.asParameter(codableHelper: apiConfiguration.codableHelper){{#isQueryParam}}, isExplode: {{isExplode}}){{/isQueryParam}}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{dataType}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useJsonEncodable}}, QueryStringEncodable{{/useJsonEncodable}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{/enumUnknownDefaultCase}} {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{dataType}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{/enumUnknownDefaultCase}} {
{{#allowableValues}}
{{#enumVars}}
case {{{name}}} = {{{value}}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{enumName}}: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isContainer}}{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useJsonEncodable}}, QueryStringEncodable{{/useJsonEncodable}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/isContainer}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{#isContainer}}, CaseIterableDefaultsLast{{/isContainer}}{{/enumUnknownDefaultCase}} {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{enumName}}: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}, Sendable, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isContainer}}{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/isContainer}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{#isContainer}}, CaseIterableDefaultsLast{{/isContainer}}{{/enumUnknownDefaultCase}} {
{{#allowableValues}}
{{#enumVars}}
case {{{name}}} = {{{value}}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}@unchecked Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#useJsonEncodable}}, QueryStringEncodable{{/useJsonEncodable}}{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class {{classname}}: NSObject, Codable{{#useJsonEncodable}}, QueryStringEncodable{{/useJsonEncodable}} {
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}@unchecked Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class {{classname}}: NSObject, Codable{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}} {
{{/objcCompatible}}

{{#allVars}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#useJsonEncodable}}, QueryStringEncodable{{/useJsonEncodable}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}}{{/useVapor}} {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{classname}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#useParameterConvertible}}, ParameterConvertible{{/useParameterConvertible}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}}{{/useVapor}} {
{{#oneOf}}
case type{{#transformArrayType}}{{.}}{{/transformArrayType}}({{.}})
{{/oneOf}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class Swift6ClientCodegenOptionsProvider implements OptionsProvider {
public static final String GENERATE_MODEL_ADDITIONAL_PROPERTIES_VALUE = "true";
public static final String HASHABLE_MODELS_VALUE = "true";
public static final String IDENTIFIABLE_MODELS_VALUE = "true";
public static final String USE_JSON_ENCODABLE_VALUE = "true";
public static final String USE_PARAMETER_CONVERTIBLE_VALUE = "true";
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true";
public static final String LIBRARY_VALUE = "alamofire";
Expand Down Expand Up @@ -99,7 +99,7 @@ public Map<String, String> createOptions() {
GENERATE_MODEL_ADDITIONAL_PROPERTIES_VALUE)
.put(Swift6ClientCodegen.HASHABLE_MODELS, HASHABLE_MODELS_VALUE)
.put(Swift6ClientCodegen.IDENTIFIABLE_MODELS, IDENTIFIABLE_MODELS_VALUE)
.put(Swift6ClientCodegen.USE_JSON_ENCODABLE, USE_JSON_ENCODABLE_VALUE)
.put(Swift6ClientCodegen.USE_PARAMETER_CONVERTIBLE, USE_PARAMETER_CONVERTIBLE_VALUE)
.put(Swift6ClientCodegen.MAP_FILE_BINARY_TO_DATA, "false")
.put(Swift6ClientCodegen.USE_CUSTOM_DATE_WITHOUT_TIME, "false")
.put(Swift6ClientCodegen.VALIDATABLE, "true")
Expand Down
Loading
Loading