mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 04:35:58 +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}
|
value={viewName || undefined}
|
||||||
>
|
>
|
||||||
{viewsData?.data.data.map((view) => (
|
{viewsData?.data.data.map((view) => (
|
||||||
<Select.Option key={view.uuid} value={view.name}>
|
<Select.Option key={view.id} value={view.name}>
|
||||||
<MenuItemGenerator
|
<MenuItemGenerator
|
||||||
viewName={view.name}
|
viewName={view.name}
|
||||||
viewKey={viewKey}
|
viewKey={viewKey}
|
||||||
createdBy={view.createdBy}
|
createdBy={view.createdBy}
|
||||||
uuid={view.uuid}
|
uuid={view.id}
|
||||||
refetchAllView={refetchAllView}
|
refetchAllView={refetchAllView}
|
||||||
viewData={viewsData.data.data}
|
viewData={viewsData.data.data}
|
||||||
sourcePage={sourcepage}
|
sourcePage={sourcepage}
|
||||||
|
@ -53,17 +53,12 @@ function MenuItemGenerator({
|
|||||||
({ key }: { key: string }): void => {
|
({ key }: { key: string }): void => {
|
||||||
const currentViewDetails = getViewDetailsUsingViewKey(key, viewData);
|
const currentViewDetails = getViewDetailsUsingViewKey(key, viewData);
|
||||||
if (!currentViewDetails) return;
|
if (!currentViewDetails) return;
|
||||||
const {
|
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||||
query,
|
|
||||||
name,
|
|
||||||
uuid,
|
|
||||||
panelType: currentPanelType,
|
|
||||||
} = currentViewDetails;
|
|
||||||
|
|
||||||
handleExplorerTabChange(currentPanelType, {
|
handleExplorerTabChange(currentPanelType, {
|
||||||
query,
|
query,
|
||||||
name,
|
name,
|
||||||
uuid,
|
id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[viewData, handleExplorerTabChange],
|
[viewData, handleExplorerTabChange],
|
||||||
|
@ -4,7 +4,7 @@ import { DataSource } from 'types/common/queryBuilder';
|
|||||||
|
|
||||||
export const viewMockData: ViewProps[] = [
|
export const viewMockData: ViewProps[] = [
|
||||||
{
|
{
|
||||||
uuid: 'view1',
|
id: 'view1',
|
||||||
name: 'View 1',
|
name: 'View 1',
|
||||||
createdBy: 'User 1',
|
createdBy: 'User 1',
|
||||||
category: 'category 1',
|
category: 'category 1',
|
||||||
@ -17,7 +17,7 @@ export const viewMockData: ViewProps[] = [
|
|||||||
updatedBy: 'User 1',
|
updatedBy: 'User 1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: 'view2',
|
id: 'view2',
|
||||||
name: 'View 2',
|
name: 'View 2',
|
||||||
createdBy: 'User 2',
|
createdBy: 'User 2',
|
||||||
category: 'category 2',
|
category: 'category 2',
|
||||||
|
@ -25,9 +25,9 @@ describe('MenuItemGenerator', () => {
|
|||||||
<MockQueryClientProvider>
|
<MockQueryClientProvider>
|
||||||
<MenuItemGenerator
|
<MenuItemGenerator
|
||||||
viewName={viewMockData[0].name}
|
viewName={viewMockData[0].name}
|
||||||
viewKey={viewMockData[0].uuid}
|
viewKey={viewMockData[0].id}
|
||||||
createdBy={viewMockData[0].createdBy}
|
createdBy={viewMockData[0].createdBy}
|
||||||
uuid={viewMockData[0].uuid}
|
uuid={viewMockData[0].id}
|
||||||
refetchAllView={jest.fn()}
|
refetchAllView={jest.fn()}
|
||||||
viewData={viewMockData}
|
viewData={viewMockData}
|
||||||
sourcePage={DataSource.TRACES}
|
sourcePage={DataSource.TRACES}
|
||||||
@ -43,9 +43,9 @@ describe('MenuItemGenerator', () => {
|
|||||||
<MockQueryClientProvider>
|
<MockQueryClientProvider>
|
||||||
<MenuItemGenerator
|
<MenuItemGenerator
|
||||||
viewName={viewMockData[0].name}
|
viewName={viewMockData[0].name}
|
||||||
viewKey={viewMockData[0].uuid}
|
viewKey={viewMockData[0].id}
|
||||||
createdBy={viewMockData[0].createdBy}
|
createdBy={viewMockData[0].createdBy}
|
||||||
uuid={viewMockData[0].uuid}
|
uuid={viewMockData[0].id}
|
||||||
refetchAllView={jest.fn()}
|
refetchAllView={jest.fn()}
|
||||||
viewData={viewMockData}
|
viewData={viewMockData}
|
||||||
sourcePage={DataSource.TRACES}
|
sourcePage={DataSource.TRACES}
|
||||||
|
@ -26,7 +26,7 @@ export type GetViewDetailsUsingViewKey = (
|
|||||||
| {
|
| {
|
||||||
query: Query;
|
query: Query;
|
||||||
name: string;
|
name: string;
|
||||||
uuid: string;
|
id: string;
|
||||||
panelType: PANEL_TYPES;
|
panelType: PANEL_TYPES;
|
||||||
extraData?: string;
|
extraData?: string;
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ export const getViewDetailsUsingViewKey: GetViewDetailsUsingViewKey = (
|
|||||||
viewKey,
|
viewKey,
|
||||||
data,
|
data,
|
||||||
) => {
|
) => {
|
||||||
const selectedView = data?.find((view) => view.uuid === viewKey);
|
const selectedView = data?.find((view) => view.id === viewKey);
|
||||||
if (selectedView) {
|
if (selectedView) {
|
||||||
const { compositeQuery, name, uuid, extraData } = selectedView;
|
const { compositeQuery, name, id, extraData } = selectedView;
|
||||||
const query = mapQueryDataFromApi(compositeQuery);
|
const query = mapQueryDataFromApi(compositeQuery);
|
||||||
return { query, name, uuid, panelType: compositeQuery.panelType, extraData };
|
return { query, name, id, panelType: compositeQuery.panelType, extraData };
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
@ -223,7 +223,7 @@ function ExplorerOptions({
|
|||||||
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
|
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
|
||||||
const viewKey = useGetSearchQueryParam(QueryParams.viewKey) || '';
|
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;
|
?.extraData;
|
||||||
|
|
||||||
const extraDataColor = extraData ? JSON.parse(extraData).color : '';
|
const extraDataColor = extraData ? JSON.parse(extraData).color : '';
|
||||||
@ -357,17 +357,12 @@ function ExplorerOptions({
|
|||||||
viewsData?.data?.data,
|
viewsData?.data?.data,
|
||||||
);
|
);
|
||||||
if (!currentViewDetails) return;
|
if (!currentViewDetails) return;
|
||||||
const {
|
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||||
query,
|
|
||||||
name,
|
|
||||||
uuid,
|
|
||||||
panelType: currentPanelType,
|
|
||||||
} = currentViewDetails;
|
|
||||||
|
|
||||||
handleExplorerTabChange(currentPanelType, {
|
handleExplorerTabChange(currentPanelType, {
|
||||||
query,
|
query,
|
||||||
name,
|
name,
|
||||||
uuid,
|
id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[viewsData, handleExplorerTabChange],
|
[viewsData, handleExplorerTabChange],
|
||||||
@ -694,7 +689,7 @@ function ExplorerOptions({
|
|||||||
bgColor = extraData.color;
|
bgColor = extraData.color;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Select.Option key={view.uuid} value={view.name}>
|
<Select.Option key={view.id} value={view.name}>
|
||||||
<div className="render-options">
|
<div className="render-options">
|
||||||
<span
|
<span
|
||||||
className="dot"
|
className="dot"
|
||||||
|
@ -63,17 +63,17 @@ export default function SavedViews({
|
|||||||
|
|
||||||
const handleRedirectQuery = (view: ViewProps): void => {
|
const handleRedirectQuery = (view: ViewProps): void => {
|
||||||
logEvent('Homepage: Saved view clicked', {
|
logEvent('Homepage: Saved view clicked', {
|
||||||
viewId: view.uuid,
|
viewId: view.id,
|
||||||
viewName: view.name,
|
viewName: view.name,
|
||||||
entity: selectedEntity,
|
entity: selectedEntity,
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentViewDetails = getViewDetailsUsingViewKey(
|
const currentViewDetails = getViewDetailsUsingViewKey(
|
||||||
view.uuid,
|
view.id,
|
||||||
selectedEntity === 'logs' ? logsViews : tracesViews,
|
selectedEntity === 'logs' ? logsViews : tracesViews,
|
||||||
);
|
);
|
||||||
if (!currentViewDetails) return;
|
if (!currentViewDetails) return;
|
||||||
const { query, name, uuid, panelType: currentPanelType } = currentViewDetails;
|
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||||
|
|
||||||
if (selectedEntity) {
|
if (selectedEntity) {
|
||||||
handleExplorerTabChange(
|
handleExplorerTabChange(
|
||||||
@ -81,7 +81,7 @@ export default function SavedViews({
|
|||||||
{
|
{
|
||||||
query,
|
query,
|
||||||
name,
|
name,
|
||||||
uuid,
|
id,
|
||||||
},
|
},
|
||||||
SOURCEPAGE_VS_ROUTES[selectedEntity],
|
SOURCEPAGE_VS_ROUTES[selectedEntity],
|
||||||
);
|
);
|
||||||
|
@ -70,7 +70,7 @@ export const useHandleExplorerTabChange = (): {
|
|||||||
{
|
{
|
||||||
[QueryParams.panelTypes]: newPanelType,
|
[QueryParams.panelTypes]: newPanelType,
|
||||||
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
||||||
[QueryParams.viewKey]: currentQueryData?.uuid || viewKey,
|
[QueryParams.viewKey]: currentQueryData?.id || viewKey,
|
||||||
},
|
},
|
||||||
redirectToUrl,
|
redirectToUrl,
|
||||||
);
|
);
|
||||||
@ -78,7 +78,7 @@ export const useHandleExplorerTabChange = (): {
|
|||||||
redirectWithQueryBuilderData(query, {
|
redirectWithQueryBuilderData(query, {
|
||||||
[QueryParams.panelTypes]: newPanelType,
|
[QueryParams.panelTypes]: newPanelType,
|
||||||
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
[QueryParams.viewName]: currentQueryData?.name || viewName,
|
||||||
[QueryParams.viewKey]: currentQueryData?.uuid || viewKey,
|
[QueryParams.viewKey]: currentQueryData?.id || viewKey,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -90,6 +90,6 @@ export const useHandleExplorerTabChange = (): {
|
|||||||
|
|
||||||
interface ICurrentQueryData {
|
interface ICurrentQueryData {
|
||||||
name: string;
|
name: string;
|
||||||
uuid: string;
|
id: string;
|
||||||
query: Query;
|
query: Query;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ export const explorerView = {
|
|||||||
status: 'success',
|
status: 'success',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
uuid: 'test-uuid-1',
|
id: 'test-uuid-1',
|
||||||
name: 'Table View',
|
name: 'Table View',
|
||||||
category: '',
|
category: '',
|
||||||
createdAt: '2023-08-29T18:04:10.906310033Z',
|
createdAt: '2023-08-29T18:04:10.906310033Z',
|
||||||
@ -78,7 +78,7 @@ export const explorerView = {
|
|||||||
extraData: '{"color":"#00ffd0"}',
|
extraData: '{"color":"#00ffd0"}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: '8c4bf492-d54d-4ab2-a8d6-9c1563f46e1f',
|
id: '8c4bf492-d54d-4ab2-a8d6-9c1563f46e1f',
|
||||||
name: 'R-test panel',
|
name: 'R-test panel',
|
||||||
category: '',
|
category: '',
|
||||||
createdAt: '2024-07-01T13:45:57.924686766Z',
|
createdAt: '2024-07-01T13:45:57.924686766Z',
|
||||||
|
@ -81,7 +81,7 @@ function SaveView(): JSX.Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleEditModelOpen = (view: ViewProps, color: string): void => {
|
const handleEditModelOpen = (view: ViewProps, color: string): void => {
|
||||||
setActiveViewKey(view.uuid);
|
setActiveViewKey(view.id);
|
||||||
setColor(color);
|
setColor(color);
|
||||||
setActiveViewName(view.name);
|
setActiveViewName(view.name);
|
||||||
setNewViewName(view.name);
|
setNewViewName(view.name);
|
||||||
@ -188,11 +188,11 @@ function SaveView(): JSX.Element {
|
|||||||
|
|
||||||
const handleRedirectQuery = (view: ViewProps): void => {
|
const handleRedirectQuery = (view: ViewProps): void => {
|
||||||
const currentViewDetails = getViewDetailsUsingViewKey(
|
const currentViewDetails = getViewDetailsUsingViewKey(
|
||||||
view.uuid,
|
view.id,
|
||||||
viewsData?.data.data,
|
viewsData?.data.data,
|
||||||
);
|
);
|
||||||
if (!currentViewDetails) return;
|
if (!currentViewDetails) return;
|
||||||
const { query, name, uuid, panelType: currentPanelType } = currentViewDetails;
|
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
|
||||||
|
|
||||||
if (sourcepage) {
|
if (sourcepage) {
|
||||||
handleExplorerTabChange(
|
handleExplorerTabChange(
|
||||||
@ -200,7 +200,7 @@ function SaveView(): JSX.Element {
|
|||||||
{
|
{
|
||||||
query,
|
query,
|
||||||
name,
|
name,
|
||||||
uuid,
|
id,
|
||||||
},
|
},
|
||||||
SOURCEPAGE_VS_ROUTES[sourcepage],
|
SOURCEPAGE_VS_ROUTES[sourcepage],
|
||||||
);
|
);
|
||||||
@ -258,7 +258,7 @@ function SaveView(): JSX.Element {
|
|||||||
className={isEditDeleteSupported ? '' : 'hidden'}
|
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||||
color={Color.BG_CHERRY_500}
|
color={Color.BG_CHERRY_500}
|
||||||
data-testid="delete-view"
|
data-testid="delete-view"
|
||||||
onClick={(): void => handleDeleteModelOpen(view.uuid, view.name)}
|
onClick={(): void => handleDeleteModelOpen(view.id, view.name)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@ import { DataSource } from 'types/common/queryBuilder';
|
|||||||
import { ICompositeMetricQuery } from '../alerts/compositeQuery';
|
import { ICompositeMetricQuery } from '../alerts/compositeQuery';
|
||||||
|
|
||||||
export interface ViewProps {
|
export interface ViewProps {
|
||||||
uuid: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
category: string;
|
category: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
"github.com/google/uuid"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
"go.uber.org/zap"
|
"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())
|
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||||
}
|
}
|
||||||
savedViews = append(savedViews, &v3.SavedView{
|
savedViews = append(savedViews, &v3.SavedView{
|
||||||
UUID: view.UUID,
|
ID: view.ID,
|
||||||
Name: view.Name,
|
Name: view.Name,
|
||||||
Category: view.Category,
|
Category: view.Category,
|
||||||
CreatedAt: view.CreatedAt,
|
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())
|
return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||||
}
|
}
|
||||||
savedViews = append(savedViews, &v3.SavedView{
|
savedViews = append(savedViews, &v3.SavedView{
|
||||||
UUID: view.UUID,
|
ID: view.ID,
|
||||||
Name: view.Name,
|
Name: view.Name,
|
||||||
CreatedAt: view.CreatedAt,
|
CreatedAt: view.CreatedAt,
|
||||||
CreatedBy: view.CreatedBy,
|
CreatedBy: view.CreatedBy,
|
||||||
@ -98,23 +98,19 @@ func GetViewsForFilters(ctx context.Context, orgID string, sourcePage string, na
|
|||||||
return savedViews, nil
|
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)
|
data, err := json.Marshal(view.CompositeQuery)
|
||||||
if err != nil {
|
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
|
uuid := valuer.GenerateUUID()
|
||||||
|
|
||||||
if uuid_ == "" {
|
|
||||||
uuid_ = uuid.New().String()
|
|
||||||
}
|
|
||||||
createdAt := time.Now()
|
createdAt := time.Now()
|
||||||
updatedAt := time.Now()
|
updatedAt := time.Now()
|
||||||
|
|
||||||
claims, ok := authtypes.ClaimsFromContext(ctx)
|
claims, ok := authtypes.ClaimsFromContext(ctx)
|
||||||
if !ok {
|
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
|
createBy := claims.Email
|
||||||
@ -129,8 +125,10 @@ func CreateView(ctx context.Context, orgID string, view v3.SavedView) (string, e
|
|||||||
CreatedBy: createBy,
|
CreatedBy: createBy,
|
||||||
UpdatedBy: updatedBy,
|
UpdatedBy: updatedBy,
|
||||||
},
|
},
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
UUID: uuid_,
|
Identifiable: types.Identifiable{
|
||||||
|
ID: uuid,
|
||||||
|
},
|
||||||
Name: view.Name,
|
Name: view.Name,
|
||||||
Category: view.Category,
|
Category: view.Category,
|
||||||
SourcePage: view.SourcePage,
|
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)
|
_, err = store.BunDB().NewInsert().Model(&dbView).Exec(ctx)
|
||||||
if err != nil {
|
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
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error in getting saved view: %s", err.Error())
|
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 nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error())
|
||||||
}
|
}
|
||||||
return &v3.SavedView{
|
return &v3.SavedView{
|
||||||
UUID: view.UUID,
|
ID: view.ID,
|
||||||
Name: view.Name,
|
Name: view.Name,
|
||||||
Category: view.Category,
|
Category: view.Category,
|
||||||
CreatedAt: view.CreatedAt,
|
CreatedAt: view.CreatedAt,
|
||||||
@ -173,7 +171,7 @@ func GetView(ctx context.Context, orgID string, uuid_ string) (*v3.SavedView, er
|
|||||||
}, nil
|
}, 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)
|
data, err := json.Marshal(view.CompositeQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error in marshalling explorer query data: %s", err.Error())
|
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{}).
|
Model(&types.SavedView{}).
|
||||||
Set("updated_at = ?, updated_by = ?, name = ?, category = ?, source_page = ?, tags = ?, data = ?, extra_data = ?",
|
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).
|
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).
|
Where("org_id = ?", orgID).
|
||||||
Exec(ctx)
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -200,10 +198,10 @@ func UpdateView(ctx context.Context, orgID string, uuid_ string, view v3.SavedVi
|
|||||||
return nil
|
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().
|
_, err := store.BunDB().NewDelete().
|
||||||
Model(&types.SavedView{}).
|
Model(&types.SavedView{}).
|
||||||
Where("uuid = ?", uuid_).
|
Where("id = ?", uuid.StringValue()).
|
||||||
Where("org_id = ?", orgID).
|
Where("org_id = ?", orgID).
|
||||||
Exec(ctx)
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/http/render"
|
"github.com/SigNoz/signoz/pkg/http/render"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/app/metricsexplorer"
|
"github.com/SigNoz/signoz/pkg/query-service/app/metricsexplorer"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/websocket"
|
"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) {
|
func (aH *APIHandler) getSavedView(w http.ResponseWriter, r *http.Request) {
|
||||||
viewID := mux.Vars(r)["viewId"]
|
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())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if !ok {
|
if !ok {
|
||||||
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
view, err := explorer.GetView(r.Context(), claims.OrgID, viewID)
|
view, err := explorer.GetView(r.Context(), claims.OrgID, viewUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||||
return
|
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) {
|
func (aH *APIHandler) updateSavedView(w http.ResponseWriter, r *http.Request) {
|
||||||
viewID := mux.Vars(r)["viewId"]
|
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
|
var view v3.SavedView
|
||||||
err := json.NewDecoder(r.Body).Decode(&view)
|
err = json.NewDecoder(r.Body).Decode(&view)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
|
||||||
return
|
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"))
|
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = explorer.UpdateView(r.Context(), claims.OrgID, viewID, view)
|
err = explorer.UpdateView(r.Context(), claims.OrgID, viewUUID, view)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||||
return
|
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) {
|
func (aH *APIHandler) deleteSavedView(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
viewID := mux.Vars(r)["viewId"]
|
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())
|
claims, ok := authtypes.ClaimsFromContext(r.Context())
|
||||||
if !ok {
|
if !ok {
|
||||||
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
render.Error(w, errorsV2.Newf(errorsV2.TypeUnauthenticated, errorsV2.CodeUnauthenticated, "unauthenticated"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := explorer.DeleteView(r.Context(), claims.OrgID, viewID)
|
err = explorer.DeleteView(r.Context(), claims.OrgID, viewUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
|
||||||
return
|
return
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"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 name is used to identify the page that initiated the query
|
||||||
// The source page could be "traces", "logs", "metrics".
|
// The source page could be "traces", "logs", "metrics".
|
||||||
type SavedView struct {
|
type SavedView struct {
|
||||||
UUID string `json:"uuid,omitempty"`
|
ID valuer.UUID `json:"id,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Category string `json:"category"`
|
Category string `json:"category"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
@ -1432,9 +1432,6 @@ func (eq *SavedView) Validate() error {
|
|||||||
return fmt.Errorf("composite query is required")
|
return fmt.Errorf("composite query is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if eq.UUID == "" {
|
|
||||||
eq.UUID = uuid.New().String()
|
|
||||||
}
|
|
||||||
return eq.CompositeQuery.Validate()
|
return eq.CompositeQuery.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ func NewSQLMigrationProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedM
|
|||||||
sqlmigration.NewUpdateDashboardAndSavedViewsFactory(sqlstore),
|
sqlmigration.NewUpdateDashboardAndSavedViewsFactory(sqlstore),
|
||||||
sqlmigration.NewUpdatePatAndOrgDomainsFactory(sqlstore),
|
sqlmigration.NewUpdatePatAndOrgDomainsFactory(sqlstore),
|
||||||
sqlmigration.NewUpdatePipelines(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"
|
"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)
|
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new timestamp column
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := bun.NewUpdate().
|
if _, err := bun.
|
||||||
|
NewUpdate().
|
||||||
Table(table).
|
Table(table).
|
||||||
Set(column + " = to_timestamp(cast(" + column + "_old as INTEGER))").
|
Set(column + " = to_timestamp(cast(" + column + "_old as INTEGER))").
|
||||||
Where("1=1").
|
Where("1=1").
|
||||||
@ -39,14 +45,18 @@ func (dialect *PGDialect) MigrateIntToTimestamp(ctx context.Context, bun bun.IDB
|
|||||||
}
|
}
|
||||||
|
|
||||||
// drop old column
|
// 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 err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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)
|
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -56,12 +66,17 @@ func (dialect *PGDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB,
|
|||||||
return nil
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new boolean column
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +97,7 @@ func (dialect *PGDialect) MigrateIntToBoolean(ctx context.Context, bun bun.IDB,
|
|||||||
return nil
|
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
|
var columnType string
|
||||||
|
|
||||||
err := bun.NewSelect().
|
err := bun.NewSelect().
|
||||||
@ -98,7 +113,7 @@ func (dialect *PGDialect) GetColumnType(ctx context.Context, bun bun.IDB, table
|
|||||||
return columnType, nil
|
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
|
var count int
|
||||||
err := bun.NewSelect().
|
err := bun.NewSelect().
|
||||||
ColumnExpr("COUNT(*)").
|
ColumnExpr("COUNT(*)").
|
||||||
@ -113,3 +128,26 @@ func (dialect *PGDialect) ColumnExists(ctx context.Context, bun bun.IDB, table s
|
|||||||
|
|
||||||
return count > 0, nil
|
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
|
sqldb *sql.DB
|
||||||
bundb *sqlstore.BunDB
|
bundb *sqlstore.BunDB
|
||||||
sqlxdb *sqlx.DB
|
sqlxdb *sqlx.DB
|
||||||
dialect *PGDialect
|
dialect *dialect
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
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,
|
sqldb: sqldb,
|
||||||
bundb: sqlstore.NewBunDB(settings, sqldb, pgdialect.New(), hooks),
|
bundb: sqlstore.NewBunDB(settings, sqldb, pgdialect.New(), hooks),
|
||||||
sqlxdb: sqlx.NewDb(sqldb, "postgres"),
|
sqlxdb: sqlx.NewDb(sqldb, "postgres"),
|
||||||
dialect: &PGDialect{},
|
dialect: new(dialect),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,10 @@ import (
|
|||||||
"github.com/uptrace/bun"
|
"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)
|
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -25,12 +25,17 @@ func (dialect *SQLiteDialect) MigrateIntToTimestamp(ctx context.Context, bun bun
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add new timestamp column
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy data from old column to new column, converting from int (unix timestamp) to timestamp
|
// 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).
|
Table(table).
|
||||||
Set(column + " = datetime(" + column + "_old, 'unixepoch')").
|
Set(column + " = datetime(" + column + "_old, 'unixepoch')").
|
||||||
Where("1=1").
|
Where("1=1").
|
||||||
@ -46,7 +51,7 @@ func (dialect *SQLiteDialect) MigrateIntToTimestamp(ctx context.Context, bun bun
|
|||||||
return nil
|
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)
|
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// copy data from old column to new column, converting from int to boolean
|
||||||
if _, err := bun.NewUpdate().
|
if _, err := bun.
|
||||||
|
NewUpdate().
|
||||||
Table(table).
|
Table(table).
|
||||||
Set(column + " = CASE WHEN " + column + "_old = 1 THEN true ELSE false END").
|
Set(column + " = CASE WHEN " + column + "_old = 1 THEN true ELSE false END").
|
||||||
Where("1=1").
|
Where("1=1").
|
||||||
@ -82,10 +88,11 @@ func (dialect *SQLiteDialect) MigrateIntToBoolean(ctx context.Context, bun bun.I
|
|||||||
return nil
|
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
|
var columnType string
|
||||||
|
|
||||||
err := bun.NewSelect().
|
err := bun.
|
||||||
|
NewSelect().
|
||||||
ColumnExpr("type").
|
ColumnExpr("type").
|
||||||
TableExpr("pragma_table_info(?)", table).
|
TableExpr("pragma_table_info(?)", table).
|
||||||
Where("name = ?", column).
|
Where("name = ?", column).
|
||||||
@ -97,7 +104,7 @@ func (dialect *SQLiteDialect) GetColumnType(ctx context.Context, bun bun.IDB, ta
|
|||||||
return columnType, nil
|
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
|
var count int
|
||||||
err := bun.NewSelect().
|
err := bun.NewSelect().
|
||||||
ColumnExpr("COUNT(*)").
|
ColumnExpr("COUNT(*)").
|
||||||
@ -111,3 +118,26 @@ func (dialect *SQLiteDialect) ColumnExists(ctx context.Context, bun bun.IDB, tab
|
|||||||
|
|
||||||
return count > 0, nil
|
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
|
sqldb *sql.DB
|
||||||
bundb *sqlstore.BunDB
|
bundb *sqlstore.BunDB
|
||||||
sqlxdb *sqlx.DB
|
sqlxdb *sqlx.DB
|
||||||
dialect *SQLiteDialect
|
dialect *dialect
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
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,
|
sqldb: sqldb,
|
||||||
bundb: sqlstore.NewBunDB(settings, sqldb, sqlitedialect.New(), hooks),
|
bundb: sqlstore.NewBunDB(settings, sqldb, sqlitedialect.New(), hooks),
|
||||||
sqlxdb: sqlx.NewDb(sqldb, "sqlite3"),
|
sqlxdb: sqlx.NewDb(sqldb, "sqlite3"),
|
||||||
dialect: &SQLiteDialect{},
|
dialect: new(dialect),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ type SQLStoreHook interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SQLDialect interface {
|
type SQLDialect interface {
|
||||||
MigrateIntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error
|
MigrateIntToTimestamp(context.Context, bun.IDB, string, string) error
|
||||||
MigrateIntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error
|
MigrateIntToBoolean(context.Context, bun.IDB, string, string) error
|
||||||
GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error)
|
GetColumnType(context.Context, bun.IDB, string, string) (string, error)
|
||||||
ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, 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"
|
"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
|
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
|
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
|
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
|
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
|
mock sqlmock.Sqlmock
|
||||||
bunDB *bun.DB
|
bunDB *bun.DB
|
||||||
sqlxDB *sqlx.DB
|
sqlxDB *sqlx.DB
|
||||||
dialect *TestDialect
|
dialect *dialect
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
||||||
@ -43,7 +43,7 @@ func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
|||||||
mock: mock,
|
mock: mock,
|
||||||
bunDB: bunDB,
|
bunDB: bunDB,
|
||||||
sqlxDB: sqlxDB,
|
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 {
|
type SavedView struct {
|
||||||
bun.BaseModel `bun:"table:saved_views"`
|
bun.BaseModel `bun:"table:saved_views"`
|
||||||
|
|
||||||
|
Identifiable
|
||||||
TimeAuditable
|
TimeAuditable
|
||||||
UserAuditable
|
UserAuditable
|
||||||
OrgID string `json:"orgId" bun:"org_id,notnull"`
|
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"`
|
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||||
Category string `json:"category" bun:"category,type:text,notnull"`
|
Category string `json:"category" bun:"category,type:text,notnull"`
|
||||||
SourcePage string `json:"sourcePage" bun:"source_page,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