Skip to content

Releases: Prawirdani/qparser

v1.3.5

29 Nov 10:46
v1.3.5
70babd2

Choose a tag to compare

This release introduces performance enhancements, focusing on eliminating bottlenecks and improving concurrency.

Changes:

  • Eliminated splitAndTrim bottleneck: Replaced the split and trim mechanism with direct slice parsing using a new parseSliceFromStrings function, avoiding intermediate string allocations.
  • Concurrent access optimization: Replaced map + RWMutex with sync.Map for better concurrent performance.
  • Enhanced time.Time parsing: Improved parsing efficiency for date and time fields.
  • New benchmark methods: Added parallel benchmarks to better measure performance under various conditions.

Benchmark Results Comparison:

Previous Benchmarks:

Benchmark/Small-8              224376     4602 ns/op       2680 B/op      13 allocs/op
Benchmark/Medium-8             246818     4851 ns/op       2720 B/op      13 allocs/op
Benchmark/Large-8              173422     5867 ns/op       3056 B/op      21 allocs/op
Benchmark/LargeWithDate-8      160401     6543 ns/op       3104 B/op      23 allocs/op

New Benchmarks:

goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
=== Sequential ===========================================================================================
Benchmark/Seq/Minimal-8                  1204855          983.8 ns/op          224 B/op        1 allocs/op
Benchmark/Seq/1-date-8                    930016           1233 ns/op          248 B/op        2 allocs/op
Benchmark/Seq/2-dates-8                   626414           1599 ns/op          272 B/op        3 allocs/op
Benchmark/Seq/slices-string-1*50-8        348960           2924 ns/op         1144 B/op        3 allocs/op
Benchmark/Seq/slices-int-1*50-8           292065           3613 ns/op          664 B/op        3 allocs/op
Benchmark/Seq/slices-2*50-8               202550           5514 ns/op         1584 B/op        5 allocs/op
Benchmark/Seq/slices-2*100-8              123055           9351 ns/op         2960 B/op        5 allocs/op
Benchmark/Seq/2*25-slices-and-2-dates-8   257817           4158 ns/op          944 B/op        7 allocs/op
=== Parallel =============================================================================================
Benchmark/Par/Minimal-8                  4529499          261.3 ns/op          224 B/op        1 allocs/op
Benchmark/Par/1-date-8                   3590239          356.3 ns/op          248 B/op        2 allocs/op
Benchmark/Par/2-dates-8                  2865769          420.1 ns/op          272 B/op        3 allocs/op
Benchmark/Par/slices-string-1*50-8       1261774          963.2 ns/op         1144 B/op        3 allocs/op
Benchmark/Par/slices-int-1*50-8          1136395           1025 ns/op          664 B/op        3 allocs/op
Benchmark/Par/slices-2*50-8               684651           1758 ns/op         1584 B/op        5 allocs/op
Benchmark/Par/slices-2*100-8              410012           2982 ns/op         2960 B/op        5 allocs/op
Benchmark/Par/2*25-slices-and-2-dates-8   990036           1244 ns/op          944 B/op        7 allocs/op

Performance Gains:

  • Sequential operations: Up to 4x faster execution times with significantly reduced memory allocations (from 13-23 allocs/op to 1-7 allocs/op).
  • Memory efficiency: Dramatic reduction in bytes per operation, from thousands to hundreds.
  • Overall, the changes provide substantial performance improvements while maintaining functionality.

v1.3.4

27 Nov 15:21
v1.3.4
14c9fa5

Choose a tag to compare

Changes

  • API: Internal parse function is now public as Parse.
  • Errors: Enhanced messages with specific types (e.g., ErrInvalidValue) and field-specific reporting.
  • Pointers: Always initialized; no longer reset to nil if unset, reducing overhead.
  • Caching: Introduced reflection caching to avoid repeated struct field operations.
  • Parsing: Optimized with direct switch on reflect.Kind for better performance.

Performance

Benchmark Results

Before:

goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
Benchmark/Small-8              91339      13457 ns/op      4720 B/op      111 allocs/op
Benchmark/Medium-8             69544      17252 ns/op      4784 B/op      113 allocs/op
Benchmark/Large-8              63728      18126 ns/op      5240 B/op      128 allocs/op
Benchmark/LargeWithDate-8      18294      67437 ns/op      36575 B/op     402 allocs/op

After:

goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
Benchmark/Small-8              224376     4602 ns/op       2680 B/op      13 allocs/op
Benchmark/Medium-8             246818     4851 ns/op       2720 B/op      13 allocs/op
Benchmark/Large-8              173422     5867 ns/op       3056 B/op      21 allocs/op
Benchmark/LargeWithDate-8      160401     6543 ns/op       3104 B/op      23 allocs/op

Performance Improvements

The refactored version delivers massive performance improvements across all benchmark scenarios:

  • Small: 2.5x faster (13,457ns → 4,602ns) with 94% fewer allocations (111 → 13)
  • Medium: 3.6x faster (17,252ns → 4,851ns) with 89% fewer allocations (113 → 13)
  • Large: 3.1x faster (18,126ns → 5,867ns) with 84% fewer allocations (128 → 21)
  • LargeWithDate: 10.3x faster (67,437ns → 6,543ns) with 94% fewer allocations (402 → 23)

Key optimizations driving these gains:

  1. Reflection Caching: Eliminated repeated struct field introspection by caching field metadata, reducing reflection overhead from O(n) to O(1) per struct type.

  2. Direct Type Switching: Replaced function lookups with a raw switch statement on reflect.Kind in setSingleValue, eliminating function call overhead and enabling compiler optimizations.

  3. Global Regex Optimization: Moved timezoneFixRegex from function-level to global scope, preventing regex recompilation on every date parse call - the primary driver of the 10x improvement in LargeWithDate benchmarks.

  4. Memory Efficiency: Reduced allocations by pre-allocating slices and reusing cached field information, cutting memory pressure by up to 94% in date-heavy scenarios.

  5. Pointer Optimization: Simplified pointer handling logic and eliminated unnecessary nil checks, streamlining the parsing path for pointer fields.

The most dramatic improvement comes in date parsing scenarios (LargeWithDate), where eliminating regex recompilation combined with caching and optimized type switching reduces parsing time from 67μs to just 6.5μs - a 10x speedup.

Full Changelog: v1.2.4...v1.3.4

v1.2.4

27 Nov 10:29
v1.2.4
7cf0aa8

Choose a tag to compare

Changes

  • Updated Go version to 1.24.5, used for development and benchmarks. No impact on consumers using older Go versions.
  • Added initial benchmark suite to evaluate performance of the library.

Notes

  • This release does not include breaking changes.

v1.2.3

04 Jul 14:07
v1.2.3
9d1bab0

Choose a tag to compare

🚀 New: time.Time Support

Added support for parsing time.Time, *time.Time, and their aliases.
Handles various standard formats including:

  • RFC3339, RFC3339Nano
  • Date-only (YYYY-MM-DD)
  • Time-only (HH:MM:SS)
  • With or without timezone offsets
  • Supports up to nanosecond precision

v1.2.0

18 Sep 07:44
v1.2.0
2817027

Choose a tag to compare

What's Changed

Repeated Keys Multiple Values Query

  • The parser now supports repeated keys for multiple values query parameters not only by comma-separated values but also by repeated keys. This allows for more flexibility in handling query parameters. It also supports a combination of both methods.

Full Changelog: v1.1.0...v1.2.0

v1.1.0

17 Sep 13:21
v1.1.0
29e9ebd

Choose a tag to compare

What's Changed

Pointer Fields Handling

  • Regular pointer fields and nested struct pointer fields now remain nil under the following conditions:
    • The field is not tagged.
    • The value for the related tag is not provided in the query parameters.
    • For nested struct pointers: All fields within the nested struct are zero/empty.

Slice behavior

  • Slices now remain nil if no corresponding values are provided in the query parameters.

Full Changelog: v1.0.0...v1.1.0

1.0.0

30 Jul 14:59
v1.0.0

Choose a tag to compare

Initial Release 🎉