Skip to content

Commit 7d79533

Browse files
authored
Merge pull request #1282 from tigrisdata/main
Beta release
2 parents e326f3a + f1cea7f commit 7d79533

File tree

6 files changed

+50
-15
lines changed

6 files changed

+50
-15
lines changed

api/server/v1/tx.go

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const (
5858
ListProjectsMethodName = apiMethodPrefix + "ListProjects"
5959
ListCollectionsMethodName = apiMethodPrefix + "ListCollections"
6060
CreateProjectMethodName = apiMethodPrefix + "CreateProject"
61+
UpdateProjectMethodName = apiMethodPrefix + "UpdateProject"
6162

6263
DeleteProjectMethodName = apiMethodPrefix + "DeleteProject"
6364
DescribeDatabaseMethodName = apiMethodPrefix + "DescribeDatabase"

schema/search.go

+37-11
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,22 @@ type SearchSource struct {
6161
}
6262

6363
type SearchJSONSchema struct {
64-
Name string `json:"title,omitempty"`
65-
Description string `json:"description,omitempty"`
66-
Properties jsoniter.RawMessage `json:"properties,omitempty"`
67-
Source *SearchSource `json:"source,omitempty"`
64+
Name string `json:"title,omitempty"`
65+
Description string `json:"description,omitempty"`
66+
Properties jsoniter.RawMessage `json:"properties,omitempty"`
67+
Source *SearchSource `json:"source,omitempty"`
68+
Options *SearchSchemaOptions `json:"options,omitempty"`
69+
}
70+
71+
type SearchSchemaOptions struct {
72+
TokenSeparators *[]string `json:"token_separators,omitempty"`
73+
}
74+
75+
func (s *SearchSchemaOptions) GetTokenSeparators() []string {
76+
if s.TokenSeparators == nil {
77+
return make([]string, 0)
78+
}
79+
return *s.TokenSeparators
6880
}
6981

7082
// SearchFactory is used as an intermediate step so that collection can be initialized with properly encoded values.
@@ -74,9 +86,10 @@ type SearchFactory struct {
7486
// Fields are derived from the user schema.
7587
Fields []*Field
7688
// Schema is the raw JSON schema received
77-
Schema jsoniter.RawMessage
78-
Sub string
79-
Source SearchSource
89+
Schema jsoniter.RawMessage
90+
Sub string
91+
Source SearchSource
92+
Options SearchSchemaOptions
8093
}
8194

8295
func (fb *FactoryBuilder) BuildSearch(index string, reqSchema jsoniter.RawMessage) (*SearchFactory, error) {
@@ -120,12 +133,17 @@ func (fb *FactoryBuilder) BuildSearch(index string, reqSchema jsoniter.RawMessag
120133
return nil, err
121134
}
122135
}
136+
var schemaOptions SearchSchemaOptions
137+
if schema.Options != nil {
138+
schemaOptions = *schema.Options
139+
}
123140

124141
factory := &SearchFactory{
125-
Name: index,
126-
Fields: fields,
127-
Schema: searchSchema,
128-
Source: source,
142+
Name: index,
143+
Fields: fields,
144+
Schema: searchSchema,
145+
Source: source,
146+
Options: schemaOptions,
129147
}
130148

131149
idFound := false
@@ -181,6 +199,9 @@ type SearchIndex struct {
181199
// will be one to one mapped to queryable field but complex fields like object type field there may be more than
182200
// one queryableFields. As queryableFields represent a flattened state these can be used as-is to index in memory.
183201
QueryableFields []*QueryableField
202+
// TokenSeparators is a list of symbols or special characters to be used for splitting the text into individual
203+
// words in addition to space and new-line characters.
204+
TokenSeparators []string
184205
// Source of this index
185206
Source SearchSource
186207
SearchIDField *QueryableField
@@ -198,12 +219,14 @@ func NewSearchIndex(ver uint32, searchStoreName string, factory *SearchFactory,
198219
searchIdField = q
199220
}
200221
}
222+
201223
index := &SearchIndex{
202224
Version: ver,
203225
Name: factory.Name,
204226
Fields: factory.Fields,
205227
Schema: factory.Schema,
206228
Source: factory.Source,
229+
TokenSeparators: factory.Options.GetTokenSeparators(),
207230
SearchIDField: searchIdField,
208231
QueryableFields: queryableFields,
209232
int64FieldsPath: buildInt64Path(factory.Fields),
@@ -330,6 +353,9 @@ func (s *SearchIndex) buildSearchSchema(name string) {
330353
Name: name,
331354
Fields: tsFields,
332355
}
356+
if len(s.TokenSeparators) > 0 {
357+
s.StoreSchema.TokenSeparators = &s.TokenSeparators
358+
}
333359
}
334360

335361
func (s *SearchIndex) GetSearchDeltaFields(existingFields []*QueryableField, fieldsInSearch []tsApi.Field) []tsApi.Field {

server/config/options.go

-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,6 @@ var DefaultConfig = Config{
388388
Compression: false,
389389
IgnoreExtraFields: false,
390390
LogFilter: false,
391-
AuthKey: "ts_test_key",
392391
},
393392
KV: KVConfig{
394393
Chunking: false,

server/metadata/tenant.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -862,13 +862,16 @@ func (tenant *Tenant) CreateSearchIndex(ctx context.Context, tx transaction.Tx,
862862

863863
func (tenant *Tenant) createSearchIndex(ctx context.Context, tx transaction.Tx, project *Project, factory *schema.SearchFactory) error {
864864
if index, ok := project.search.GetIndex(factory.Name); ok {
865-
if eq, err := isSchemaEq(index.Schema, factory.Schema); eq || err != nil {
866-
// shortcut to just check if schema is eq then return early
865+
if tokensEq := reflect.DeepEqual(factory.Options.GetTokenSeparators(), index.TokenSeparators); !tokensEq {
866+
return errors.InvalidArgument("`token_separators` cannot be modified, please create a new search index")
867+
}
867868

869+
// shortcut to just check if there aren't any changes then return early
870+
if eq, err := isSchemaEq(index.Schema, factory.Schema); eq || err != nil {
868871
tx.Context().MarkNoMetadataStateChanged()
869-
870872
return err
871873
}
874+
// Tokens can only be set when schema is created, if tokens changed, then raise an informative error here
872875
return tenant.updateSearchIndex(ctx, tx, project, factory, index)
873876
}
874877

server/middleware/authz.go

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ var (
102102
api.ListProjectsMethodName,
103103
api.ListCollectionsMethodName,
104104
api.CreateProjectMethodName,
105+
api.UpdateProjectMethodName,
105106
api.DeleteProjectMethodName,
106107
api.DescribeDatabaseMethodName,
107108
api.DescribeCollectionMethodName,
@@ -194,6 +195,7 @@ var (
194195
api.ListProjectsMethodName,
195196
api.ListCollectionsMethodName,
196197
api.CreateProjectMethodName,
198+
api.UpdateProjectMethodName,
197199
api.DeleteProjectMethodName,
198200
api.DescribeDatabaseMethodName,
199201
api.DescribeCollectionMethodName,
@@ -293,6 +295,7 @@ var (
293295
api.ListProjectsMethodName,
294296
api.ListCollectionsMethodName,
295297
api.CreateProjectMethodName,
298+
api.UpdateProjectMethodName,
296299
api.DeleteProjectMethodName,
297300
api.DescribeDatabaseMethodName,
298301
api.DescribeCollectionMethodName,

server/middleware/authz_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func TestAuthzOwnerRole(t *testing.T) {
4040
require.True(t, isAuthorizedOperation(api.CreateOrUpdateCollectionsMethodName, auth.OwnerRoleName))
4141
require.True(t, isAuthorizedOperation(api.DropCollectionMethodName, auth.OwnerRoleName))
4242
require.True(t, isAuthorizedOperation(api.ListProjectsMethodName, auth.OwnerRoleName))
43+
require.True(t, isAuthorizedOperation(api.UpdateProjectMethodName, auth.OwnerRoleName))
4344
require.True(t, isAuthorizedOperation(api.ListCollectionsMethodName, auth.OwnerRoleName))
4445
require.True(t, isAuthorizedOperation(api.CreateProjectMethodName, auth.OwnerRoleName))
4546
require.True(t, isAuthorizedOperation(api.DeleteProjectMethodName, auth.OwnerRoleName))
@@ -149,6 +150,7 @@ func TestAuthzEditorRole(t *testing.T) {
149150
require.True(t, isAuthorizedOperation(api.ListProjectsMethodName, auth.EditorRoleName))
150151
require.True(t, isAuthorizedOperation(api.ListCollectionsMethodName, auth.EditorRoleName))
151152
require.True(t, isAuthorizedOperation(api.CreateProjectMethodName, auth.EditorRoleName))
153+
require.True(t, isAuthorizedOperation(api.UpdateProjectMethodName, auth.EditorRoleName))
152154
require.True(t, isAuthorizedOperation(api.DeleteProjectMethodName, auth.EditorRoleName))
153155
require.True(t, isAuthorizedOperation(api.DescribeDatabaseMethodName, auth.EditorRoleName))
154156
require.True(t, isAuthorizedOperation(api.DescribeCollectionMethodName, auth.EditorRoleName))
@@ -285,6 +287,7 @@ func TestAuthzReadOnlyRole(t *testing.T) {
285287
require.False(t, isAuthorizedOperation(api.UpdateMethodName, auth.ReadOnlyRoleName))
286288
require.False(t, isAuthorizedOperation(api.DeleteMethodName, auth.ReadOnlyRoleName))
287289
require.False(t, isAuthorizedOperation(api.CreateProjectMethodName, auth.ReadOnlyRoleName))
290+
require.False(t, isAuthorizedOperation(api.UpdateProjectMethodName, auth.ReadOnlyRoleName))
288291
require.False(t, isAuthorizedOperation(api.CreateOrUpdateCollectionMethodName, auth.ReadOnlyRoleName))
289292
require.False(t, isAuthorizedOperation(api.CreateOrUpdateCollectionsMethodName, auth.ReadOnlyRoleName))
290293
require.False(t, isAuthorizedOperation(api.DeleteProjectMethodName, auth.ReadOnlyRoleName))

0 commit comments

Comments
 (0)