mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 02:35:56 +08:00
feat(sqlmigration): cleanup the licenses and sites table (#7422)
* feat(sqlmigration): added migration for schema cleanup * feat(sqlmigration): drop sites,licenses table and added uuid v7 for saved views * feat(sqlmigration): commit the transaction * feat(sqlmigration): address review comments * feat(sqlmigration): address review comments * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views
This commit is contained in:
parent
9c25a33cd9
commit
64071165c4
@ -199,12 +199,12 @@ function ExplorerCard({
|
||||
value={viewName || undefined}
|
||||
>
|
||||
{viewsData?.data.data.map((view) => (
|
||||
<Select.Option key={view.uuid} value={view.name}>
|
||||
<Select.Option key={view.id} value={view.name}>
|
||||
<MenuItemGenerator
|
||||
viewName={view.name}
|
||||
viewKey={viewKey}
|
||||
createdBy={view.createdBy}
|
||||
uuid={view.uuid}
|
||||
uuid={view.id}
|
||||
refetchAllView={refetchAllView}
|
||||
viewData={viewsData.data.data}
|
||||
sourcePage={sourcepage}
|
||||
|
@ -53,17 +53,12 @@ function MenuItemGenerator({
|
||||
({ key }: { key: string }): void => {
|
||||
const currentViewDetails = getViewDetailsUsingViewKey(key, viewData);
|
||||
if (!currentViewDetails) return;
|
||||
const {
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
panelType: currentPanelType,
|
||||
} = currentViewDetails;
|
||||
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||
|
||||
handleExplorerTabChange(currentPanelType, {
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
id,
|
||||
});
|
||||
},
|
||||
[viewData, handleExplorerTabChange],
|
||||
|
@ -4,7 +4,7 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
export const viewMockData: ViewProps[] = [
|
||||
{
|
||||
uuid: 'view1',
|
||||
id: 'view1',
|
||||
name: 'View 1',
|
||||
createdBy: 'User 1',
|
||||
category: 'category 1',
|
||||
@ -17,7 +17,7 @@ export const viewMockData: ViewProps[] = [
|
||||
updatedBy: 'User 1',
|
||||
},
|
||||
{
|
||||
uuid: 'view2',
|
||||
id: 'view2',
|
||||
name: 'View 2',
|
||||
createdBy: 'User 2',
|
||||
category: 'category 2',
|
||||
|
@ -25,9 +25,9 @@ describe('MenuItemGenerator', () => {
|
||||
<MockQueryClientProvider>
|
||||
<MenuItemGenerator
|
||||
viewName={viewMockData[0].name}
|
||||
viewKey={viewMockData[0].uuid}
|
||||
viewKey={viewMockData[0].id}
|
||||
createdBy={viewMockData[0].createdBy}
|
||||
uuid={viewMockData[0].uuid}
|
||||
uuid={viewMockData[0].id}
|
||||
refetchAllView={jest.fn()}
|
||||
viewData={viewMockData}
|
||||
sourcePage={DataSource.TRACES}
|
||||
@ -43,9 +43,9 @@ describe('MenuItemGenerator', () => {
|
||||
<MockQueryClientProvider>
|
||||
<MenuItemGenerator
|
||||
viewName={viewMockData[0].name}
|
||||
viewKey={viewMockData[0].uuid}
|
||||
viewKey={viewMockData[0].id}
|
||||
createdBy={viewMockData[0].createdBy}
|
||||
uuid={viewMockData[0].uuid}
|
||||
uuid={viewMockData[0].id}
|
||||
refetchAllView={jest.fn()}
|
||||
viewData={viewMockData}
|
||||
sourcePage={DataSource.TRACES}
|
||||
|
@ -26,7 +26,7 @@ export type GetViewDetailsUsingViewKey = (
|
||||
| {
|
||||
query: Query;
|
||||
name: string;
|
||||
uuid: string;
|
||||
id: string;
|
||||
panelType: PANEL_TYPES;
|
||||
extraData?: string;
|
||||
}
|
||||
|
@ -27,11 +27,11 @@ export const getViewDetailsUsingViewKey: GetViewDetailsUsingViewKey = (
|
||||
viewKey,
|
||||
data,
|
||||
) => {
|
||||
const selectedView = data?.find((view) => view.uuid === viewKey);
|
||||
const selectedView = data?.find((view) => view.id === viewKey);
|
||||
if (selectedView) {
|
||||
const { compositeQuery, name, uuid, extraData } = selectedView;
|
||||
const { compositeQuery, name, id, extraData } = selectedView;
|
||||
const query = mapQueryDataFromApi(compositeQuery);
|
||||
return { query, name, uuid, panelType: compositeQuery.panelType, extraData };
|
||||
return { query, name, id, panelType: compositeQuery.panelType, extraData };
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
@ -223,7 +223,7 @@ function ExplorerOptions({
|
||||
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
|
||||
const viewKey = useGetSearchQueryParam(QueryParams.viewKey) || '';
|
||||
|
||||
const extraData = viewsData?.data?.data?.find((view) => view.uuid === viewKey)
|
||||
const extraData = viewsData?.data?.data?.find((view) => view.id === viewKey)
|
||||
?.extraData;
|
||||
|
||||
const extraDataColor = extraData ? JSON.parse(extraData).color : '';
|
||||
@ -357,17 +357,12 @@ function ExplorerOptions({
|
||||
viewsData?.data?.data,
|
||||
);
|
||||
if (!currentViewDetails) return;
|
||||
const {
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
panelType: currentPanelType,
|
||||
} = currentViewDetails;
|
||||
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||
|
||||
handleExplorerTabChange(currentPanelType, {
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
id,
|
||||
});
|
||||
},
|
||||
[viewsData, handleExplorerTabChange],
|
||||
@ -694,7 +689,7 @@ function ExplorerOptions({
|
||||
bgColor = extraData.color;
|
||||
}
|
||||
return (
|
||||
<Select.Option key={view.uuid} value={view.name}>
|
||||
<Select.Option key={view.id} value={view.name}>
|
||||
<div className="render-options">
|
||||
<span
|
||||
className="dot"
|
||||
|
@ -63,17 +63,17 @@ export default function SavedViews({
|
||||
|
||||
const handleRedirectQuery = (view: ViewProps): void => {
|
||||
logEvent('Homepage: Saved view clicked', {
|
||||
viewId: view.uuid,
|
||||
viewId: view.id,
|
||||
viewName: view.name,
|
||||
entity: selectedEntity,
|
||||
});
|
||||
|
||||
const currentViewDetails = getViewDetailsUsingViewKey(
|
||||
view.uuid,
|
||||
view.id,
|
||||
selectedEntity === 'logs' ? logsViews : tracesViews,
|
||||
);
|
||||
if (!currentViewDetails) return;
|
||||
const { query, name, uuid, panelType: currentPanelType } = currentViewDetails;
|
||||
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||
|
||||
if (selectedEntity) {
|
||||
handleExplorerTabChange(
|
||||
@ -81,7 +81,7 @@ export default function SavedViews({
|
||||
{
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
id,
|
||||
},
|
||||
SOURCEPAGE_VS_ROUTES[selectedEntity],
|
||||
);
|
||||
|
@ -70,7 +70,7 @@ export const useHandleExplorerTabChange = (): {
|
||||
{
|
||||
[QueryParams.panelTypes]: newPanelType,
|
||||
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
||||
[QueryParams.viewKey]: currentQueryData?.uuid || viewKey,
|
||||
[QueryParams.viewKey]: currentQueryData?.id || viewKey,
|
||||
},
|
||||
redirectToUrl,
|
||||
);
|
||||
@ -78,7 +78,7 @@ export const useHandleExplorerTabChange = (): {
|
||||
redirectWithQueryBuilderData(query, {
|
||||
[QueryParams.panelTypes]: newPanelType,
|
||||
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
||||
[QueryParams.viewKey]: currentQueryData?.uuid || viewKey,
|
||||
[QueryParams.viewKey]: currentQueryData?.id || viewKey,
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -90,6 +90,6 @@ export const useHandleExplorerTabChange = (): {
|
||||
|
||||
interface ICurrentQueryData {
|
||||
name: string;
|
||||
uuid: string;
|
||||
id: string;
|
||||
query: Query;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ export const explorerView = {
|
||||
status: 'success',
|
||||
data: [
|
||||
{
|
||||
uuid: 'test-uuid-1',
|
||||
id: 'test-uuid-1',
|
||||
name: 'Table View',
|
||||
category: '',
|
||||
createdAt: '2023-08-29T18:04:10.906310033Z',
|
||||
@ -78,7 +78,7 @@ export const explorerView = {
|
||||
extraData: '{"color":"#00ffd0"}',
|
||||
},
|
||||
{
|
||||
uuid: '8c4bf492-d54d-4ab2-a8d6-9c1563f46e1f',
|
||||
id: '8c4bf492-d54d-4ab2-a8d6-9c1563f46e1f',
|
||||
name: 'R-test panel',
|
||||
category: '',
|
||||
createdAt: '2024-07-01T13:45:57.924686766Z',
|
||||
|
@ -81,7 +81,7 @@ function SaveView(): JSX.Element {
|
||||
};
|
||||
|
||||
const handleEditModelOpen = (view: ViewProps, color: string): void => {
|
||||
setActiveViewKey(view.uuid);
|
||||
setActiveViewKey(view.id);
|
||||
setColor(color);
|
||||
setActiveViewName(view.name);
|
||||
setNewViewName(view.name);
|
||||
@ -188,11 +188,11 @@ function SaveView(): JSX.Element {
|
||||
|
||||
const handleRedirectQuery = (view: ViewProps): void => {
|
||||
const currentViewDetails = getViewDetailsUsingViewKey(
|
||||
view.uuid,
|
||||
view.id,
|
||||
viewsData?.data.data,
|
||||
);
|
||||
if (!currentViewDetails) return;
|
||||
const { query, name, uuid, panelType: currentPanelType } = currentViewDetails;
|
||||
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||
|
||||
if (sourcepage) {
|
||||
handleExplorerTabChange(
|
||||
@ -200,7 +200,7 @@ function SaveView(): JSX.Element {
|
||||
{
|
||||
query,
|
||||
name,
|
||||
uuid,
|
||||
id,
|
||||
},
|
||||
SOURCEPAGE_VS_ROUTES[sourcepage],
|
||||
);
|
||||
@ -258,7 +258,7 @@ function SaveView(): JSX.Element {
|
||||
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||
color={Color.BG_CHERRY_500}
|
||||
data-testid="delete-view"
|
||||
onClick={(): void => handleDeleteModelOpen(view.uuid, view.name)}
|
||||
onClick={(): void => handleDeleteModelOpen(view.id, view.name)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
import { ICompositeMetricQuery } from '../alerts/compositeQuery';
|
||||
|
||||
export interface ViewProps {
|
||||
uuid: string;
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
createdAt: string;
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/google/uuid"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -47,7 +47,7 @@ func GetViews(ctx context.Context, orgID string) ([]*v3.SavedView, error) {
|
||||
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||
}
|
||||
savedViews = append(savedViews, &v3.SavedView{
|
||||
UUID: view.UUID,
|
||||
ID: view.ID,
|
||||
Name: view.Name,
|
||||
Category: view.Category,
|
||||
CreatedAt: view.CreatedAt,
|
||||
@ -83,7 +83,7 @@ func GetViewsForFilters(ctx context.Context, orgID string, sourcePage string, na
|
||||
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||
}
|
||||
savedViews = append(savedViews, &v3.SavedView{
|
||||
UUID: view.UUID,
|
||||
ID: view.ID,
|
||||
Name: view.Name,
|
||||
CreatedAt: view.CreatedAt,
|
||||
CreatedBy: view.CreatedBy,
|
||||
@ -98,23 +98,19 @@ func GetViewsForFilters(ctx context.Context, orgID string, sourcePage string, na
|
||||
return savedViews, nil
|
||||
}
|
||||
|
||||
func CreateView(ctx context.Context, orgID string, view v3.SavedView) (string, error) {
|
||||
func CreateView(ctx context.Context, orgID string, view v3.SavedView) (valuer.UUID, error) {
|
||||
data, err := json.Marshal(view.CompositeQuery)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
||||
return valuer.UUID{}, fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
||||
}
|
||||
|
||||
uuid_ := view.UUID
|
||||
|
||||
if uuid_ == "" {
|
||||
uuid_ = uuid.New().String()
|
||||
}
|
||||
uuid := valuer.GenerateUUID()
|
||||
createdAt := time.Now()
|
||||
updatedAt := time.Now()
|
||||
|
||||
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("error in getting email from context")
|
||||
return valuer.UUID{}, fmt.Errorf("error in getting email from context")
|
||||
}
|
||||
|
||||
createBy := claims.Email
|
||||
@ -129,8 +125,10 @@ func CreateView(ctx context.Context, orgID string, view v3.SavedView) (string, e
|
||||
CreatedBy: createBy,
|
||||
UpdatedBy: updatedBy,
|
||||
},
|
||||
OrgID: orgID,
|
||||
UUID: uuid_,
|
||||
OrgID: orgID,
|
||||
Identifiable: types.Identifiable{
|
||||
ID: uuid,
|
||||
},
|
||||
Name: view.Name,
|
||||
Category: view.Category,
|
||||
SourcePage: view.SourcePage,
|
||||
@ -141,14 +139,14 @@ func CreateView(ctx context.Context, orgID string, view v3.SavedView) (string, e
|
||||
|
||||
_, err = store.BunDB().NewInsert().Model(&dbView).Exec(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error in creating saved view: %s", err.Error())
|
||||
return valuer.UUID{}, fmt.Errorf("error in creating saved view: %s", err.Error())
|
||||
}
|
||||
return uuid_, nil
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func GetView(ctx context.Context, orgID string, uuid_ string) (*v3.SavedView, error) {
|
||||
func GetView(ctx context.Context, orgID string, uuid valuer.UUID) (*v3.SavedView, error) {
|
||||
var view types.SavedView
|
||||
err := store.BunDB().NewSelect().Model(&view).Where("org_id = ? AND uuid = ?", orgID, uuid_).Scan(ctx)
|
||||
err := store.BunDB().NewSelect().Model(&view).Where("org_id = ? AND id = ?", orgID, uuid.StringValue()).Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in getting saved view: %s", err.Error())
|
||||
}
|
||||
@ -159,7 +157,7 @@ func GetView(ctx context.Context, orgID string, uuid_ string) (*v3.SavedView, er
|
||||
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||
}
|
||||
return &v3.SavedView{
|
||||
UUID: view.UUID,
|
||||
ID: view.ID,
|
||||
Name: view.Name,
|
||||
Category: view.Category,
|
||||
CreatedAt: view.CreatedAt,
|
||||
@ -173,7 +171,7 @@ func GetView(ctx context.Context, orgID string, uuid_ string) (*v3.SavedView, er
|
||||
}, nil
|
||||
}
|
||||
|
||||
func UpdateView(ctx context.Context, orgID string, uuid_ string, view v3.SavedView) error {
|
||||
func UpdateView(ctx context.Context, orgID string, uuid valuer.UUID, view v3.SavedView) error {
|
||||
data, err := json.Marshal(view.CompositeQuery)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
||||
@ -191,7 +189,7 @@ func UpdateView(ctx context.Context, orgID string, uuid_ string, view v3.SavedVi
|
||||
Model(&types.SavedView{}).
|
||||
Set("updated_at = ?, updated_by = ?, name = ?, category = ?, source_page = ?, tags = ?, data = ?, extra_data = ?",
|
||||
updatedAt, updatedBy, view.Name, view.Category, view.SourcePage, strings.Join(view.Tags, ","), data, view.ExtraData).
|
||||
Where("uuid = ?", uuid_).
|
||||
Where("id = ?", uuid.StringValue()).
|
||||
Where("org_id = ?", orgID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
@ -200,10 +198,10 @@ func UpdateView(ctx context.Context, orgID string, uuid_ string, view v3.SavedVi
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteView(ctx context.Context, orgID string, uuid_ string) error {
|
||||
func DeleteView(ctx context.Context, orgID string, uuid valuer.UUID) error {
|
||||
_, err := store.BunDB().NewDelete().
|
||||
Model(&types.SavedView{}).
|
||||
Where("uuid = ?", uuid_).
|
||||
Where("id = ?", uuid.StringValue()).
|
||||
Where("org_id = ?", orgID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/http/render"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/metricsexplorer"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
@ -4625,12 +4626,18 @@ func (aH *APIHandler) createSavedViews(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (aH *APIHandler) getSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
viewID := mux.Vars(r)["viewId"]
|
||||
viewUUID, err := valuer.NewUUID(viewID)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||
if !ok {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||
return
|
||||
}
|
||||
view, err := explorer.GetView(r.Context(), claims.OrgID, viewID)
|
||||
view, err := explorer.GetView(r.Context(), claims.OrgID, viewUUID)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
@ -4641,8 +4648,13 @@ func (aH *APIHandler) getSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (aH *APIHandler) updateSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
viewID := mux.Vars(r)["viewId"]
|
||||
viewUUID, err := valuer.NewUUID(viewID)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
var view v3.SavedView
|
||||
err := json.NewDecoder(r.Body).Decode(&view)
|
||||
err = json.NewDecoder(r.Body).Decode(&view)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||
return
|
||||
@ -4658,7 +4670,7 @@ func (aH *APIHandler) updateSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||
return
|
||||
}
|
||||
err = explorer.UpdateView(r.Context(), claims.OrgID, viewID, view)
|
||||
err = explorer.UpdateView(r.Context(), claims.OrgID, viewUUID, view)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
@ -4670,12 +4682,17 @@ func (aH *APIHandler) updateSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
func (aH *APIHandler) deleteSavedView(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
viewID := mux.Vars(r)["viewId"]
|
||||
viewUUID, err := valuer.NewUUID(viewID)
|
||||
if err != nil {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeInvalidInput, errorsV2.CodeInvalidInput, err.Error()))
|
||||
return
|
||||
}
|
||||
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||
if !ok {
|
||||
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||
return
|
||||
}
|
||||
err := explorer.DeleteView(r.Context(), claims.OrgID, viewID)
|
||||
err = explorer.DeleteView(r.Context(), claims.OrgID, viewUUID)
|
||||
if err != nil {
|
||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||
return
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@ -1412,7 +1412,7 @@ func (p *Point) UnmarshalJSON(data []byte) error {
|
||||
// The source page name is used to identify the page that initiated the query
|
||||
// The source page could be "traces", "logs", "metrics".
|
||||
type SavedView struct {
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
ID valuer.UUID `json:"id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
@ -1432,9 +1432,6 @@ func (eq *SavedView) Validate() error {
|
||||
return fmt.Errorf("composite query is required")
|
||||
}
|
||||
|
||||
if eq.UUID == "" {
|
||||
eq.UUID = uuid.New().String()
|
||||
}
|
||||
return eq.CompositeQuery.Validate()
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ func NewSQLMigrationProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedM
|
||||
sqlmigration.NewUpdateDashboardAndSavedViewsFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePatAndOrgDomainsFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePipelines(sqlstore),
|
||||
sqlmigration.NewDropLicensesSitesFactory(sqlstore),
|
||||
)
|
||||
}
|
||||
|
||||
|
62
pkg/sqlmigration/018_drop_licenses_sites.go
Normal file
62
pkg/sqlmigration/018_drop_licenses_sites.go
Normal file
@ -0,0 +1,62 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type dropLicensesSites struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewDropLicensesSitesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("drop_licenses_sites"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newDropLicensesSites(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newDropLicensesSites(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &dropLicensesSites{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if _, err := tx.NewDropTable().IfExists().Table("sites").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := tx.NewDropTable().IfExists().Table("licenses").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = migration.store.Dialect().RenameColumn(ctx, tx, "saved_views", "uuid", "id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
@ -6,10 +6,10 @@ import (
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type PGDialect struct {
|
||||
type dialect struct {
|
||||
}
|
||||
|
||||
func (dialect *PGDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -21,16 +21,22 @@ func (dialect *PGDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB
|
||||
}
|
||||
|
||||
// if the columns is integer then do this
|
||||
if _, err := bun.ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
if _, err := bun.
|
||||
ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new timestamp column
|
||||
if _, err := bun.NewAddColumn().Table(table).ColumnExpr(column + " TIMESTAMP").Exec(ctx); err != nil {
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " TIMESTAMP").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := bun.NewUpdate().
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = to_timestamp(cast(" + column + "_old as INTEGER))").
|
||||
Where("1=1").
|
||||
@ -39,14 +45,18 @@ func (dialect *PGDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB
|
||||
}
|
||||
|
||||
// drop old column
|
||||
if _, err := bun.NewDropColumn().Table(table).Column(column + "_old").Exec(ctx); err != nil {
|
||||
if _, err := bun.
|
||||
NewDropColumn().
|
||||
Table(table).
|
||||
Column(column + "_old").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *PGDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -56,12 +66,17 @@ func (dialect *PGDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB,
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := bun.ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
if _, err := bun.
|
||||
ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new boolean column
|
||||
if _, err := bun.NewAddColumn().Table(table).ColumnExpr(column + " BOOLEAN").Exec(ctx); err != nil {
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " BOOLEAN").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -82,7 +97,7 @@ func (dialect *PGDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *PGDialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
var columnType string
|
||||
|
||||
err := bun.NewSelect().
|
||||
@ -98,7 +113,7 @@ func (dialect *PGDialect) GetColumnType(ctx context.Context, bun bun.IDB, table
|
||||
return columnType, nil
|
||||
}
|
||||
|
||||
func (dialect *PGDialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
var count int
|
||||
err := bun.NewSelect().
|
||||
ColumnExpr("COUNT(*)").
|
||||
@ -113,3 +128,26 @@ func (dialect *PGDialect) ColumnExists(ctx context.Context, bun bun.IDB, table s
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
oldColumnExists, err := dialect.ColumnExists(ctx, bun, table, oldColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newColumnExists, err := dialect.ColumnExists(ctx, bun, table, newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !oldColumnExists && newColumnExists {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, "ALTER TABLE "+table+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ type provider struct {
|
||||
sqldb *sql.DB
|
||||
bundb *sqlstore.BunDB
|
||||
sqlxdb *sqlx.DB
|
||||
dialect *PGDialect
|
||||
dialect *dialect
|
||||
}
|
||||
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
@ -60,7 +60,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
sqldb: sqldb,
|
||||
bundb: sqlstore.NewBunDB(settings, sqldb, pgdialect.New(), hooks),
|
||||
sqlxdb: sqlx.NewDb(sqldb, "postgres"),
|
||||
dialect: &PGDialect{},
|
||||
dialect: new(dialect),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type SQLiteDialect struct {
|
||||
type dialect struct {
|
||||
}
|
||||
|
||||
func (dialect *SQLiteDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -25,12 +25,17 @@ func (dialect *SQLiteDialect) MigrateIntToTimestamp(ctx context.Context, bun bun
|
||||
}
|
||||
|
||||
// add new timestamp column
|
||||
if _, err := bun.NewAddColumn().Table(table).ColumnExpr(column + " TIMESTAMP").Exec(ctx); err != nil {
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " TIMESTAMP").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy data from old column to new column, converting from int (unix timestamp) to timestamp
|
||||
if _, err := bun.NewUpdate().
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = datetime(" + column + "_old, 'unixepoch')").
|
||||
Where("1=1").
|
||||
@ -46,7 +51,7 @@ func (dialect *SQLiteDialect) MigrateIntToTimestamp(ctx context.Context, bun bun
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *SQLiteDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,7 +71,8 @@ func (dialect *SQLiteDialect) MigrateIntToBoolean(ctx context.Context, bun bun.I
|
||||
}
|
||||
|
||||
// copy data from old column to new column, converting from int to boolean
|
||||
if _, err := bun.NewUpdate().
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = CASE WHEN " + column + "_old = 1 THEN true ELSE false END").
|
||||
Where("1=1").
|
||||
@ -82,10 +88,11 @@ func (dialect *SQLiteDialect) MigrateIntToBoolean(ctx context.Context, bun bun.I
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *SQLiteDialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
var columnType string
|
||||
|
||||
err := bun.NewSelect().
|
||||
err := bun.
|
||||
NewSelect().
|
||||
ColumnExpr("type").
|
||||
TableExpr("pragma_table_info(?)", table).
|
||||
Where("name = ?", column).
|
||||
@ -97,7 +104,7 @@ func (dialect *SQLiteDialect) GetColumnType(ctx context.Context, bun bun.IDB, ta
|
||||
return columnType, nil
|
||||
}
|
||||
|
||||
func (dialect *SQLiteDialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
var count int
|
||||
err := bun.NewSelect().
|
||||
ColumnExpr("COUNT(*)").
|
||||
@ -111,3 +118,26 @@ func (dialect *SQLiteDialect) ColumnExists(ctx context.Context, bun bun.IDB, tab
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
oldColumnExists, err := dialect.ColumnExists(ctx, bun, table, oldColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newColumnExists, err := dialect.ColumnExists(ctx, bun, table, newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !oldColumnExists && newColumnExists {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, "ALTER TABLE "+table+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ type provider struct {
|
||||
sqldb *sql.DB
|
||||
bundb *sqlstore.BunDB
|
||||
sqlxdb *sqlx.DB
|
||||
dialect *SQLiteDialect
|
||||
dialect *dialect
|
||||
}
|
||||
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
@ -50,7 +50,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
sqldb: sqldb,
|
||||
bundb: sqlstore.NewBunDB(settings, sqldb, sqlitedialect.New(), hooks),
|
||||
sqlxdb: sqlx.NewDb(sqldb, "sqlite3"),
|
||||
dialect: &SQLiteDialect{},
|
||||
dialect: new(dialect),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,9 @@ type SQLStoreHook interface {
|
||||
}
|
||||
|
||||
type SQLDialect interface {
|
||||
MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error
|
||||
MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error
|
||||
GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error)
|
||||
ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error)
|
||||
MigrateIntToTimestamp(context.Context, bun.IDB, string, string) error
|
||||
MigrateIntToBoolean(context.Context, bun.IDB, string, string) error
|
||||
GetColumnType(context.Context, bun.IDB, string, string) (string, error)
|
||||
ColumnExists(context.Context, bun.IDB, string, string) (bool, error)
|
||||
RenameColumn(context.Context, bun.IDB, string, string, string) (bool, error)
|
||||
}
|
||||
|
@ -6,21 +6,25 @@ import (
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type TestDialect struct {
|
||||
type dialect struct {
|
||||
}
|
||||
|
||||
func (dialect *TestDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *TestDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
func (dialect *dialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *TestDialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (dialect *TestDialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ type Provider struct {
|
||||
mock sqlmock.Sqlmock
|
||||
bunDB *bun.DB
|
||||
sqlxDB *sqlx.DB
|
||||
dialect *TestDialect
|
||||
dialect *dialect
|
||||
}
|
||||
|
||||
func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
||||
@ -43,7 +43,7 @@ func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
||||
mock: mock,
|
||||
bunDB: bunDB,
|
||||
sqlxDB: sqlxDB,
|
||||
dialect: &TestDialect{},
|
||||
dialect: new(dialect),
|
||||
}
|
||||
}
|
||||
|
||||
|
9
pkg/types/identity.go
Normal file
9
pkg/types/identity.go
Normal file
@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type Identifiable struct {
|
||||
ID valuer.UUID `json:"id" bun:"id,pk,type:text"`
|
||||
}
|
@ -7,10 +7,10 @@ import (
|
||||
type SavedView struct {
|
||||
bun.BaseModel `bun:"table:saved_views"`
|
||||
|
||||
Identifiable
|
||||
TimeAuditable
|
||||
UserAuditable
|
||||
OrgID string `json:"orgId" bun:"org_id,notnull"`
|
||||
UUID string `json:"uuid" bun:"uuid,pk,type:text"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
Category string `json:"category" bun:"category,type:text,notnull"`
|
||||
SourcePage string `json:"sourcePage" bun:"source_page,type:text,notnull"`
|
||||
|
120
pkg/valuer/uuid.go
Normal file
120
pkg/valuer/uuid.go
Normal file
@ -0,0 +1,120 @@
|
||||
package valuer
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var _ Valuer = (*UUID)(nil)
|
||||
|
||||
type UUID struct {
|
||||
val uuid.UUID
|
||||
}
|
||||
|
||||
func NewUUID(value string) (UUID, error) {
|
||||
val, err := uuid.Parse(value)
|
||||
if err != nil {
|
||||
return UUID{}, err
|
||||
}
|
||||
|
||||
return UUID{
|
||||
val: val,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewUUIDFromBytes(value []byte) (UUID, error) {
|
||||
val, err := uuid.ParseBytes(value)
|
||||
if err != nil {
|
||||
return UUID{}, err
|
||||
}
|
||||
|
||||
return UUID{
|
||||
val: val,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func MustNewUUID(val string) UUID {
|
||||
uuid, err := NewUUID(val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return uuid
|
||||
}
|
||||
|
||||
func GenerateUUID() UUID {
|
||||
val, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return UUID{
|
||||
val: val,
|
||||
}
|
||||
}
|
||||
|
||||
func (enum UUID) IsZero() bool {
|
||||
return enum.val == uuid.UUID{}
|
||||
}
|
||||
|
||||
func (enum UUID) StringValue() string {
|
||||
return enum.val.String()
|
||||
}
|
||||
|
||||
func (enum UUID) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(enum.StringValue())
|
||||
}
|
||||
|
||||
func (enum *UUID) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uuid, err := NewUUID(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*enum = uuid
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enum UUID) Value() (driver.Value, error) {
|
||||
return enum.StringValue(), nil
|
||||
}
|
||||
|
||||
func (enum *UUID) Scan(val interface{}) error {
|
||||
if enum == nil {
|
||||
return fmt.Errorf("uuid: (nil \"%s\")", reflect.TypeOf(enum).String())
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
return fmt.Errorf("uuid: (nil \"%s\")", reflect.TypeOf(val).String())
|
||||
}
|
||||
|
||||
var enumVal UUID
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
_enumVal, err := NewUUID(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("uuid: (invalid-uuid \"%s\")", err.Error())
|
||||
}
|
||||
enumVal = _enumVal
|
||||
case []byte:
|
||||
_enumVal, err := NewUUIDFromBytes(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("uuid: (invalid-uuid \"%s\")", err.Error())
|
||||
}
|
||||
enumVal = _enumVal
|
||||
default:
|
||||
return fmt.Errorf("uuid: (non-uuid \"%s\")", reflect.TypeOf(val).String())
|
||||
}
|
||||
|
||||
*enum = enumVal
|
||||
return nil
|
||||
}
|
22
pkg/valuer/valuer.go
Normal file
22
pkg/valuer/valuer.go
Normal file
@ -0,0 +1,22 @@
|
||||
package valuer
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Valuer interface {
|
||||
// IsZero returns true if the value is considered empty or zero
|
||||
IsZero() bool
|
||||
// StringValue returns the string representation of the value
|
||||
StringValue() string
|
||||
// MarshalJSON returns the JSON encoding of the value.
|
||||
json.Marshaler
|
||||
// UnmarshalJSON returns the JSON decoding of the value.
|
||||
json.Unmarshaler
|
||||
// Scan into underlying struct from a database driver's value
|
||||
sql.Scanner
|
||||
// Convert the struct to a database driver's value
|
||||
driver.Valuer
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user