Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ build
.vscode
mcp.yaml
oas/**
mise.toml
100 changes: 100 additions & 0 deletions pkg/clients/add_business_term_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package clients

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)

// AddBusinessTermAssetRequest is the request body for creating a business term asset.
type AddBusinessTermAssetRequest struct {
Name string `json:"name"`
TypePublicId string `json:"typePublicId"`
DomainId string `json:"domainId"`
}

// AddBusinessTermAssetResponse is the response from creating a business term asset.
type AddBusinessTermAssetResponse struct {
Id string `json:"id"`
}

// AddBusinessTermAttributeRequest is the request body for adding an attribute to an asset.
type AddBusinessTermAttributeRequest struct {
AssetId string `json:"assetId"`
TypeId string `json:"typeId"`
Value string `json:"value"`
}

// AddBusinessTermAttributeResponse is the response from adding an attribute to an asset.
type AddBusinessTermAttributeResponse struct {
Id string `json:"id"`
}

// CreateBusinessTermAsset creates a new business term asset via POST /rest/2.0/assets.
func CreateBusinessTermAsset(ctx context.Context, client *http.Client, req AddBusinessTermAssetRequest) (*AddBusinessTermAssetResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("marshaling business term asset request: %w", err)
}

httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, "/rest/2.0/assets", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("creating business term asset request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")

resp, err := client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("creating business term asset: %w", err)
}
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusCreated {
respBody, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("creating business term asset: unexpected status %d: %s", resp.StatusCode, string(respBody))
}

var result AddBusinessTermAssetResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decoding business term asset response: %w", err)
}

return &result, nil
}

// CreateBusinessTermAttribute adds an attribute to an asset via POST /rest/2.0/attributes.
func CreateBusinessTermAttribute(ctx context.Context, client *http.Client, req AddBusinessTermAttributeRequest) (*AddBusinessTermAttributeResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("marshaling business term attribute request: %w", err)
}

httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, "/rest/2.0/attributes", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("creating business term attribute request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")

resp, err := client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("creating business term attribute: %w", err)
}
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusCreated {
respBody, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("creating business term attribute: unexpected status %d: %s", resp.StatusCode, string(respBody))
}

var result AddBusinessTermAttributeResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decoding business term attribute response: %w", err)
}

return &result, nil
}
160 changes: 160 additions & 0 deletions pkg/clients/create_asset_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package clients

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)

// CreateAssetRequest is the request body for POST /rest/2.0/assets.
type CreateAssetRequest struct {
Name string `json:"name"`
TypeID string `json:"typeId"`
DomainID string `json:"domainId"`
DisplayName string `json:"displayName,omitempty"`
ExcludeFromAutoHyperlinking bool `json:"excludeFromAutoHyperlinking,omitempty"`
}

// CreateAssetResponse is the response from POST /rest/2.0/assets.
type CreateAssetResponse struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"displayName"`
Type CreateAssetTypeRef `json:"type"`
Domain CreateAssetDomainRef `json:"domain"`
CreatedBy string `json:"createdBy"`
CreatedOn int64 `json:"createdOn"`
LastModifiedBy string `json:"lastModifiedBy"`
LastModifiedOn int64 `json:"lastModifiedOn"`
}

// CreateAssetTypeRef is a reference to an asset type in a create asset response.
type CreateAssetTypeRef struct {
ID string `json:"id"`
Name string `json:"name"`
}

// CreateAssetDomainRef is a reference to a domain in a create asset response.
type CreateAssetDomainRef struct {
ID string `json:"id"`
Name string `json:"name"`
}

// CreateAttributeRequest is the request body for POST /rest/2.0/attributes.
type CreateAttributeRequest struct {
AssetID string `json:"assetId"`
TypeID string `json:"typeId"`
Value string `json:"value"`
}

// CreateAttributeResponse is the response from POST /rest/2.0/attributes.
type CreateAttributeResponse struct {
ID string `json:"id"`
Type CreateAttributeTypeRef `json:"type"`
Asset CreateAttributeAssetRef `json:"asset"`
Value string `json:"value"`
}

// CreateAttributeTypeRef is a reference to an attribute type.
type CreateAttributeTypeRef struct {
ID string `json:"id"`
Name string `json:"name"`
}

// CreateAttributeAssetRef is a reference to an asset in an attribute response.
type CreateAttributeAssetRef struct {
ID string `json:"id"`
}

// CreateAsset creates a new asset via POST /rest/2.0/assets.
func CreateAsset(ctx context.Context, client *http.Client, request CreateAssetRequest) (*CreateAssetResponse, error) {
body, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("creating asset: marshaling request: %w", err)
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/rest/2.0/assets", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("creating asset: building request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("creating asset: sending request: %w", err)
}
defer func() { _ = resp.Body.Close() }()

respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("creating asset: reading response: %w", err)
}

if resp.StatusCode != http.StatusCreated {
switch resp.StatusCode {
case http.StatusBadRequest:
return nil, fmt.Errorf("creating asset: bad request (invalid parameters or duplicate name): %s", string(respBody))
case http.StatusForbidden:
return nil, fmt.Errorf("creating asset: asset type not allowed in domain: %s", string(respBody))
case http.StatusNotFound:
return nil, fmt.Errorf("creating asset: invalid assetTypeId or domainId: %s", string(respBody))
default:
return nil, fmt.Errorf("creating asset: unexpected status %d: %s", resp.StatusCode, string(respBody))
}
}

var result CreateAssetResponse
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("creating asset: decoding response: %w", err)
}

return &result, nil
}

// CreateAttribute creates a new attribute on an asset via POST /rest/2.0/attributes.
func CreateAttribute(ctx context.Context, client *http.Client, request CreateAttributeRequest) (*CreateAttributeResponse, error) {
body, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("creating attribute: marshaling request: %w", err)
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/rest/2.0/attributes", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("creating attribute: building request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("creating attribute: sending request: %w", err)
}
defer func() { _ = resp.Body.Close() }()

respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("creating attribute: reading response: %w", err)
}

if resp.StatusCode != http.StatusCreated {
switch resp.StatusCode {
case http.StatusBadRequest:
return nil, fmt.Errorf("creating attribute: bad request (invalid parameters): %s", string(respBody))
case http.StatusNotFound:
return nil, fmt.Errorf("creating attribute: asset or attribute type not found: %s", string(respBody))
default:
return nil, fmt.Errorf("creating attribute: unexpected status %d: %s", resp.StatusCode, string(respBody))
}
}

var result CreateAttributeResponse
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("creating attribute: decoding response: %w", err)
}

return &result, nil
}
14 changes: 7 additions & 7 deletions pkg/clients/dgc_relation_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (

// Well-known Collibra UUIDs for relation and attribute types.
const (
DefinitionAttributeTypeID = "00000000-0000-0000-0000-000000003008"
DataAttributeRepresentsMeasureRelID = "00000000-0000-0000-0000-000000007200"
GenericConnectedAssetRelID = "00000000-0000-0000-0000-000000007038"
ColumnToTableRelID = "00000000-0000-0000-0000-000000007042"
DataAttributeRelID1 = "00000000-0000-0000-0000-000000007094"
DataAttributeRelID2 = "cd000000-0000-0000-0000-000000000023"
DefinitionAttributeTypeID = "00000000-0000-0000-0000-000000000202"
MeasureIsCalculatedUsingDataElementRelID = "00000000-0000-0000-0000-000000007200"
BusinessAssetRepresentsDataAssetRelID = "00000000-0000-0000-0000-000000007038"
ColumnIsPartOfTableRelID = "00000000-0000-0000-0000-000000007042"
DataAttributeRepresentsColumnRelID = "00000000-0000-0000-0000-000000007094"
ColumnIsSourceForDataAttributeRelID = "00000000-0000-0000-0000-120000000011"
)

type RelationsQueryParams struct {
Expand Down Expand Up @@ -164,7 +164,7 @@ func FindColumnsForDataAttribute(ctx context.Context, client *http.Client, dataA
seen := make(map[string]struct{})
result := make([]ConnectedAsset, 0)

for _, relID := range []string{DataAttributeRelID1, DataAttributeRelID2} {
for _, relID := range []string{DataAttributeRepresentsColumnRelID, ColumnIsSourceForDataAttributeRelID} {
assets, err := FindConnectedAssets(ctx, client, dataAttributeID, relID)
if err != nil {
return nil, err
Expand Down
Loading
Loading