Skip to content
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

[Generator] Support unexploded query items #171

Merged
merged 4 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ enum LiteralDescription: Equatable, Codable {
/// For example `42`.
case int(Int)

/// A Boolean literal.
///
/// For example `true`.
case bool(Bool)

/// The nil literal: `nil`.
case `nil`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ struct TextBasedRenderer: RendererProtocol {
return "\"\(string)\""
case let .int(int):
return "\(int)"
case let .bool(bool):
return bool ? "true" : "false"
case .nil:
return "nil"
case .array(let items):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ enum Constants {

/// The name of the namespace.
static let namespace: String = "Parameters"

/// Maps to `OpenAPIRuntime.ParameterStyle`.
enum Style {

/// The form style.
static let form = "form"
}
}

/// Constants related to the Headers namespace.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ struct TypedParameter {
/// The underlying schema.
var schema: UnresolvedSchema

/// The parameter serialization style.
var style: OpenAPI.Parameter.SchemaContext.Style

/// The parameter explode value.
var explode: Bool

/// The computed type usage.
var typeUsage: TypeUsage

Expand Down Expand Up @@ -134,9 +140,13 @@ extension FileTranslator {

let schema: UnresolvedSchema
let codingStrategy: CodingStrategy
let style: OpenAPI.Parameter.SchemaContext.Style
let explode: Bool
switch parameter.schemaOrContent {
case let .a(schemaContext):
schema = schemaContext.schema
style = schemaContext.style
explode = schemaContext.explode
codingStrategy = .text

// Check supported exploded/style types
Expand All @@ -150,13 +160,6 @@ extension FileTranslator {
)
return nil
}
guard schemaContext.explode else {
diagnostics.emitUnsupported(
"Unexploded query params",
foundIn: foundIn
)
return nil
}
case .header, .path:
guard case .simple = schemaContext.style else {
diagnostics.emitUnsupported(
Expand Down Expand Up @@ -189,6 +192,14 @@ extension FileTranslator {
.content
.contentType
.codingStrategy
switch parameter.location {
case .query, .cookie:
style = .form
explode = true
case .path, .header:
style = .simple
explode = false
czechboy0 marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Check if the underlying schema is supported
Expand Down Expand Up @@ -221,6 +232,8 @@ extension FileTranslator {
return .init(
parameter: parameter,
schema: schema,
style: style,
explode: explode,
typeUsage: usage,
codingStrategy: codingStrategy,
asSwiftSafeName: swiftSafeName
Expand Down Expand Up @@ -271,3 +284,16 @@ extension OpenAPI.Parameter.Context.Location {
}
}
}

extension OpenAPI.Parameter.SchemaContext.Style {

/// The runtime name for the style.
var runtimeName: String {
switch self {
case .form:
return Constants.Components.Parameters.Style.form
default:
preconditionFailure("Unsupported style")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,32 @@ extension ClientFileTranslator {
) throws -> Expression? {
let methodPrefix: String
let containerExpr: Expression
let supportsStyleAndExplode: Bool
switch parameter.location {
case .header:
methodPrefix = "HeaderField"
containerExpr = .identifier(requestVariableName).dot("headerFields")
supportsStyleAndExplode = false
case .query:
methodPrefix = "QueryItem"
containerExpr = .identifier(requestVariableName)
supportsStyleAndExplode = true
default:
diagnostics.emitUnsupported(
"Parameter of type \(parameter.location.rawValue)",
foundIn: parameter.description
)
return nil
}
let styleAndExplodeArgs: [FunctionArgumentDescription]
if supportsStyleAndExplode {
styleAndExplodeArgs = [
.init(label: "style", expression: .dot(parameter.style.runtimeName)),
.init(label: "explode", expression: .literal(.bool(parameter.explode))),
]
} else {
styleAndExplodeArgs = []
}
return .try(
.identifier("converter")
.dot("set\(methodPrefix)As\(parameter.codingStrategy.runtimeName)")
Expand All @@ -138,7 +150,8 @@ extension ClientFileTranslator {
.init(
label: "in",
expression: .inOut(containerExpr)
),
)
] + styleAndExplodeArgs + [
.init(label: "name", expression: .literal(parameter.name)),
.init(
label: "value",
Expand Down Expand Up @@ -194,6 +207,8 @@ extension ServerFileTranslator {
.identifier("converter").dot(methodName("QueryItem"))
.call([
.init(label: "in", expression: .identifier("metadata").dot("queryParameters")),
.init(label: "style", expression: .dot(typedParameter.style.runtimeName)),
.init(label: "explode", expression: .literal(.bool(typedParameter.explode))),
.init(label: "name", expression: .literal(parameter.name)),
.init(
label: "as",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct TypesFileTranslator: FileTranslator {
let components = try translateComponents(doc.components)

let operationDescriptions = try OperationDescription.all(
from: parsedOpenAPI.paths,
from: doc.paths,
in: doc.components,
asSwiftSafeName: swiftSafeName
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Supported features are always provided on _both_ client and server.
- [x] requestBody
- [x] responses
- [ ] callbacks
- [ ] deprecated
- [x] deprecated
- [ ] security
- [ ] servers

Expand Down Expand Up @@ -162,7 +162,7 @@ Supported features are always provided on _both_ client and server.
- [ ] xml
- [ ] externalDocs
- [ ] example
- [ ] deprecated
- [x] deprecated

#### External Documentation Object

Expand Down Expand Up @@ -196,15 +196,15 @@ Supported features are always provided on _both_ client and server.
- [x] in
- [x] description
- [x] required
- [ ] deprecated
- [x] deprecated
- [ ] allowEmptyValue
- [x] style (not all)
- [x] explode (only explode: `true`)
- [x] style (only defaults)
- [x] explode (non default only for query items)
- [ ] allowReserved
- [x] schema
- [ ] example
- [ ] examples
- [ ] content
- [x] content (chooses one from the map)

#### Style Values

Expand All @@ -223,7 +223,7 @@ Supported features are always provided on _both_ client and server.

Supported location + styles + exploded combinations:
- path + simple + false
- query + form + true
- query + form + true/false
- header + simple + false

#### Reference Object
Expand Down
8 changes: 5 additions & 3 deletions Tests/OpenAPIGeneratorCoreTests/StructureHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,15 @@ extension Declaration {
extension LiteralDescription {
var name: String {
switch self {
case .string(_):
case .string:
return "string"
case .int(_):
case .int:
return "int"
case .bool:
return "bool"
case .nil:
return "nil"
case .array(_):
case .array:
return "array"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,22 @@ public struct Client: APIProtocol {
suppressMutabilityWarning(&request)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "limit",
value: input.query.limit
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "habitat",
value: input.query.habitat
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "feeds",
value: input.query.feeds
)
Expand All @@ -72,6 +78,8 @@ public struct Client: APIProtocol {
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "since",
value: input.query.since
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,29 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
let query: Operations.listPets.Input.Query = .init(
limit: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "limit",
as: Swift.Int32.self
),
habitat: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "habitat",
as: Operations.listPets.Input.Query.habitatPayload.self
),
feeds: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "feeds",
as: Operations.listPets.Input.Query.feedsPayload.self
),
since: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "since",
as: Components.Parameters.query_born_since.self
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,22 @@ public struct Client: APIProtocol {
suppressMutabilityWarning(&request)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "limit",
value: input.query.limit
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "habitat",
value: input.query.habitat
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "feeds",
value: input.query.feeds
)
Expand All @@ -72,6 +78,8 @@ public struct Client: APIProtocol {
)
try converter.setQueryItemAsText(
in: &request,
style: .form,
explode: true,
name: "since",
value: input.query.since
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,29 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
let query: Operations.listPets.Input.Query = .init(
limit: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "limit",
as: Swift.Int32.self
),
habitat: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "habitat",
as: Operations.listPets.Input.Query.habitatPayload.self
),
feeds: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "feeds",
as: Operations.listPets.Input.Query.feedsPayload.self
),
since: try converter.getOptionalQueryItemAsText(
in: metadata.queryParameters,
style: .form,
explode: true,
name: "since",
as: Components.Parameters.query_born_since.self
)
Expand Down
Loading