Skip to content

Commit 69b1906

Browse files
authored
V30.0 changes (#213)
* chore: update gen files based on api spec * fix(conversational-model): update the response to expect a 201 on creation * fix(synonyms): remove old synonyms from collection interface * feat(synonyms): add synonym set interfaces * feat(client): register synonym sets to root client * chore: remove old synonym api interface * fix(test): update utils for synonyms to match new api * test(synonyms): test synonym sets api * feat(generator): recursively extract sub-types for schemas on api spec * feat(debug): add debug to client interface * chore: udpate gen files based on api spec * feat(analytics): migrate analytics to v30 refactor * feat(test): add util function to skip v30 tests on older versions * refactor(test): refactor synonym set tests to nested format * fix(test): update analytic helper methods to match v30 analytics api * fix(test): update analytics tests to v30 api * fix(test): remove synonymsets from expected collections under v30 * chore: lint * refactor(generator): improve code structure and fix deprecated usage - replace deprecated strings.title with golang.org/x/text/cases - extract complex nested logic into separate functions - reduce cyclomatic complexity by breaking down large functions - improve code readability and maintainability * chore: update gen files based on api spec * refactor(generator): break down main function to fix linter issues * chore: remove old overrides from v30 * feat(curation): add new curation sets api * feat: register curation sets to root level of the client object * feat(test): add db helper methods for new curations and remove old ones * test(curation): test new curation rules * fix(test): also check for non prefixed v versions * ci: upgrade typesense to v30 * chore: update generated client from api spec * fix: correct http status codes and endpoint validation in convo tests - add missing http.statuscreated header in conversation models test - fix endpoint comparison logic for urls with query strings * chore: lint * chore: add go-releaser
1 parent c55b9a3 commit 69b1906

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+8471
-4638
lines changed

.github/workflows/release.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v5
17+
with:
18+
fetch-depth: 0
19+
- name: Set up Go
20+
uses: actions/setup-go@v5
21+
with:
22+
go-version-file: go.mod
23+
24+
- name: Run GoReleaser
25+
uses: goreleaser/goreleaser-action@v6
26+
with:
27+
distribution: goreleaser
28+
version: "~> v2"
29+
args: release --clean
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/tests.yml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,26 @@ on:
1111
jobs:
1212
test:
1313
runs-on: ubuntu-latest
14-
services:
15-
typesense:
16-
image: typesense/typesense:28.0.rc35
17-
ports:
18-
- 8108:8108/tcp
19-
volumes:
20-
- /tmp/typesense-server-data:/data
21-
env:
22-
TYPESENSE_DATA_DIR: '/data'
23-
TYPESENSE_API_KEY: 'test_key'
24-
TYPESENSE_ENABLE_CORS: true
25-
TYPESENSE_URL: 'http://localhost:8108'
2614

2715
steps:
2816
- uses: actions/checkout@v4
2917

18+
- name: Start Typesense
19+
run: |
20+
docker run -d \
21+
-p 8108:8108 \
22+
--name typesense \
23+
-v /tmp/typesense-data:/data \
24+
-v /tmp/typesense-analytics-data:/analytics-data \
25+
typesense/typesense:30.0.alpha1 \
26+
--api-key=test_key \
27+
--data-dir=/data \
28+
--enable-search-analytics=true \
29+
--analytics-dir=/analytics-data \
30+
--analytics-flush-interval=60 \
31+
--analytics-minute-rate-limit=50 \
32+
--enable-cors
33+
3034
- name: Setup Go
3135
uses: actions/setup-go@v5
3236
with:

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
.idea
1+
.ideadist/

.goreleaser.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
2+
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
3+
4+
version: 2
5+
6+
builds: []
7+
8+
before:
9+
hooks:
10+
- go mod tidy
11+
- go generate ./...
12+
13+
builds:
14+
- env:
15+
- CGO_ENABLED=0
16+
goos:
17+
- linux
18+
- windows
19+
- darwin
20+
21+
archives:
22+
- formats: [tar.gz]
23+
# this name template makes the OS and Arch compatible with the results of `uname`.
24+
name_template: >-
25+
{{ .ProjectName }}_
26+
{{- title .Os }}_
27+
{{- if eq .Arch "amd64" }}x86_64
28+
{{- else if eq .Arch "386" }}i386
29+
{{- else }}{{ .Arch }}{{ end }}
30+
{{- if .Arm }}v{{ .Arm }}{{ end }}
31+
# use zip for windows archives
32+
format_overrides:
33+
- goos: windows
34+
formats: [zip]
35+
36+
changelog:
37+
sort: asc
38+
filters:
39+
exclude:
40+
- "^docs:"
41+
- "^test:"
42+
- "^chore:"
43+
44+
release:
45+
github:
46+
owner: typesense
47+
name: typesense-go
48+
mode: replace

typesense/analytics_events.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,32 @@ import (
77
)
88

99
type AnalyticsEventsInterface interface {
10-
Create(ctx context.Context, eventSchema *api.AnalyticsEventCreateSchema) (*api.AnalyticsEventCreateResponse, error)
10+
Create(ctx context.Context, eventSchema *api.AnalyticsEvent) (*api.AnalyticsEventCreateResponse, error)
11+
Retrieve(ctx context.Context, params *api.GetAnalyticsEventsParams) (*api.AnalyticsEventsResponse, error)
1112
}
1213

1314
type analyticsEvents struct {
1415
apiClient APIClientInterface
1516
}
1617

17-
func (a *analyticsEvents) Create(ctx context.Context, eventSchema *api.AnalyticsEventCreateSchema) (*api.AnalyticsEventCreateResponse, error) {
18+
func (a *analyticsEvents) Create(ctx context.Context, eventSchema *api.AnalyticsEvent) (*api.AnalyticsEventCreateResponse, error) {
1819
response, err := a.apiClient.CreateAnalyticsEventWithResponse(ctx, api.CreateAnalyticsEventJSONRequestBody(*eventSchema))
1920
if err != nil {
2021
return nil, err
2122
}
22-
if response.JSON201 == nil {
23+
if response.JSON200 == nil {
2324
return nil, &HTTPError{Status: response.StatusCode(), Body: response.Body}
2425
}
25-
return response.JSON201, nil
26+
return response.JSON200, nil
27+
}
28+
29+
func (a *analyticsEvents) Retrieve(ctx context.Context, params *api.GetAnalyticsEventsParams) (*api.AnalyticsEventsResponse, error) {
30+
response, err := a.apiClient.GetAnalyticsEventsWithResponse(ctx, params)
31+
if err != nil {
32+
return nil, err
33+
}
34+
if response.JSON200 == nil {
35+
return nil, &HTTPError{Status: response.StatusCode(), Body: response.Body}
36+
}
37+
return response.JSON200, nil
2638
}

typesense/analytics_events_test.go

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,117 @@ import (
1111
)
1212

1313
func TestAnalyticsEventsCreate(t *testing.T) {
14-
expectedData := &api.AnalyticsEventCreateSchema{
15-
Name: "products_click_event",
16-
Type: "click",
17-
Data: map[string]interface{}{
18-
"hello": "hi",
14+
eventData := &api.AnalyticsEvent{
15+
Name: "test_rule",
16+
EventType: "click",
17+
Data: struct {
18+
AnalyticsTag *string `json:"analytics_tag,omitempty"`
19+
DocId *string `json:"doc_id,omitempty"`
20+
DocIds *[]string `json:"doc_ids,omitempty"` //nolint:revive // matches API type
21+
Q *string `json:"q,omitempty"`
22+
UserId *string `json:"user_id,omitempty"`
23+
}{
24+
DocId: stringPtr("123"),
25+
UserId: stringPtr("user_123"),
1926
},
2027
}
2128

29+
expectedResponse := &api.AnalyticsEventCreateResponse{
30+
Ok: true,
31+
}
32+
2233
server, client := newTestServerAndClient(func(w http.ResponseWriter, r *http.Request) {
2334
validateRequestMetadata(t, r, "/analytics/events", http.MethodPost)
2435

25-
var reqBody api.AnalyticsEventCreateSchema
36+
var reqBody api.AnalyticsEvent
2637
err := json.NewDecoder(r.Body).Decode(&reqBody)
27-
2838
assert.NoError(t, err)
29-
assert.Equal(t, *expectedData, reqBody)
39+
assert.Equal(t, eventData.Name, reqBody.Name)
40+
assert.Equal(t, eventData.EventType, reqBody.EventType)
41+
42+
data := jsonEncode(t, expectedResponse)
43+
44+
w.Header().Set("Content-Type", "application/json")
45+
w.WriteHeader(http.StatusOK)
46+
w.Write(data)
47+
})
48+
defer server.Close()
49+
50+
res, err := client.Analytics().Events().Create(context.Background(), eventData)
51+
assert.NoError(t, err)
52+
assert.Equal(t, expectedResponse, res)
53+
}
54+
55+
func TestAnalyticsEventsRetrieve(t *testing.T) {
56+
params := &api.GetAnalyticsEventsParams{
57+
Name: "test_rule",
58+
UserId: "user_123",
59+
N: 10,
60+
}
3061

31-
data := jsonEncode(t, api.AnalyticsEventCreateResponse{
32-
Ok: true,
33-
})
62+
expectedResponse := &api.AnalyticsEventsResponse{
63+
Events: []struct {
64+
Collection *string `json:"collection,omitempty"`
65+
DocId *string `json:"doc_id,omitempty"`
66+
DocIds *[]string `json:"doc_ids,omitempty"` //nolint:revive // matches API type
67+
EventType *string `json:"event_type,omitempty"`
68+
Name *string `json:"name,omitempty"`
69+
Query *string `json:"query,omitempty"`
70+
Timestamp *int64 `json:"timestamp,omitempty"`
71+
UserId *string `json:"user_id,omitempty"`
72+
}{
73+
{
74+
Name: stringPtr("test_rule"),
75+
EventType: stringPtr("click"),
76+
DocId: stringPtr("123"),
77+
UserId: stringPtr("user_123"),
78+
},
79+
},
80+
}
81+
82+
server, client := newTestServerAndClient(func(w http.ResponseWriter, r *http.Request) {
83+
validateRequestMetadata(t, r, "/analytics/events", http.MethodGet)
84+
85+
// Check query parameters
86+
assert.Equal(t, "test_rule", r.URL.Query().Get("name"))
87+
assert.Equal(t, "user_123", r.URL.Query().Get("user_id"))
88+
assert.Equal(t, "10", r.URL.Query().Get("n"))
89+
90+
data := jsonEncode(t, expectedResponse)
3491

3592
w.Header().Set("Content-Type", "application/json")
36-
w.WriteHeader(http.StatusCreated)
3793
w.Write(data)
3894
})
3995
defer server.Close()
4096

41-
res, err := client.Analytics().Events().Create(context.Background(), expectedData)
97+
res, err := client.Analytics().Events().Retrieve(context.Background(), params)
4298
assert.NoError(t, err)
43-
assert.True(t, res.Ok)
99+
assert.Equal(t, expectedResponse, res)
44100
}
45101

46102
func TestAnalyticsEventsCreateOnHttpStatusErrorCodeReturnsError(t *testing.T) {
47103
server, client := newTestServerAndClient(func(w http.ResponseWriter, r *http.Request) {
48104
validateRequestMetadata(t, r, "/analytics/events", http.MethodPost)
49-
w.WriteHeader(http.StatusConflict)
105+
w.WriteHeader(http.StatusBadRequest)
106+
})
107+
defer server.Close()
108+
109+
_, err := client.Analytics().Events().Create(context.Background(), &api.AnalyticsEvent{})
110+
assert.ErrorContains(t, err, "status: 400")
111+
}
112+
113+
func TestAnalyticsEventsRetrieveOnHttpStatusErrorCodeReturnsError(t *testing.T) {
114+
server, client := newTestServerAndClient(func(w http.ResponseWriter, r *http.Request) {
115+
validateRequestMetadata(t, r, "/analytics/events", http.MethodGet)
116+
w.WriteHeader(http.StatusInternalServerError)
50117
})
51118
defer server.Close()
52119

53-
_, err := client.Analytics().Events().Create(context.Background(), &api.AnalyticsEventCreateSchema{})
54-
assert.ErrorContains(t, err, "status: 409")
120+
_, err := client.Analytics().Events().Retrieve(context.Background(), &api.GetAnalyticsEventsParams{})
121+
assert.ErrorContains(t, err, "status: 500")
122+
}
123+
124+
// Helper function to create string pointers
125+
func stringPtr(s string) *string {
126+
return &s
55127
}

typesense/analytics_rule.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import (
77
)
88

99
type AnalyticsRuleInterface interface {
10-
Delete(ctx context.Context) (*api.AnalyticsRuleDeleteResponse, error)
11-
Retrieve(ctx context.Context) (*api.AnalyticsRuleSchema, error)
10+
Delete(ctx context.Context) (*api.AnalyticsRule, error)
11+
Retrieve(ctx context.Context) (*api.AnalyticsRule, error)
12+
Update(ctx context.Context, ruleSchema *api.AnalyticsRuleUpdate) (*api.AnalyticsRule, error)
1213
}
1314

1415
type analyticsRule struct {
1516
apiClient APIClientInterface
1617
ruleName string
1718
}
1819

19-
func (a *analyticsRule) Delete(ctx context.Context) (*api.AnalyticsRuleDeleteResponse, error) {
20+
func (a *analyticsRule) Delete(ctx context.Context) (*api.AnalyticsRule, error) {
2021
response, err := a.apiClient.DeleteAnalyticsRuleWithResponse(ctx, a.ruleName)
2122
if err != nil {
2223
return nil, err
@@ -27,7 +28,7 @@ func (a *analyticsRule) Delete(ctx context.Context) (*api.AnalyticsRuleDeleteRes
2728
return response.JSON200, nil
2829
}
2930

30-
func (a *analyticsRule) Retrieve(ctx context.Context) (*api.AnalyticsRuleSchema, error) {
31+
func (a *analyticsRule) Retrieve(ctx context.Context) (*api.AnalyticsRule, error) {
3132
response, err := a.apiClient.RetrieveAnalyticsRuleWithResponse(ctx, a.ruleName)
3233
if err != nil {
3334
return nil, err
@@ -37,3 +38,14 @@ func (a *analyticsRule) Retrieve(ctx context.Context) (*api.AnalyticsRuleSchema,
3738
}
3839
return response.JSON200, nil
3940
}
41+
42+
func (a *analyticsRule) Update(ctx context.Context, ruleSchema *api.AnalyticsRuleUpdate) (*api.AnalyticsRule, error) {
43+
response, err := a.apiClient.UpsertAnalyticsRuleWithResponse(ctx, a.ruleName, api.UpsertAnalyticsRuleJSONRequestBody(*ruleSchema))
44+
if err != nil {
45+
return nil, err
46+
}
47+
if response.JSON200 == nil {
48+
return nil, &HTTPError{Status: response.StatusCode(), Body: response.Body}
49+
}
50+
return response.JSON200, nil
51+
}

typesense/analytics_rule_test.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import (
1111
)
1212

1313
func TestAnalyticsRuleRetrieve(t *testing.T) {
14-
expectedData := &api.AnalyticsRuleSchema{
15-
Name: "test_rule",
16-
Type: "test_type",
17-
Params: api.AnalyticsRuleParameters{
18-
Limit: pointer.Int(10),
14+
expectedData := &api.AnalyticsRule{
15+
Name: "test_rule",
16+
Type: api.AnalyticsRuleTypeCounter,
17+
Collection: "test_collection",
18+
EventType: "click",
19+
Params: &api.AnalyticsRuleCreateParams{
20+
CounterField: pointer.String("popularity"),
21+
Weight: pointer.Int(10),
1922
},
2023
}
2124

@@ -45,7 +48,7 @@ func TestAnalyticsRuleRetrieveOnHttpStatusErrorCodeReturnsError(t *testing.T) {
4548
}
4649

4750
func TestAnalyticsRuleDelete(t *testing.T) {
48-
expectedData := &api.AnalyticsRuleDeleteResponse{
51+
expectedData := &api.AnalyticsRule{
4952
Name: "test_rule",
5053
}
5154

@@ -63,7 +66,7 @@ func TestAnalyticsRuleDelete(t *testing.T) {
6366
assert.Equal(t, expectedData, res)
6467
}
6568

66-
func TestAnalyticsRuleUpsertOnHttpStatusErrorCodeReturnsError(t *testing.T) {
69+
func TestAnalyticsRuleDeleteOnHttpStatusErrorCodeReturnsError(t *testing.T) {
6770
server, client := newTestServerAndClient(func(w http.ResponseWriter, r *http.Request) {
6871
validateRequestMetadata(t, r, "/analytics/rules/test_rule", http.MethodDelete)
6972
w.WriteHeader(http.StatusConflict)

0 commit comments

Comments
 (0)