feat(mc): Add dynamic filter options endpoint for model catalog (#1727)
* feat: generate server and client files only Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: add support for catalog dynamic catalog filtering Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: catalog test fix Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: add tests for filter options Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: remove duplicate filterQuery parameter and regenerate OpenAPI files Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: check range bug Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: add filter options and fix openapi spec conflicts Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: add filteroptionrange Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: gitattributes file Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: regenerate OpenAPI code and remove stale converter files Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix(catalog): regenerate files And fix badly generated openapi code. Signed-off-by: Paul Boyd <paul@pboyd.io> * Update api/openapi/src/catalog.yaml Co-authored-by: Paul Boyd <paul@pboyd.io> Signed-off-by: Sidney Glinton <sglinton@redhat.com> * Update api/openapi/src/catalog.yaml Co-authored-by: Paul Boyd <paul@pboyd.io> Signed-off-by: Sidney Glinton <sglinton@redhat.com> * Update api/openapi/src/catalog.yaml Co-authored-by: Paul Boyd <paul@pboyd.io> Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: pr feedback changes Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: regen files Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: build and remove sourceLabel fields Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: regen on openapi gen 7.13.0 Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: regen openapi files after rebase Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: build and tests and rebase Signed-off-by: Sidney Glinton <sglinton@redhat.com> * Update catalog/internal/server/openapi/api_model_catalog_service_service_test.go Co-authored-by: Paul Boyd <paul@pboyd.io> Signed-off-by: Sidney Glinton <sglinton@redhat.com> * fix: revert logic on older refactor Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: regen files Signed-off-by: Sidney Glinton <sglinton@redhat.com> * feat: regen catalog Signed-off-by: Sidney Glinton <sglinton@redhat.com> --------- Signed-off-by: Sidney Glinton <sglinton@redhat.com> Signed-off-by: Paul Boyd <paul@pboyd.io> Co-authored-by: Paul Boyd <paul@pboyd.io>
This commit is contained in:
parent
ceaf413d44
commit
f61929fbae
|
|
@ -20,6 +20,9 @@ catalog/pkg/openapi/model_catalog_model_list.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_catalog_source.go linguist-generated=true
|
catalog/pkg/openapi/model_catalog_source.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_catalog_source_list.go linguist-generated=true
|
catalog/pkg/openapi/model_catalog_source_list.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_error.go linguist-generated=true
|
catalog/pkg/openapi/model_error.go linguist-generated=true
|
||||||
|
catalog/pkg/openapi/model_filter_option.go linguist-generated=true
|
||||||
|
catalog/pkg/openapi/model_filter_option_range.go linguist-generated=true
|
||||||
|
catalog/pkg/openapi/model_filter_options_list.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_metadata_bool_value.go linguist-generated=true
|
catalog/pkg/openapi/model_metadata_bool_value.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_metadata_double_value.go linguist-generated=true
|
catalog/pkg/openapi/model_metadata_double_value.go linguist-generated=true
|
||||||
catalog/pkg/openapi/model_metadata_int_value.go linguist-generated=true
|
catalog/pkg/openapi/model_metadata_int_value.go linguist-generated=true
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,22 @@ paths:
|
||||||
"500":
|
"500":
|
||||||
$ref: "#/components/responses/InternalServerError"
|
$ref: "#/components/responses/InternalServerError"
|
||||||
operationId: findModels
|
operationId: findModels
|
||||||
|
/api/model_catalog/v1alpha1/models/filter_options:
|
||||||
|
description: Lists options for `filterQuery` when listing models.
|
||||||
|
get:
|
||||||
|
summary: Lists fields and available options that can be used in `filterQuery` on the list models endpoint.
|
||||||
|
tags:
|
||||||
|
- ModelCatalogService
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: "#/components/responses/FilterOptionsResponse"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/InternalServerError"
|
||||||
|
operationId: findModelsFilterOptions
|
||||||
/api/model_catalog/v1alpha1/sources:
|
/api/model_catalog/v1alpha1/sources:
|
||||||
summary: Path used to get the list of catalog sources.
|
summary: Path used to get the list of catalog sources.
|
||||||
description: >-
|
description: >-
|
||||||
|
|
@ -434,6 +450,40 @@ components:
|
||||||
message:
|
message:
|
||||||
description: Error message
|
description: Error message
|
||||||
type: string
|
type: string
|
||||||
|
FilterOption:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The data type of the filter option
|
||||||
|
enum:
|
||||||
|
- string
|
||||||
|
- number
|
||||||
|
values:
|
||||||
|
type: array
|
||||||
|
description: Known values of the property for string types with a small number of possible options.
|
||||||
|
items: {}
|
||||||
|
range:
|
||||||
|
$ref: "#/components/schemas/FilterOptionRange"
|
||||||
|
FilterOptionRange:
|
||||||
|
type: object
|
||||||
|
description: Min and max values for number types.
|
||||||
|
properties:
|
||||||
|
min:
|
||||||
|
type: number
|
||||||
|
max:
|
||||||
|
type: number
|
||||||
|
FilterOptionsList:
|
||||||
|
description: List of FilterOptions
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
filters:
|
||||||
|
type: object
|
||||||
|
description: A single filter option.
|
||||||
|
additionalProperties:
|
||||||
|
$ref: "#/components/schemas/FilterOption"
|
||||||
MetadataBoolValue:
|
MetadataBoolValue:
|
||||||
description: A bool property value.
|
description: A bool property value.
|
||||||
type: object
|
type: object
|
||||||
|
|
@ -598,6 +648,12 @@ components:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Error"
|
$ref: "#/components/schemas/Error"
|
||||||
description: Conflict with current state of target resource
|
description: Conflict with current state of target resource
|
||||||
|
FilterOptionsResponse:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/FilterOptionsList"
|
||||||
|
description: A response containing options for a `filterQuery` parameter.
|
||||||
InternalServerError:
|
InternalServerError:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,22 @@ paths:
|
||||||
"500":
|
"500":
|
||||||
$ref: "#/components/responses/InternalServerError"
|
$ref: "#/components/responses/InternalServerError"
|
||||||
operationId: findModels
|
operationId: findModels
|
||||||
|
/api/model_catalog/v1alpha1/models/filter_options:
|
||||||
|
description: Lists options for `filterQuery` when listing models.
|
||||||
|
get:
|
||||||
|
summary: Lists fields and available options that can be used in `filterQuery` on the list models endpoint.
|
||||||
|
tags:
|
||||||
|
- ModelCatalogService
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: "#/components/responses/FilterOptionsResponse"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/InternalServerError"
|
||||||
|
operationId: findModelsFilterOptions
|
||||||
/api/model_catalog/v1alpha1/sources:
|
/api/model_catalog/v1alpha1/sources:
|
||||||
summary: Path used to get the list of catalog sources.
|
summary: Path used to get the list of catalog sources.
|
||||||
description: >-
|
description: >-
|
||||||
|
|
@ -295,6 +311,40 @@ components:
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/CatalogSource"
|
$ref: "#/components/schemas/CatalogSource"
|
||||||
- $ref: "#/components/schemas/BaseResourceList"
|
- $ref: "#/components/schemas/BaseResourceList"
|
||||||
|
FilterOption:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The data type of the filter option
|
||||||
|
enum:
|
||||||
|
- string
|
||||||
|
- number
|
||||||
|
values:
|
||||||
|
type: array
|
||||||
|
description: Known values of the property for string types with a small number of possible options.
|
||||||
|
items: {}
|
||||||
|
range:
|
||||||
|
$ref: "#/components/schemas/FilterOptionRange"
|
||||||
|
FilterOptionRange:
|
||||||
|
type: object
|
||||||
|
description: Min and max values for number types.
|
||||||
|
properties:
|
||||||
|
min:
|
||||||
|
type: number
|
||||||
|
max:
|
||||||
|
type: number
|
||||||
|
FilterOptionsList:
|
||||||
|
description: List of FilterOptions
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
filters:
|
||||||
|
type: object
|
||||||
|
description: A single filter option.
|
||||||
|
additionalProperties:
|
||||||
|
$ref: "#/components/schemas/FilterOption"
|
||||||
OrderByField:
|
OrderByField:
|
||||||
description: Supported fields for ordering result entities.
|
description: Supported fields for ordering result entities.
|
||||||
enum:
|
enum:
|
||||||
|
|
@ -335,6 +385,12 @@ components:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/CatalogSource"
|
$ref: "#/components/schemas/CatalogSource"
|
||||||
description: A response containing a `CatalogSource` entity.
|
description: A response containing a `CatalogSource` entity.
|
||||||
|
FilterOptionsResponse:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/FilterOptionsList"
|
||||||
|
description: A response containing options for a `filterQuery` parameter.
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
orderBy:
|
orderBy:
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,8 @@ type APIProvider interface {
|
||||||
// model is found with that name, it returns nil. If the model is
|
// model is found with that name, it returns nil. If the model is
|
||||||
// found, but has no artifacts, an empty list is returned.
|
// found, but has no artifacts, an empty list is returned.
|
||||||
GetArtifacts(ctx context.Context, modelName string, sourceID string, params ListArtifactsParams) (model.CatalogArtifactList, error)
|
GetArtifacts(ctx context.Context, modelName string, sourceID string, params ListArtifactsParams) (model.CatalogArtifactList, error)
|
||||||
|
|
||||||
|
// GetFilterOptions returns all available filter options for models.
|
||||||
|
// This includes field names, data types, and available values or ranges.
|
||||||
|
GetFilterOptions(ctx context.Context) (*model.FilterOptionsList, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,10 @@ func (m *MockCatalogModelRepository) Save(model dbmodels.CatalogModel) (dbmodels
|
||||||
return savedModel, nil
|
return savedModel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockCatalogModelRepository) GetFilterableProperties(maxLength int) (map[string][]string, error) {
|
||||||
|
return make(map[string][]string), nil
|
||||||
|
}
|
||||||
|
|
||||||
// MockCatalogModelArtifactRepository mocks the CatalogModelArtifactRepository interface.
|
// MockCatalogModelArtifactRepository mocks the CatalogModelArtifactRepository interface.
|
||||||
type MockCatalogModelArtifactRepository struct {
|
type MockCatalogModelArtifactRepository struct {
|
||||||
SavedArtifacts []dbmodels.CatalogModelArtifact
|
SavedArtifacts []dbmodels.CatalogModelArtifact
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
dbmodels "github.com/kubeflow/model-registry/catalog/internal/db/models"
|
dbmodels "github.com/kubeflow/model-registry/catalog/internal/db/models"
|
||||||
|
|
@ -184,6 +185,68 @@ func (d *dbCatalogImpl) GetArtifacts(ctx context.Context, modelName string, sour
|
||||||
return *artifactList, nil
|
return *artifactList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dbCatalogImpl) GetFilterOptions(ctx context.Context) (*apimodels.FilterOptionsList, error) {
|
||||||
|
// Max length threshold for filter values (excludes verbose fields like readme, description)
|
||||||
|
const maxFilterValueLength = 100
|
||||||
|
|
||||||
|
// Query database for filterable properties
|
||||||
|
filterableProps, err := d.catalogModelRepository.GetFilterableProperties(maxFilterValueLength)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build FilterOptionsList
|
||||||
|
options := make(map[string]apimodels.FilterOption, maxFilterValueLength)
|
||||||
|
|
||||||
|
// Process each property and its values
|
||||||
|
for fieldName, values := range filterableProps {
|
||||||
|
// Skip internal/technical fields that shouldn't be exposed as filters
|
||||||
|
if fieldName == "source_id" || fieldName == "logo" || fieldName == "license_link" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduplicate values
|
||||||
|
uniqueValues := make(map[string]bool)
|
||||||
|
|
||||||
|
// Parse JSON arrays for fields like language and tasks
|
||||||
|
for _, value := range values {
|
||||||
|
var arrayValues []string
|
||||||
|
if err := json.Unmarshal([]byte(value), &arrayValues); err == nil {
|
||||||
|
// Successfully parsed as array, add individual values
|
||||||
|
for _, v := range arrayValues {
|
||||||
|
uniqueValues[v] = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a JSON array
|
||||||
|
uniqueValues[value] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uniqueValues) > 0 {
|
||||||
|
sortedValues := make([]string, 0, len(uniqueValues))
|
||||||
|
for v := range uniqueValues {
|
||||||
|
sortedValues = append(sortedValues, v)
|
||||||
|
}
|
||||||
|
sort.Strings(sortedValues)
|
||||||
|
|
||||||
|
// Convert to []interface{} (supports future non-string filter types)
|
||||||
|
expandedValues := make([]interface{}, len(sortedValues))
|
||||||
|
for i, v := range sortedValues {
|
||||||
|
expandedValues[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
options[fieldName] = apimodels.FilterOption{
|
||||||
|
Type: "string",
|
||||||
|
Values: expandedValues,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apimodels.FilterOptionsList{
|
||||||
|
Filters: &options,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func mapDBModelToAPIModel(m dbmodels.CatalogModel) apimodels.CatalogModel {
|
func mapDBModelToAPIModel(m dbmodels.CatalogModel) apimodels.CatalogModel {
|
||||||
res := apimodels.CatalogModel{}
|
res := apimodels.CatalogModel{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -801,6 +801,168 @@ func TestDBCatalog(t *testing.T) {
|
||||||
assert.Contains(t, err.Error(), "invalid model name")
|
assert.Contains(t, err.Error(), "invalid model name")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("TestGetFilterOptions", func(t *testing.T) {
|
||||||
|
// Create models with various properties for filter options testing
|
||||||
|
model1 := &models.CatalogModelImpl{
|
||||||
|
TypeID: apiutils.Of(int32(catalogModelTypeID)),
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("filter-options-model-1"),
|
||||||
|
ExternalID: apiutils.Of("filter-opt-1"),
|
||||||
|
},
|
||||||
|
Properties: &[]mr_models.Properties{
|
||||||
|
{Name: "source_id", StringValue: apiutils.Of("filter-test-source")},
|
||||||
|
{Name: "license", StringValue: apiutils.Of("MIT")},
|
||||||
|
{Name: "provider", StringValue: apiutils.Of("HuggingFace")},
|
||||||
|
{Name: "maturity", StringValue: apiutils.Of("stable")},
|
||||||
|
{Name: "library_name", StringValue: apiutils.Of("transformers")},
|
||||||
|
{Name: "language", StringValue: apiutils.Of(`["python", "rust"]`)},
|
||||||
|
{Name: "tasks", StringValue: apiutils.Of(`["text-classification", "token-classification"]`)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
model2 := &models.CatalogModelImpl{
|
||||||
|
TypeID: apiutils.Of(int32(catalogModelTypeID)),
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("filter-options-model-2"),
|
||||||
|
ExternalID: apiutils.Of("filter-opt-2"),
|
||||||
|
},
|
||||||
|
Properties: &[]mr_models.Properties{
|
||||||
|
{Name: "source_id", StringValue: apiutils.Of("filter-test-source")},
|
||||||
|
{Name: "license", StringValue: apiutils.Of("Apache-2.0")},
|
||||||
|
{Name: "provider", StringValue: apiutils.Of("OpenAI")},
|
||||||
|
{Name: "maturity", StringValue: apiutils.Of("experimental")},
|
||||||
|
{Name: "library_name", StringValue: apiutils.Of("openai")},
|
||||||
|
{Name: "language", StringValue: apiutils.Of(`["python", "javascript"]`)},
|
||||||
|
{Name: "tasks", StringValue: apiutils.Of(`["text-generation", "conversational"]`)},
|
||||||
|
{Name: "readme", StringValue: apiutils.Of("This is a very long readme that exceeds 100 characters and should be excluded from filter options because it's too verbose for filtering purposes.")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
model3 := &models.CatalogModelImpl{
|
||||||
|
TypeID: apiutils.Of(int32(catalogModelTypeID)),
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("filter-options-model-3"),
|
||||||
|
ExternalID: apiutils.Of("filter-opt-3"),
|
||||||
|
},
|
||||||
|
Properties: &[]mr_models.Properties{
|
||||||
|
{Name: "source_id", StringValue: apiutils.Of("filter-test-source")},
|
||||||
|
{Name: "license", StringValue: apiutils.Of("MIT")},
|
||||||
|
{Name: "provider", StringValue: apiutils.Of("PyTorch")},
|
||||||
|
{Name: "maturity", StringValue: apiutils.Of("stable")},
|
||||||
|
{Name: "language", StringValue: apiutils.Of(`["python"]`)},
|
||||||
|
{Name: "tasks", StringValue: apiutils.Of(`["image-classification"]`)},
|
||||||
|
{Name: "logo", StringValue: apiutils.Of("https://example.com/logo.png")},
|
||||||
|
{Name: "license_link", StringValue: apiutils.Of("https://example.com/license")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := catalogModelRepo.Save(model1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = catalogModelRepo.Save(model2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = catalogModelRepo.Save(model3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Test GetFilterOptions
|
||||||
|
filterOptions, err := dbCatalog.GetFilterOptions(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, filterOptions)
|
||||||
|
require.NotNil(t, filterOptions.Filters)
|
||||||
|
|
||||||
|
filters := *filterOptions.Filters
|
||||||
|
|
||||||
|
// Should include short properties
|
||||||
|
assert.Contains(t, filters, "license")
|
||||||
|
assert.Contains(t, filters, "provider")
|
||||||
|
assert.Contains(t, filters, "maturity")
|
||||||
|
assert.Contains(t, filters, "library_name")
|
||||||
|
assert.Contains(t, filters, "language")
|
||||||
|
assert.Contains(t, filters, "tasks")
|
||||||
|
|
||||||
|
// Should exclude internal/verbose fields
|
||||||
|
assert.NotContains(t, filters, "source_id", "source_id should be excluded")
|
||||||
|
assert.NotContains(t, filters, "logo", "logo should be excluded")
|
||||||
|
assert.NotContains(t, filters, "license_link", "license_link should be excluded")
|
||||||
|
assert.NotContains(t, filters, "readme", "readme should be excluded (too long)")
|
||||||
|
|
||||||
|
licenseFilter := filters["license"]
|
||||||
|
assert.Equal(t, "string", licenseFilter.Type)
|
||||||
|
assert.NotNil(t, licenseFilter.Values)
|
||||||
|
assert.GreaterOrEqual(t, len(licenseFilter.Values), 2, "Should have at least MIT and Apache-2.0")
|
||||||
|
|
||||||
|
// Convert to string slice for easier checking
|
||||||
|
licenseValues := make([]string, 0)
|
||||||
|
for _, v := range licenseFilter.Values {
|
||||||
|
if strVal, ok := v.(string); ok {
|
||||||
|
licenseValues = append(licenseValues, strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Contains(t, licenseValues, "MIT")
|
||||||
|
assert.Contains(t, licenseValues, "Apache-2.0")
|
||||||
|
|
||||||
|
// Verify provider filter options
|
||||||
|
providerFilter := filters["provider"]
|
||||||
|
assert.Equal(t, "string", providerFilter.Type)
|
||||||
|
providerValues := make([]string, 0)
|
||||||
|
for _, v := range providerFilter.Values {
|
||||||
|
if strVal, ok := v.(string); ok {
|
||||||
|
providerValues = append(providerValues, strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Contains(t, providerValues, "HuggingFace")
|
||||||
|
assert.Contains(t, providerValues, "OpenAI")
|
||||||
|
assert.Contains(t, providerValues, "PyTorch")
|
||||||
|
|
||||||
|
// Verify JSON array fields are properly parsed and expanded
|
||||||
|
languageFilter := filters["language"]
|
||||||
|
assert.Equal(t, "string", languageFilter.Type)
|
||||||
|
languageValues := make([]string, 0)
|
||||||
|
for _, v := range languageFilter.Values {
|
||||||
|
if strVal, ok := v.(string); ok {
|
||||||
|
languageValues = append(languageValues, strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Should contain individual values from JSON arrays
|
||||||
|
assert.Contains(t, languageValues, "python")
|
||||||
|
assert.Contains(t, languageValues, "rust")
|
||||||
|
assert.Contains(t, languageValues, "javascript")
|
||||||
|
|
||||||
|
// Verify tasks are properly expanded
|
||||||
|
tasksFilter := filters["tasks"]
|
||||||
|
assert.Equal(t, "string", tasksFilter.Type)
|
||||||
|
tasksValues := make([]string, 0)
|
||||||
|
for _, v := range tasksFilter.Values {
|
||||||
|
if strVal, ok := v.(string); ok {
|
||||||
|
tasksValues = append(tasksValues, strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Contains(t, tasksValues, "text-classification")
|
||||||
|
assert.Contains(t, tasksValues, "token-classification")
|
||||||
|
assert.Contains(t, tasksValues, "text-generation")
|
||||||
|
assert.Contains(t, tasksValues, "conversational")
|
||||||
|
assert.Contains(t, tasksValues, "image-classification")
|
||||||
|
|
||||||
|
// Verify no duplicates
|
||||||
|
pythonCount := 0
|
||||||
|
for _, v := range languageValues {
|
||||||
|
if v == "python" {
|
||||||
|
pythonCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Equal(t, 1, pythonCount, "python should appear only once (deduplicated)")
|
||||||
|
|
||||||
|
// Verify maturity options
|
||||||
|
maturityFilter := filters["maturity"]
|
||||||
|
maturityValues := make([]string, 0)
|
||||||
|
for _, v := range maturityFilter.Values {
|
||||||
|
if strVal, ok := v.(string); ok {
|
||||||
|
maturityValues = append(maturityValues, strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Contains(t, maturityValues, "stable")
|
||||||
|
assert.Contains(t, maturityValues, "experimental")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions to get type IDs from database
|
// Helper functions to get type IDs from database
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,15 @@ func (h *hfCatalogImpl) GetArtifacts(ctx context.Context, modelName string, sour
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *hfCatalogImpl) GetFilterOptions(ctx context.Context) (*openapi.FilterOptionsList, error) {
|
||||||
|
// TODO: Implement HuggingFace filter options retrieval
|
||||||
|
// For now, return empty options to satisfy interface
|
||||||
|
emptyFilters := make(map[string]openapi.FilterOption)
|
||||||
|
return &openapi.FilterOptionsList{
|
||||||
|
Filters: &emptyFilters,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// validateCredentials checks if the HuggingFace API credentials are valid
|
// validateCredentials checks if the HuggingFace API credentials are valid
|
||||||
func (h *hfCatalogImpl) validateCredentials(ctx context.Context) error {
|
func (h *hfCatalogImpl) validateCredentials(ctx context.Context) error {
|
||||||
glog.Infof("Validating HuggingFace API credentials")
|
glog.Infof("Validating HuggingFace API credentials")
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,7 @@ type CatalogModelRepository interface {
|
||||||
GetByName(name string) (CatalogModel, error)
|
GetByName(name string) (CatalogModel, error)
|
||||||
List(listOptions CatalogModelListOptions) (*models.ListWrapper[CatalogModel], error)
|
List(listOptions CatalogModelListOptions) (*models.ListWrapper[CatalogModel], error)
|
||||||
Save(model CatalogModel) (CatalogModel, error)
|
Save(model CatalogModel) (CatalogModel, error)
|
||||||
|
// GetFilterableProperties returns a map of property names to their unique values
|
||||||
|
// Only includes string properties where all values are shorter than maxLength
|
||||||
|
GetFilterableProperties(maxLength int) (map[string][]string, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,3 +231,56 @@ func mapDataLayerToCatalogModel(modelCtx schema.Context, propertiesCtx []schema.
|
||||||
|
|
||||||
return catalogModel
|
return catalogModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFilterableProperties returns property names and their unique values
|
||||||
|
// Only includes properties where ALL values are shorter than maxLength
|
||||||
|
func (r *CatalogModelRepositoryImpl) GetFilterableProperties(maxLength int) (map[string][]string, error) {
|
||||||
|
config := r.GetConfig()
|
||||||
|
|
||||||
|
// Get table names using GORM utilities for database compatibility
|
||||||
|
contextTable := utils.GetTableName(config.DB, &schema.Context{})
|
||||||
|
propertyTable := utils.GetTableName(config.DB, &schema.ContextProperty{})
|
||||||
|
|
||||||
|
// Simplified query: get distinct property name/value pairs
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
SELECT DISTINCT cp.name, cp.string_value
|
||||||
|
FROM %s cp
|
||||||
|
WHERE cp.context_id IN (
|
||||||
|
SELECT id FROM %s WHERE type_id = ?
|
||||||
|
)
|
||||||
|
AND cp.name IN (
|
||||||
|
SELECT name FROM (
|
||||||
|
SELECT name, MAX(CHAR_LENGTH(string_value)) as max_len
|
||||||
|
FROM %s
|
||||||
|
WHERE context_id IN (
|
||||||
|
SELECT id FROM %s WHERE type_id = ?
|
||||||
|
)
|
||||||
|
AND string_value IS NOT NULL
|
||||||
|
AND string_value != ''
|
||||||
|
GROUP BY name
|
||||||
|
) AS field_lengths
|
||||||
|
WHERE max_len <= ?
|
||||||
|
)
|
||||||
|
AND cp.string_value IS NOT NULL
|
||||||
|
AND cp.string_value != ''
|
||||||
|
ORDER BY cp.name, cp.string_value
|
||||||
|
`, propertyTable, contextTable, propertyTable, contextTable)
|
||||||
|
|
||||||
|
type propertyRow struct {
|
||||||
|
Name string
|
||||||
|
StringValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows []propertyRow
|
||||||
|
if err := config.DB.Raw(query, config.TypeID, config.TypeID, maxLength).Scan(&rows).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("error querying filterable properties: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate values by property name in Go
|
||||||
|
result := make(map[string][]string)
|
||||||
|
for _, row := range rows {
|
||||||
|
result[row.Name] = append(result[row.Name], row.StringValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,85 @@ func TestCatalogModelRepository(t *testing.T) {
|
||||||
require.NotNil(t, retrieved.GetCustomProperties())
|
require.NotNil(t, retrieved.GetCustomProperties())
|
||||||
assert.Len(t, *retrieved.GetCustomProperties(), 2)
|
assert.Len(t, *retrieved.GetCustomProperties(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("TestGetFilterableProperties", func(t *testing.T) {
|
||||||
|
// Create models with various property lengths
|
||||||
|
shortValueModel := &models.CatalogModelImpl{
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("short-value-model"),
|
||||||
|
ExternalID: apiutils.Of("short-ext"),
|
||||||
|
},
|
||||||
|
Properties: &[]dbmodels.Properties{
|
||||||
|
{Name: "license", StringValue: apiutils.Of("MIT")},
|
||||||
|
{Name: "provider", StringValue: apiutils.Of("HuggingFace")},
|
||||||
|
{Name: "maturity", StringValue: apiutils.Of("stable")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
longValueModel := &models.CatalogModelImpl{
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("long-value-model"),
|
||||||
|
ExternalID: apiutils.Of("long-ext"),
|
||||||
|
},
|
||||||
|
Properties: &[]dbmodels.Properties{
|
||||||
|
{Name: "license", StringValue: apiutils.Of("Apache-2.0")},
|
||||||
|
{Name: "readme", StringValue: apiutils.Of("This is a very long readme that should be excluded from filterable properties because it exceeds the maximum length threshold of 100 characters. It contains detailed information about the model.")},
|
||||||
|
{Name: "description", StringValue: apiutils.Of("This is also a very long description that should be excluded from filterable properties because it exceeds 100 chars")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonArrayModel := &models.CatalogModelImpl{
|
||||||
|
Attributes: &models.CatalogModelAttributes{
|
||||||
|
Name: apiutils.Of("json-array-model"),
|
||||||
|
ExternalID: apiutils.Of("json-ext"),
|
||||||
|
},
|
||||||
|
Properties: &[]dbmodels.Properties{
|
||||||
|
{Name: "language", StringValue: apiutils.Of(`["python", "go"]`)},
|
||||||
|
{Name: "tasks", StringValue: apiutils.Of(`["text-classification", "question-answering"]`)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := repo.Save(shortValueModel)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = repo.Save(longValueModel)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = repo.Save(jsonArrayModel)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Test with max length of 100
|
||||||
|
result, err := repo.GetFilterableProperties(100)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
|
||||||
|
// Should include short properties
|
||||||
|
assert.Contains(t, result, "license")
|
||||||
|
assert.Contains(t, result, "provider")
|
||||||
|
assert.Contains(t, result, "maturity")
|
||||||
|
assert.Contains(t, result, "language")
|
||||||
|
assert.Contains(t, result, "tasks")
|
||||||
|
|
||||||
|
// Should exclude long properties
|
||||||
|
assert.NotContains(t, result, "readme")
|
||||||
|
assert.NotContains(t, result, "description")
|
||||||
|
|
||||||
|
// Verify license has both values
|
||||||
|
licenseValues := result["license"]
|
||||||
|
assert.GreaterOrEqual(t, len(licenseValues), 2)
|
||||||
|
assert.Contains(t, licenseValues, "MIT")
|
||||||
|
assert.Contains(t, licenseValues, "Apache-2.0")
|
||||||
|
|
||||||
|
// Test with smaller max length
|
||||||
|
result, err = repo.GetFilterableProperties(10)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
|
||||||
|
// Should include only very short properties
|
||||||
|
assert.Contains(t, result, "license")
|
||||||
|
// Should exclude longer properties
|
||||||
|
assert.NotContains(t, result, "provider") // "HuggingFace" is > 10 chars
|
||||||
|
assert.NotContains(t, result, "language")
|
||||||
|
assert.NotContains(t, result, "tasks")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get or create CatalogModel type ID
|
// Helper function to get or create CatalogModel type ID
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ model_catalog_model_list.go
|
||||||
model_catalog_source.go
|
model_catalog_source.go
|
||||||
model_catalog_source_list.go
|
model_catalog_source_list.go
|
||||||
model_error.go
|
model_error.go
|
||||||
|
model_filter_option.go
|
||||||
|
model_filter_option_range.go
|
||||||
|
model_filter_options_list.go
|
||||||
model_metadata_bool_value.go
|
model_metadata_bool_value.go
|
||||||
model_metadata_double_value.go
|
model_metadata_double_value.go
|
||||||
model_metadata_int_value.go
|
model_metadata_int_value.go
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
// pass the data to a ModelCatalogServiceAPIServicer to perform the required actions, then write the service results to the http response.
|
// pass the data to a ModelCatalogServiceAPIServicer to perform the required actions, then write the service results to the http response.
|
||||||
type ModelCatalogServiceAPIRouter interface {
|
type ModelCatalogServiceAPIRouter interface {
|
||||||
FindModels(http.ResponseWriter, *http.Request)
|
FindModels(http.ResponseWriter, *http.Request)
|
||||||
|
FindModelsFilterOptions(http.ResponseWriter, *http.Request)
|
||||||
FindSources(http.ResponseWriter, *http.Request)
|
FindSources(http.ResponseWriter, *http.Request)
|
||||||
GetModel(http.ResponseWriter, *http.Request)
|
GetModel(http.ResponseWriter, *http.Request)
|
||||||
GetAllModelArtifacts(http.ResponseWriter, *http.Request)
|
GetAllModelArtifacts(http.ResponseWriter, *http.Request)
|
||||||
|
|
@ -33,6 +34,7 @@ type ModelCatalogServiceAPIRouter interface {
|
||||||
// and updated with the logic required for the API.
|
// and updated with the logic required for the API.
|
||||||
type ModelCatalogServiceAPIServicer interface {
|
type ModelCatalogServiceAPIServicer interface {
|
||||||
FindModels(context.Context, []string, string, []string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
FindModels(context.Context, []string, string, []string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
||||||
|
FindModelsFilterOptions(context.Context) (ImplResponse, error)
|
||||||
FindSources(context.Context, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
FindSources(context.Context, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
||||||
GetModel(context.Context, string, string) (ImplResponse, error)
|
GetModel(context.Context, string, string) (ImplResponse, error)
|
||||||
GetAllModelArtifacts(context.Context, string, string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
GetAllModelArtifacts(context.Context, string, string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,11 @@ func (c *ModelCatalogServiceAPIController) Routes() Routes {
|
||||||
"/api/model_catalog/v1alpha1/models",
|
"/api/model_catalog/v1alpha1/models",
|
||||||
c.FindModels,
|
c.FindModels,
|
||||||
},
|
},
|
||||||
|
"FindModelsFilterOptions": Route{
|
||||||
|
strings.ToUpper("Get"),
|
||||||
|
"/api/model_catalog/v1alpha1/models/filter_options",
|
||||||
|
c.FindModelsFilterOptions,
|
||||||
|
},
|
||||||
"FindSources": Route{
|
"FindSources": Route{
|
||||||
strings.ToUpper("Get"),
|
strings.ToUpper("Get"),
|
||||||
"/api/model_catalog/v1alpha1/sources",
|
"/api/model_catalog/v1alpha1/sources",
|
||||||
|
|
@ -96,6 +101,18 @@ func (c *ModelCatalogServiceAPIController) FindModels(w http.ResponseWriter, r *
|
||||||
EncodeJSONResponse(result.Body, &result.Code, w)
|
EncodeJSONResponse(result.Body, &result.Code, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindModelsFilterOptions - Lists fields and available options that can be used in `filterQuery` on the list models endpoint.
|
||||||
|
func (c *ModelCatalogServiceAPIController) FindModelsFilterOptions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
result, err := c.service.FindModelsFilterOptions(r.Context())
|
||||||
|
// If an error occurred, encode the error with the status code
|
||||||
|
if err != nil {
|
||||||
|
c.errorHandler(w, r, err, &result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// If no error, encode the body and the result code
|
||||||
|
EncodeJSONResponse(result.Body, &result.Code, w)
|
||||||
|
}
|
||||||
|
|
||||||
// FindSources - List All CatalogSources
|
// FindSources - List All CatalogSources
|
||||||
func (c *ModelCatalogServiceAPIController) FindSources(w http.ResponseWriter, r *http.Request) {
|
func (c *ModelCatalogServiceAPIController) FindSources(w http.ResponseWriter, r *http.Request) {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ func (m *ModelCatalogServiceAPIService) GetAllModelArtifacts(ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts, err := m.provider.GetArtifacts(ctx, modelName, sourceID, catalog.ListArtifactsParams{
|
artifacts, err := m.provider.GetArtifacts(ctx, modelName, sourceID, catalog.ListArtifactsParams{
|
||||||
|
ArtifactType: &artifactType,
|
||||||
PageSize: pageSizeInt,
|
PageSize: pageSizeInt,
|
||||||
OrderBy: orderBy,
|
OrderBy: orderBy,
|
||||||
SortOrder: sortOrder,
|
SortOrder: sortOrder,
|
||||||
NextPageToken: &nextPageToken,
|
NextPageToken: &nextPageToken,
|
||||||
ArtifactType: &artifactType,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statusCode := api.ErrToStatus(err)
|
statusCode := api.ErrToStatus(err)
|
||||||
|
|
@ -64,7 +64,7 @@ func (m *ModelCatalogServiceAPIService) GetAllModelArtifacts(ctx context.Context
|
||||||
return Response(http.StatusOK, artifacts), nil
|
return Response(http.StatusOK, artifacts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ModelCatalogServiceAPIService) FindModels(ctx context.Context, sourceIDs []string, q string, sourceLabels []string, filterQuery, pageSize string, orderBy model.OrderByField, sortOrder model.SortOrder, nextPageToken string) (ImplResponse, error) {
|
func (m *ModelCatalogServiceAPIService) FindModels(ctx context.Context, sourceIDs []string, q string, sourceLabels []string, filterQuery string, pageSize string, orderBy model.OrderByField, sortOrder model.SortOrder, nextPageToken string) (ImplResponse, error) {
|
||||||
var err error
|
var err error
|
||||||
pageSizeInt := int32(10)
|
pageSizeInt := int32(10)
|
||||||
|
|
||||||
|
|
@ -107,6 +107,15 @@ func (m *ModelCatalogServiceAPIService) FindModels(ctx context.Context, sourceID
|
||||||
return Response(http.StatusOK, models), nil
|
return Response(http.StatusOK, models), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ModelCatalogServiceAPIService) FindModelsFilterOptions(ctx context.Context) (ImplResponse, error) {
|
||||||
|
filterOptions, err := m.provider.GetFilterOptions(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, err), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response(http.StatusOK, filterOptions), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ModelCatalogServiceAPIService) GetModel(ctx context.Context, sourceID, modelName string) (ImplResponse, error) {
|
func (m *ModelCatalogServiceAPIService) GetModel(ctx context.Context, sourceID, modelName string) (ImplResponse, error) {
|
||||||
if newName, err := url.PathUnescape(modelName); err == nil {
|
if newName, err := url.PathUnescape(modelName); err == nil {
|
||||||
modelName = newName
|
modelName = newName
|
||||||
|
|
|
||||||
|
|
@ -776,6 +776,11 @@ func (m *mockModelProvider) GetArtifacts(ctx context.Context, name string, sourc
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockModelProvider) GetFilterOptions(ctx context.Context) (*model.FilterOptionsList, error) {
|
||||||
|
emptyFilters := make(map[string]model.FilterOption)
|
||||||
|
return &model.FilterOptionsList{Filters: &emptyFilters}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetModel(t *testing.T) {
|
func TestGetModel(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -1002,3 +1007,44 @@ func TestGetAllModelArtifacts(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindModelsFilterOptions(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
provider catalog.APIProvider
|
||||||
|
expectedStatus int
|
||||||
|
expectedError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Successfully retrieve filter options",
|
||||||
|
provider: &mockModelProvider{
|
||||||
|
models: map[string]*model.CatalogModel{},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedError: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
sources := catalog.NewSourceCollection()
|
||||||
|
service := NewModelCatalogServiceAPIService(tc.provider, sources)
|
||||||
|
|
||||||
|
resp, err := service.FindModelsFilterOptions(context.Background())
|
||||||
|
|
||||||
|
assert.Equal(t, tc.expectedStatus, resp.Code)
|
||||||
|
|
||||||
|
if tc.expectedError {
|
||||||
|
assert.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NotNil(t, resp.Body)
|
||||||
|
|
||||||
|
// Type assertion to access the FilterOptionsList
|
||||||
|
filterOptions, ok := resp.Body.(*model.FilterOptionsList)
|
||||||
|
require.True(t, ok, "Response body should be a FilterOptionsList")
|
||||||
|
|
||||||
|
require.NotNil(t, filterOptions.Filters)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,26 @@ func AssertErrorRequired(obj model.Error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertFilterOptionRangeConstraints checks if the values respects the defined constraints
|
||||||
|
func AssertFilterOptionRangeConstraints(obj model.FilterOptionRange) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertFilterOptionRangeRequired checks if the required fields are not zero-ed
|
||||||
|
func AssertFilterOptionRangeRequired(obj model.FilterOptionRange) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertFilterOptionsListConstraints checks if the values respects the defined constraints
|
||||||
|
func AssertFilterOptionsListConstraints(obj model.FilterOptionsList) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertFilterOptionsListRequired checks if the required fields are not zero-ed
|
||||||
|
func AssertFilterOptionsListRequired(obj model.FilterOptionsList) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AssertMetadataBoolValueConstraints checks if the values respects the defined constraints
|
// AssertMetadataBoolValueConstraints checks if the values respects the defined constraints
|
||||||
func AssertMetadataBoolValueConstraints(obj model.MetadataBoolValue) error {
|
func AssertMetadataBoolValueConstraints(obj model.MetadataBoolValue) error {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,22 @@ func AssertCatalogArtifactRequired(obj model.CatalogArtifact) error {
|
||||||
// checks the fields from CatalogModelArtifact, which doesn't compile.
|
// checks the fields from CatalogModelArtifact, which doesn't compile.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertFilterOptionRequired checks if the required fields are not zero-ed
|
||||||
|
func AssertFilterOptionRequired(obj model.FilterOption) error {
|
||||||
|
elements := map[string]interface{}{
|
||||||
|
"type": obj.Type,
|
||||||
|
}
|
||||||
|
for name, el := range elements {
|
||||||
|
if isZero := IsZeroValue(el); isZero {
|
||||||
|
return &RequiredError{Field: name}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Range != nil {
|
||||||
|
if err := AssertFilterOptionRangeRequired(*obj.Range); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ model_catalog_model_list.go
|
||||||
model_catalog_source.go
|
model_catalog_source.go
|
||||||
model_catalog_source_list.go
|
model_catalog_source_list.go
|
||||||
model_error.go
|
model_error.go
|
||||||
|
model_filter_option.go
|
||||||
|
model_filter_option_range.go
|
||||||
|
model_filter_options_list.go
|
||||||
model_metadata_bool_value.go
|
model_metadata_bool_value.go
|
||||||
model_metadata_double_value.go
|
model_metadata_double_value.go
|
||||||
model_metadata_int_value.go
|
model_metadata_int_value.go
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,136 @@ func (a *ModelCatalogServiceAPIService) FindModelsExecute(r ApiFindModelsRequest
|
||||||
return localVarReturnValue, localVarHTTPResponse, nil
|
return localVarReturnValue, localVarHTTPResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ApiFindModelsFilterOptionsRequest struct {
|
||||||
|
ctx context.Context
|
||||||
|
ApiService *ModelCatalogServiceAPIService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ApiFindModelsFilterOptionsRequest) Execute() (*FilterOptionsList, *http.Response, error) {
|
||||||
|
return r.ApiService.FindModelsFilterOptionsExecute(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
FindModelsFilterOptions Lists fields and available options that can be used in `filterQuery` on the list models endpoint.
|
||||||
|
|
||||||
|
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||||
|
@return ApiFindModelsFilterOptionsRequest
|
||||||
|
*/
|
||||||
|
func (a *ModelCatalogServiceAPIService) FindModelsFilterOptions(ctx context.Context) ApiFindModelsFilterOptionsRequest {
|
||||||
|
return ApiFindModelsFilterOptionsRequest{
|
||||||
|
ApiService: a,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute executes the request
|
||||||
|
//
|
||||||
|
// @return FilterOptionsList
|
||||||
|
func (a *ModelCatalogServiceAPIService) FindModelsFilterOptionsExecute(r ApiFindModelsFilterOptionsRequest) (*FilterOptionsList, *http.Response, error) {
|
||||||
|
var (
|
||||||
|
localVarHTTPMethod = http.MethodGet
|
||||||
|
localVarPostBody interface{}
|
||||||
|
formFiles []formFile
|
||||||
|
localVarReturnValue *FilterOptionsList
|
||||||
|
)
|
||||||
|
|
||||||
|
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ModelCatalogServiceAPIService.FindModelsFilterOptions")
|
||||||
|
if err != nil {
|
||||||
|
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarPath := localBasePath + "/api/model_catalog/v1alpha1/models/filter_options"
|
||||||
|
|
||||||
|
localVarHeaderParams := make(map[string]string)
|
||||||
|
localVarQueryParams := url.Values{}
|
||||||
|
localVarFormParams := url.Values{}
|
||||||
|
|
||||||
|
// to determine the Content-Type header
|
||||||
|
localVarHTTPContentTypes := []string{}
|
||||||
|
|
||||||
|
// set Content-Type header
|
||||||
|
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||||
|
if localVarHTTPContentType != "" {
|
||||||
|
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
// to determine the Accept header
|
||||||
|
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||||
|
|
||||||
|
// set Accept header
|
||||||
|
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||||
|
if localVarHTTPHeaderAccept != "" {
|
||||||
|
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||||
|
}
|
||||||
|
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||||
|
if err != nil {
|
||||||
|
return localVarReturnValue, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||||
|
if err != nil || localVarHTTPResponse == nil {
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, err
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||||
|
localVarHTTPResponse.Body.Close()
|
||||||
|
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||||
|
if err != nil {
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if localVarHTTPResponse.StatusCode >= 300 {
|
||||||
|
newErr := &GenericOpenAPIError{
|
||||||
|
body: localVarBody,
|
||||||
|
error: localVarHTTPResponse.Status,
|
||||||
|
}
|
||||||
|
if localVarHTTPResponse.StatusCode == 400 {
|
||||||
|
var v Error
|
||||||
|
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
newErr.error = err.Error()
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||||
|
newErr.model = v
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
if localVarHTTPResponse.StatusCode == 401 {
|
||||||
|
var v Error
|
||||||
|
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
newErr.error = err.Error()
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||||
|
newErr.model = v
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
if localVarHTTPResponse.StatusCode == 500 {
|
||||||
|
var v Error
|
||||||
|
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
newErr.error = err.Error()
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||||
|
newErr.model = v
|
||||||
|
}
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
newErr := &GenericOpenAPIError{
|
||||||
|
body: localVarBody,
|
||||||
|
error: err.Error(),
|
||||||
|
}
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return localVarReturnValue, localVarHTTPResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
type ApiFindSourcesRequest struct {
|
type ApiFindSourcesRequest struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ApiService *ModelCatalogServiceAPIService
|
ApiService *ModelCatalogServiceAPIService
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
Model Catalog REST API
|
||||||
|
|
||||||
|
REST API for Model Registry to create and manage ML model metadata
|
||||||
|
|
||||||
|
API version: v1alpha1
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||||
|
|
||||||
|
package openapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checks if the FilterOption type satisfies the MappedNullable interface at compile time
|
||||||
|
var _ MappedNullable = &FilterOption{}
|
||||||
|
|
||||||
|
// FilterOption struct for FilterOption
|
||||||
|
type FilterOption struct {
|
||||||
|
// The data type of the filter option
|
||||||
|
Type string `json:"type"`
|
||||||
|
// Known values of the property for string types with a small number of possible options.
|
||||||
|
Values []interface{} `json:"values,omitempty"`
|
||||||
|
Range *FilterOptionRange `json:"range,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOption instantiates a new FilterOption object
|
||||||
|
// This constructor will assign default values to properties that have it defined,
|
||||||
|
// and makes sure properties required by API are set, but the set of arguments
|
||||||
|
// will change when the set of required properties is changed
|
||||||
|
func NewFilterOption(type_ string) *FilterOption {
|
||||||
|
this := FilterOption{}
|
||||||
|
this.Type = type_
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOptionWithDefaults instantiates a new FilterOption object
|
||||||
|
// This constructor will only assign default values to properties that have it defined,
|
||||||
|
// but it doesn't guarantee that properties required by API are set
|
||||||
|
func NewFilterOptionWithDefaults() *FilterOption {
|
||||||
|
this := FilterOption{}
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetType returns the Type field value
|
||||||
|
func (o *FilterOption) GetType() string {
|
||||||
|
if o == nil {
|
||||||
|
var ret string
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTypeOk returns a tuple with the Type field value
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOption) GetTypeOk() (*string, bool) {
|
||||||
|
if o == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return &o.Type, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetType sets field value
|
||||||
|
func (o *FilterOption) SetType(v string) {
|
||||||
|
o.Type = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValues returns the Values field value if set, zero value otherwise.
|
||||||
|
func (o *FilterOption) GetValues() []interface{} {
|
||||||
|
if o == nil || IsNil(o.Values) {
|
||||||
|
var ret []interface{}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return o.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValuesOk returns a tuple with the Values field value if set, nil otherwise
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOption) GetValuesOk() ([]interface{}, bool) {
|
||||||
|
if o == nil || IsNil(o.Values) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return o.Values, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasValues returns a boolean if a field has been set.
|
||||||
|
func (o *FilterOption) HasValues() bool {
|
||||||
|
if o != nil && !IsNil(o.Values) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValues gets a reference to the given []interface{} and assigns it to the Values field.
|
||||||
|
func (o *FilterOption) SetValues(v []interface{}) {
|
||||||
|
o.Values = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRange returns the Range field value if set, zero value otherwise.
|
||||||
|
func (o *FilterOption) GetRange() FilterOptionRange {
|
||||||
|
if o == nil || IsNil(o.Range) {
|
||||||
|
var ret FilterOptionRange
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return *o.Range
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRangeOk returns a tuple with the Range field value if set, nil otherwise
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOption) GetRangeOk() (*FilterOptionRange, bool) {
|
||||||
|
if o == nil || IsNil(o.Range) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return o.Range, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasRange returns a boolean if a field has been set.
|
||||||
|
func (o *FilterOption) HasRange() bool {
|
||||||
|
if o != nil && !IsNil(o.Range) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRange gets a reference to the given FilterOptionRange and assigns it to the Range field.
|
||||||
|
func (o *FilterOption) SetRange(v FilterOptionRange) {
|
||||||
|
o.Range = &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOption) MarshalJSON() ([]byte, error) {
|
||||||
|
toSerialize, err := o.ToMap()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return json.Marshal(toSerialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOption) ToMap() (map[string]interface{}, error) {
|
||||||
|
toSerialize := map[string]interface{}{}
|
||||||
|
toSerialize["type"] = o.Type
|
||||||
|
if !IsNil(o.Values) {
|
||||||
|
toSerialize["values"] = o.Values
|
||||||
|
}
|
||||||
|
if !IsNil(o.Range) {
|
||||||
|
toSerialize["range"] = o.Range
|
||||||
|
}
|
||||||
|
return toSerialize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullableFilterOption struct {
|
||||||
|
value *FilterOption
|
||||||
|
isSet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOption) Get() *FilterOption {
|
||||||
|
return v.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOption) Set(val *FilterOption) {
|
||||||
|
v.value = val
|
||||||
|
v.isSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOption) IsSet() bool {
|
||||||
|
return v.isSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOption) Unset() {
|
||||||
|
v.value = nil
|
||||||
|
v.isSet = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullableFilterOption(val *FilterOption) *NullableFilterOption {
|
||||||
|
return &NullableFilterOption{value: val, isSet: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOption) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOption) UnmarshalJSON(src []byte) error {
|
||||||
|
v.isSet = true
|
||||||
|
return json.Unmarshal(src, &v.value)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
Model Catalog REST API
|
||||||
|
|
||||||
|
REST API for Model Registry to create and manage ML model metadata
|
||||||
|
|
||||||
|
API version: v1alpha1
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||||
|
|
||||||
|
package openapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checks if the FilterOptionRange type satisfies the MappedNullable interface at compile time
|
||||||
|
var _ MappedNullable = &FilterOptionRange{}
|
||||||
|
|
||||||
|
// FilterOptionRange Min and max values for number types.
|
||||||
|
type FilterOptionRange struct {
|
||||||
|
Min *float32 `json:"min,omitempty"`
|
||||||
|
Max *float32 `json:"max,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOptionRange instantiates a new FilterOptionRange object
|
||||||
|
// This constructor will assign default values to properties that have it defined,
|
||||||
|
// and makes sure properties required by API are set, but the set of arguments
|
||||||
|
// will change when the set of required properties is changed
|
||||||
|
func NewFilterOptionRange() *FilterOptionRange {
|
||||||
|
this := FilterOptionRange{}
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOptionRangeWithDefaults instantiates a new FilterOptionRange object
|
||||||
|
// This constructor will only assign default values to properties that have it defined,
|
||||||
|
// but it doesn't guarantee that properties required by API are set
|
||||||
|
func NewFilterOptionRangeWithDefaults() *FilterOptionRange {
|
||||||
|
this := FilterOptionRange{}
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMin returns the Min field value if set, zero value otherwise.
|
||||||
|
func (o *FilterOptionRange) GetMin() float32 {
|
||||||
|
if o == nil || IsNil(o.Min) {
|
||||||
|
var ret float32
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return *o.Min
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMinOk returns a tuple with the Min field value if set, nil otherwise
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOptionRange) GetMinOk() (*float32, bool) {
|
||||||
|
if o == nil || IsNil(o.Min) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return o.Min, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasMin returns a boolean if a field has been set.
|
||||||
|
func (o *FilterOptionRange) HasMin() bool {
|
||||||
|
if o != nil && !IsNil(o.Min) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMin gets a reference to the given float32 and assigns it to the Min field.
|
||||||
|
func (o *FilterOptionRange) SetMin(v float32) {
|
||||||
|
o.Min = &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMax returns the Max field value if set, zero value otherwise.
|
||||||
|
func (o *FilterOptionRange) GetMax() float32 {
|
||||||
|
if o == nil || IsNil(o.Max) {
|
||||||
|
var ret float32
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return *o.Max
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxOk returns a tuple with the Max field value if set, nil otherwise
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOptionRange) GetMaxOk() (*float32, bool) {
|
||||||
|
if o == nil || IsNil(o.Max) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return o.Max, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasMax returns a boolean if a field has been set.
|
||||||
|
func (o *FilterOptionRange) HasMax() bool {
|
||||||
|
if o != nil && !IsNil(o.Max) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMax gets a reference to the given float32 and assigns it to the Max field.
|
||||||
|
func (o *FilterOptionRange) SetMax(v float32) {
|
||||||
|
o.Max = &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOptionRange) MarshalJSON() ([]byte, error) {
|
||||||
|
toSerialize, err := o.ToMap()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return json.Marshal(toSerialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOptionRange) ToMap() (map[string]interface{}, error) {
|
||||||
|
toSerialize := map[string]interface{}{}
|
||||||
|
if !IsNil(o.Min) {
|
||||||
|
toSerialize["min"] = o.Min
|
||||||
|
}
|
||||||
|
if !IsNil(o.Max) {
|
||||||
|
toSerialize["max"] = o.Max
|
||||||
|
}
|
||||||
|
return toSerialize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullableFilterOptionRange struct {
|
||||||
|
value *FilterOptionRange
|
||||||
|
isSet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionRange) Get() *FilterOptionRange {
|
||||||
|
return v.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionRange) Set(val *FilterOptionRange) {
|
||||||
|
v.value = val
|
||||||
|
v.isSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionRange) IsSet() bool {
|
||||||
|
return v.isSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionRange) Unset() {
|
||||||
|
v.value = nil
|
||||||
|
v.isSet = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullableFilterOptionRange(val *FilterOptionRange) *NullableFilterOptionRange {
|
||||||
|
return &NullableFilterOptionRange{value: val, isSet: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionRange) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionRange) UnmarshalJSON(src []byte) error {
|
||||||
|
v.isSet = true
|
||||||
|
return json.Unmarshal(src, &v.value)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
Model Catalog REST API
|
||||||
|
|
||||||
|
REST API for Model Registry to create and manage ML model metadata
|
||||||
|
|
||||||
|
API version: v1alpha1
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||||
|
|
||||||
|
package openapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checks if the FilterOptionsList type satisfies the MappedNullable interface at compile time
|
||||||
|
var _ MappedNullable = &FilterOptionsList{}
|
||||||
|
|
||||||
|
// FilterOptionsList List of FilterOptions
|
||||||
|
type FilterOptionsList struct {
|
||||||
|
// A single filter option.
|
||||||
|
Filters *map[string]FilterOption `json:"filters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOptionsList instantiates a new FilterOptionsList object
|
||||||
|
// This constructor will assign default values to properties that have it defined,
|
||||||
|
// and makes sure properties required by API are set, but the set of arguments
|
||||||
|
// will change when the set of required properties is changed
|
||||||
|
func NewFilterOptionsList() *FilterOptionsList {
|
||||||
|
this := FilterOptionsList{}
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterOptionsListWithDefaults instantiates a new FilterOptionsList object
|
||||||
|
// This constructor will only assign default values to properties that have it defined,
|
||||||
|
// but it doesn't guarantee that properties required by API are set
|
||||||
|
func NewFilterOptionsListWithDefaults() *FilterOptionsList {
|
||||||
|
this := FilterOptionsList{}
|
||||||
|
return &this
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFilters returns the Filters field value if set, zero value otherwise.
|
||||||
|
func (o *FilterOptionsList) GetFilters() map[string]FilterOption {
|
||||||
|
if o == nil || IsNil(o.Filters) {
|
||||||
|
var ret map[string]FilterOption
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return *o.Filters
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFiltersOk returns a tuple with the Filters field value if set, nil otherwise
|
||||||
|
// and a boolean to check if the value has been set.
|
||||||
|
func (o *FilterOptionsList) GetFiltersOk() (*map[string]FilterOption, bool) {
|
||||||
|
if o == nil || IsNil(o.Filters) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return o.Filters, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasFilters returns a boolean if a field has been set.
|
||||||
|
func (o *FilterOptionsList) HasFilters() bool {
|
||||||
|
if o != nil && !IsNil(o.Filters) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFilters gets a reference to the given map[string]FilterOption and assigns it to the Filters field.
|
||||||
|
func (o *FilterOptionsList) SetFilters(v map[string]FilterOption) {
|
||||||
|
o.Filters = &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOptionsList) MarshalJSON() ([]byte, error) {
|
||||||
|
toSerialize, err := o.ToMap()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return json.Marshal(toSerialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FilterOptionsList) ToMap() (map[string]interface{}, error) {
|
||||||
|
toSerialize := map[string]interface{}{}
|
||||||
|
if !IsNil(o.Filters) {
|
||||||
|
toSerialize["filters"] = o.Filters
|
||||||
|
}
|
||||||
|
return toSerialize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullableFilterOptionsList struct {
|
||||||
|
value *FilterOptionsList
|
||||||
|
isSet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionsList) Get() *FilterOptionsList {
|
||||||
|
return v.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionsList) Set(val *FilterOptionsList) {
|
||||||
|
v.value = val
|
||||||
|
v.isSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionsList) IsSet() bool {
|
||||||
|
return v.isSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionsList) Unset() {
|
||||||
|
v.value = nil
|
||||||
|
v.isSet = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullableFilterOptionsList(val *FilterOptionsList) *NullableFilterOptionsList {
|
||||||
|
return &NullableFilterOptionsList{value: val, isSet: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v NullableFilterOptionsList) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NullableFilterOptionsList) UnmarshalJSON(src []byte) error {
|
||||||
|
v.isSet = true
|
||||||
|
return json.Unmarshal(src, &v.value)
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,9 @@ ASSERT_FILE_PATH="$1/type_asserts.go"
|
||||||
PROJECT_ROOT=$(realpath "$(dirname "$0")"/..)
|
PROJECT_ROOT=$(realpath "$(dirname "$0")"/..)
|
||||||
|
|
||||||
# These files generate with incorrect logic:
|
# These files generate with incorrect logic:
|
||||||
rm -f "$1/model_metadata_value.go" "$1/model_catalog_artifact.go"
|
rm -f "$1/model_metadata_value.go" \
|
||||||
|
"$1/model_catalog_artifact.go" \
|
||||||
|
"$1/model_filter_option.go"
|
||||||
|
|
||||||
python3 "${PROJECT_ROOT}/scripts/gen_type_asserts.py" $1 >"$ASSERT_FILE_PATH"
|
python3 "${PROJECT_ROOT}/scripts/gen_type_asserts.py" $1 >"$ASSERT_FILE_PATH"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue