From 8927764e18295f50c6e75ecb35c51902eabe1ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirza=20U=C4=8Danbarli=C4=87?= <56406159+supersonicbyte@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:19:37 +0200 Subject: [PATCH] Add support for array indices in query params decoding (#542) * Add support for array indices in query params decoding * Resolve PR comments --- .../URLEncodedForm/URLEncodedFormNode.swift | 20 ++++++++-- .../URLEncodedForm/URLDecoderTests.swift | 39 ++++++++++++++++++- .../URLEncodedForm/URLEncodedNodeTests.swift | 5 +++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift index f7944d25b..ac59fb52f 100644 --- a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift +++ b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift @@ -7,9 +7,10 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable { /// holds an array of nodes case array(Array) - enum Error: Swift.Error { + enum Error: Swift.Error, Equatable { case failedToDecode(String? = nil) case notSupported + case invalidArrayIndex(Int) } /// Initialize node from URL encoded form data @@ -51,7 +52,7 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable { /// function for create `URLEncodedFormNode` from `KeyParser.Key.Type` func createNode(from key: KeyParser.KeyType) -> URLEncodedFormNode { switch key { - case .array: + case .array, .arrayWithIndices: return .array(.init()) case .map: return .map(.init()) @@ -84,6 +85,11 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable { // currently don't support arrays and maps inside arrays throw Error.notSupported } + case (.array(let array), .arrayWithIndices(let index)): + guard keys.count == 0, array.values.count == index else { + throw Error.invalidArrayIndex(index) + } + array.values.append(.leaf(value)) default: throw Error.failedToDecode() } @@ -168,7 +174,7 @@ enum URLEncodedFormNode: CustomStringConvertible, Equatable { /// Parse URL encoded key enum KeyParser { - enum KeyType: Equatable { case map(Substring), array } + enum KeyType: Equatable { case map(Substring), array, arrayWithIndices(Int) } static func parse(_ key: String) -> [KeyType]? { var index = key.startIndex @@ -186,13 +192,19 @@ enum KeyParser { index = key.index(after: index) // an open bracket is unexpected guard index != key.endIndex else { return nil } + if key[index] == "]" { values.append(.array) index = key.index(after: index) } else { // an open bracket is unexpected guard let bracketIndex = key[index...].firstIndex(of: "]") else { return nil } - values.append(.map(key[index..