Skip to content

Commit c5ea264

Browse files
authored
Merge pull request #1 from spacemagneto/develop
json compression implement library v1
2 parents 13013e9 + 9cd083f commit c5ea264

20 files changed

Lines changed: 1240 additions & 1 deletion

.github/workflows/go.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Test
2+
on: [push, pull_request]
3+
4+
jobs:
5+
lint:
6+
name: Lint
7+
runs-on: ubuntu-latest
8+
timeout-minutes: 5
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v4
12+
with:
13+
fetch-depth: 0 # Required for golangci-lint to analyze changes
14+
15+
- name: Set up Go
16+
uses: actions/setup-go@v5
17+
with:
18+
go-version: '1.24.x' # Match test-cache for consistency
19+
cache: true # Cache Go modules
20+
21+
- name: Run golangci-lint
22+
uses: golangci/golangci-lint-action@v8
23+
with:
24+
version: v2.1.6 # Latest stable v2 release as of May 2025
25+
only-new-issues: true # Show only new issues on PRs
26+
27+
test-nocache:
28+
name: Test (No Cache)
29+
strategy:
30+
matrix:
31+
go-version: [1.23.x, 1.24.x]
32+
os: [ubuntu-latest, macos-latest, windows-latest]
33+
runs-on: ${{ matrix.os }}
34+
steps:
35+
- uses: actions/checkout@v4
36+
- uses: actions/setup-go@v5
37+
with:
38+
go-version: ${{ matrix.go-version }}
39+
cache: false
40+
- run: go test ./...

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ go.work.sum
3030
# Editor/IDE
3131
.idea/
3232
.vscode/
33+
34+
/setup.sh

.golangci.yaml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
version: "2"
2+
run:
3+
concurrency: 4
4+
modules-download-mode: readonly
5+
issues-exit-code: 1
6+
tests: false
7+
allow-parallel-runners: false
8+
linters:
9+
enable:
10+
- asasalint
11+
- asciicheck
12+
- bidichk
13+
- bodyclose
14+
- contextcheck
15+
- copyloopvar
16+
- dupl
17+
- durationcheck
18+
- errname
19+
- errorlint
20+
- gocritic
21+
- gocyclo
22+
- gosec
23+
- misspell
24+
- nakedret
25+
- nilerr
26+
- nilnil
27+
- noctx
28+
- prealloc
29+
- reassign
30+
- revive
31+
- staticcheck
32+
- unconvert
33+
- unparam
34+
- usestdlibvars
35+
- wastedassign
36+
settings:
37+
copyloopvar:
38+
check-alias: true
39+
dupl:
40+
threshold: 300
41+
gocritic:
42+
disabled-checks:
43+
- hugeParam
44+
- rangeExprCopy
45+
- rangeValCopy
46+
enabled-tags:
47+
- diagnostic
48+
- experimental
49+
- opinionated
50+
- performance
51+
- style
52+
gosec:
53+
excludes:
54+
- G114
55+
- G115
56+
- G301
57+
misspell:
58+
locale: US
59+
revive:
60+
confidence: 0.8
61+
severity: warning
62+
rules:
63+
- name: exported
64+
disabled: true
65+
- name: package-comments
66+
severity: warning
67+
disabled: true
68+
- name: exported
69+
arguments:
70+
- checkPrivateReceivers
71+
- disableStutteringCheck
72+
severity: warning
73+
disabled: false
74+
exclusions:
75+
generated: lax
76+
rules:
77+
- linters:
78+
- staticcheck
79+
text: at least one file in a package should have a package comment
80+
- linters:
81+
- dupl
82+
- gosec
83+
path: _test\.go
84+
paths:
85+
- vendor
86+
- test
87+
- e2e
88+
- docker
89+
- third_party$
90+
- builtin$
91+
- examples$
92+
issues:
93+
max-issues-per-linter: 0
94+
max-same-issues: 0
95+
uniq-by-line: false
96+
new: false
97+
fix: false
98+
formatters:
99+
enable:
100+
- gofmt
101+
- gofumpt
102+
- goimports
103+
settings:
104+
goimports:
105+
local-prefixes:
106+
- github.com/spacemagneto/go-cache
107+
exclusions:
108+
generated: lax
109+
paths:
110+
- vendor
111+
- test
112+
- e2e
113+
- docker
114+
- third_party$
115+
- builtin$
116+
- examples$

.mockery.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
packages:
2+
github.com/spacemagneto/compressjson:
3+
config:
4+
dir: "{{.InterfaceDir}}"
5+
filename: "mocks/mocks.go"
6+
structname: "{{.Mock}}{{.InterfaceName}}"
7+
interfaces:
8+
Transcoder:
9+
config:

Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This Makefile defines common tasks for a Go project, including linting the code,
2+
# running tests, and generating mocks using mockery.
3+
4+
# Target: lint
5+
# Description: Run the Go linter using golangci-lint.
6+
# This checks the code for stylistic issues, potential bugs, and other improvements.
7+
lint: ## Run linter
8+
golangci-lint run
9+
10+
# Target: test
11+
# Description: Run all tests in the project.
12+
# The -v flag makes the test output verbose, showing detailed information about each test.
13+
test: ## Run tests
14+
go test -v ./...
15+
16+
# Target: generate
17+
# Description: Generate code, particularly mocks using mockery.
18+
# If mockery is not installed, this will install it first, and then run go generate.
19+
generate: ## Generate mocks
20+
# Check if mockery is installed. If not, install it.
21+
ifeq (, $(shell which mockery))
22+
go install github.com/vektra/mockery
23+
endif
24+
# Run go generate to trigger code generation in the project.
25+
mockery

