You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
perf: eliminates splitAndTrim bottleneck and replace map+RWMutex with sync.Map
- Replace map + RWMutex with sync.Map for better concurrent cache access performance.
- Eliminated the major splitAndTrim bottleneck and achieved significant performance gains. The key insight was parsing comma-separated values directly instead of creating intermediate string allocations. Replace entire split and trims mechanism into single parseSliceFromStrings function.
- Enhance time.Time parsing.
- New benchmark method
- Add Parallel benchmark
`qparser` is a simple package that helps parse query parameters into structs in Go. It is inspired by [gorilla/schema](https://github.com/gorilla/schema) with a main focus on query parameters. Built on top of Go stdlib, it uses a custom struct tag `qp` to define the query parameter key.
6
+
`qparser` is a lightweight Go package designed to parse URL query parameters directly into Go structs. It is built on the Go standard library, offering a simple and focused solution for handling incoming query strings.
7
7
8
8
## Table of Contents
9
9
-[Installation](#installation)
@@ -79,6 +79,7 @@ func main() {
79
79
// Do something with pagination
80
80
}
81
81
```
82
+
82
83
### Multiple Values Query & Nested Struct
83
84
To support multiple values for a single query parameter, use a slice type. For nested structs, utilize the qp tag within the fields of the nested struct to pass the query parameters. It's important to note that the parent struct containing the nested/child struct **should not have its own qp tag**. Here's an example:
84
85
```go
@@ -107,9 +108,14 @@ func GetMenus(w http.ResponseWriter, r *http.Request) {
107
108
}
108
109
```
109
110
There are three ways for the parser to handle multiple values query parameters:
| RFC3339 (Z or offset) |`2006-01-02T15:04:05Z07:00`|
129
+
| RFC3339Nano (Z or offset, nanosecond prec) |`2006-01-02T15:04:05.999999999Z07:00`|
122
130
| Time only |`15:04:05`|
123
131
| Date only |`2006-01-02`|
124
132
| Date & time (space separated) |`2006-01-02 15:04:05`|
@@ -129,11 +137,9 @@ Supports time.Time, *time.Time, and type aliases. Handles a variety of standard
129
137
| Date & time + milliseconds + TZ |`2006-01-02T15:04:05.000-07:00`|
130
138
| Date & time + microseconds + TZ |`2006-01-02T15:04:05.000000-07:00`|
131
139
| Date & time + nanoseconds + TZ |`2006-01-02T15:04:05.999999999-07:00`|
132
-
| RFC3339 (Z or offset) |`2006-01-02T15:04:05Z07:00`|
133
-
| RFC3339Nano (Z or offset, nanosecond prec) |`2006-01-02T15:04:05.999999999Z07:00`|
134
140
| Space separator + TZ |`2006-01-02 15:04:05-07:00`|
135
141
| Space separator + TZ (+ offset) |`2006-01-02 15:04:05+07:00`|
136
-
| Space separator + fractional + TZ |`2006-01-02 15:04:05.123456789-07:00`|
142
+
| Space separator + fractional + TZ |`2006-01-02 15:04:05.123456789-07:00`|
137
143
138
144
</div>
139
145
@@ -145,8 +151,9 @@ Example:
145
151
```go
146
152
typeReportFilterstruct {
147
153
From time.Time`qp:"from"`
148
-
To time.Time`qp:"to"`
154
+
Totime.Time`qp:"to"`
149
155
}
156
+
150
157
funcmain() {
151
158
varfilter ReportFilter
152
159
@@ -245,23 +252,62 @@ This allows you to:
245
252
246
253
247
254
## Notes
248
-
- Empty query values are not validated by default. For custom validation (including empty value checks), implement your own validation method on the struct or use a third-party validator such as [go-playground/validator](https://github.com/go-playground/validator).
255
+
256
+
- Empty query values are not validated by default. For custom validation (including empty value checks), implement your own validation method on the struct or use a third-party validator such as go-playground/validator.
249
257
- Missing query parameters:
250
-
- Primitive fields keep their zero values (0, "", false, etc.).
251
-
- Pointer fields are always initialized, even when the parameter is missing. They will contain the zero value of the underlying type.
252
-
- Slice fields become an empty slice ([]T{}), not nil.
253
-
- Pointer nested structs are also always initialized. Missing fields inside them receive their zero values.
258
+
- Primitive fields keep their zero values (0, "", false, etc.).
259
+
- Pointer-to-primitive fields (e.g., `*string`, `*int`) remain `nil` when the parameter is missing. They are only allocated when the parameter is provided.
260
+
- Slice fields (`[]T`) remain `nil` when the parameter is missing. They are allocated only when at least one value is successfully decoded.
261
+
- Pointer-to-slice fields (`*[]T`) remain `nil` when the parameter is missing. They are allocated only when the parameter is provided.
262
+
- Pointer-to-struct fields are **always initialized**, even when the nested parameters are missing. They contain the zero value of the struct.
254
263
- For repeated query parameters, the value is appended to the slice every time. If you want deduplication or sanitization, implement a post-processing method on your struct.
255
-
- The qp tag is case-sensitive and must match the query parameter key exactly.
264
+
- The `qp` tag is case-sensitive and must match the query parameter key exactly.
265
+
- Pointer-to-struct fields offer no practical benefit because they are always initialized and never `nil`, you cannot rely on `nil` checks to detect whether a nested parameter group was supplied. If you need that behavior, inspect field values or apply custom post-processing.
-**Persistent**: Cache lives for application lifetime
311
+
312
+
#### Concurrency
313
+
Parallel execution leverages sync.Map for effective caching, significantly improving performance under concurrent workloads like HTTP handlers by reducing per-operation time
0 commit comments