README.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,71 @@
1-
# compressjson
1+
# compressjson: High-Performance JSON Transcoder (Zstd + Base64)
2+
3+
## Overview
4+
5+
The compressjson library provides a high-throughput, type-safe solution for converting Go structs to a compact, text-safe string representation and vice-versa.
6+
This tool is designed for low-latency, high-throughput scenarios and is ideal for:
7+
1. High-Speed Caching (e.g., Redis, Memcached) where decompression speed is critical for read latency.
8+
2. Storage Optimization for large JSON objects in databases.
9+
3. Efficient Data Transfer in high-load, distributed systems.
10+
11+
12+
## Operating Pipeline
13+
### The encode/decode process is an optimized three-stage chain:
14+
15+
| Step | Operation | Library / Settings | Purpose |
16+
|------|------------------|----------------------------------------|---------------------------------------------------|
17+
| 1 | Serialization | `goccy/go-json` | Ultra-fast conversion of Go structs ↔ bytes |
18+
| 2 | Compression | `klauspost/compress/zstd` <br> `SpeedFastest` | Maximum compression/decompression speed |
19+
| 3 | Encoding | `encoding/base64` (std lib) | Convert binary data to transport-safe ASCII string |
20+
21+
22+
# Usage
23+
### Installation
24+
```bash
25+
go get github.com/spacemagneto/compressjson
26+
```
27+
28+
## Example Code
29+
30+
```go
31+
package main
32+
33+
import (
34+
"log"
35+
36+
"github.com/spacemagneto/compressjson"
37+
)
38+
39+
type User struct {
40+
ID int `json:"id"`
41+
Name string `json:"name"`
42+
Role string `json:"role"`
43+
}
44+
45+
func main() {
46+
transcoder := compressjson.NewTranscoder[[]User]()
47+
48+
users := []User{
49+
{ID: 1, Name: "Alice", Role: "admin"},
50+
{ID: 2, Name: "Bob", Role: "user"},
51+
{ID: 3, Name: "Charlie", Role: "moderator"},
52+
}
53+
54+
encoded, err := transcoder.Encode(users)
55+
if err != nil {
56+
log.Fatalf("encode failed: %v", err)
57+
}
58+
59+
var decoded []User
60+
decoded, err = transcoder.Decode(encoded)
61+
if err != nil {
62+
log.Fatalf("decode failed: %v", err)
63+
}
64+
65+
...
66+
}
67+
```
68+
69+
### Testing Support
70+
71+
For users integrating and testing compressjson in various scenarios (e.g., handling specific errors, simulating compression/decompression outcomes), the repository includes a dedicated transcoder mock pkg that provides the MockTranscoder implementation. This facilitates robust unit testing and integration testing without requiring actual Zstd operations.

compressjson.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package compressjson
2+
3+
// Transcoder defines a generic interface for bidirectional conversion between
4+
// a value of type T and its string representation.
5+
//
6+
// Implementations may perform serialization, compression, encryption, encoding,
7+
// or any combination thereof — the interface makes no assumptions about the
8+
// internal steps. The only requirements are type safety, correct round-trip behavior
9+
// when possible, and proper resource cleanup via Close.
10+
type Transcoder[T any] interface {
11+
// Encode converts a value of type T into a string.
12+
// The resulting string should be safe for storage or transmission.
13+
Encode(T) (string, error)
14+
15+
// Decode reconstructs a value of type T from a string previously produced by Encode.
16+
// Returns the zero value of T and an error if decoding fails.
17+
Decode(string) (T, error)
18+
}

go.mod

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module github.com/spacemagneto/compressjson
2+
3+
go 1.24.7
4+
5+
require (
6+
github.com/davecgh/go-spew v1.1.1 // indirect
7+
github.com/goccy/go-json v0.10.5 // indirect
8+
github.com/klauspost/compress v1.18.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
github.com/stretchr/objx v0.5.2 // indirect
11+
github.com/stretchr/testify v1.11.1 // indirect
12+
gopkg.in/yaml.v3 v3.0.1 // indirect
13+
)

go.sum

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
4+
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
5+
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
6+
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
7+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
9+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
10+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
11+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
12+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
13+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
14+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
15+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

lib/base64.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package lib
2+
3+
import "encoding/base64"
4+
5+
// Base64Transcoder provides a straightforward implementation of Base64 encoding and decoding
6+
// using Go's standard library encoding/base64 package with the standard padding rules (RFC 4648).
7+
type Base64Transcoder struct{}
8+
9+
// NewBase64Transcoder creates and returns a new instance of Base64Transcoder.
10+
// The returned object has no internal state and can be safely shared across the application.
11+
// It is provided as a constructor to maintain a consistent creation pattern with other transcoder types.
12+
func NewBase64Transcoder() *Base64Transcoder {
13+
return &Base64Transcoder{}
14+
}
15+
16+
// Encode converts the given byte slice into a Base64-encoded string using the standard encoding.
17+
// The result includes padding characters (=) when necessary to comply with RFC 4648.
18+
// No error is ever returned because the standard encoding is guaranteed to succeed for any input
19+
func (t *Base64Transcoder) Encode(src []byte) (string, error) {
20+
return base64.StdEncoding.EncodeToString(src), nil
21+
}
22+
23+
// Decode converts a Base64-encoded string back into its original byte representation.
24+
// It accepts both padded and un-padded input (the standard decoder is tolerant of missing padding).
25+
// If the input contains invalid characters or incorrect padding, a non-nil error is returned.
26+
func (t *Base64Transcoder) Decode(src string) ([]byte, error) {
27+
return base64.StdEncoding.DecodeString(src)
28+
}

0 commit comments

Comments
 (0)