Skip to content

feat: Simplify Destinations#35

Merged
bbernays merged 11 commits intomainfrom
simplify-destinations
Jan 24, 2023
Merged

feat: Simplify Destinations#35
bbernays merged 11 commits intomainfrom
simplify-destinations

Conversation

@bbernays
Copy link
Copy Markdown
Contributor

@bbernays bbernays commented Jan 19, 2023

Summary

This PR exposes a new method NewClient() that takes in a single struct. It returns a client that handles all of the read/write conversions for various file types

Here is how I expect destinations to use this functionality

// each destination will embed this client:
type Client struct {
	*filetypes.Client
}

// The spec will also embed the `Spec` struct from this package:
type Spec struct {
	Bucket   string `json:"bucket,omitempty"`
	Path     string `json:"path,omitempty"`
	NoRotate bool   `json:"no_rotate,omitempty"`
	*filetypes.FileSpec
}

func New(ctx context.Context, logger zerolog.Logger, spec specs.Destination) (destination.Client, error) {
	.
	.
	filetypesClient, err := filetypes.NewClient(c.pluginSpec.FileSpec)
	if err != nil {
		return nil, fmt.Errorf("failed to create filetypes client: %w", err)
	}
	c.Client = filetypesClient
	.
	.

The spec that users will use will look like this:

kind: destination
spec:
  name: "file"
  version: "v2.0.6"
  registry: "github"
  path: "cloudquery/file"
  write_mode: "overwrite-delete-stale"
  spec:
    format: "csv"
    format_spec:
      delimiter: ","
  • Anything that defines the behavior of the data within the file should be a part of format_spec (csv headers, delimiters, replacing any sort of special characters)
  • Anything that defines the behavior of the object or destination should be spec.spec (same level as format)

Use the following steps to ensure your PR is ready to be reviewed

  • Read the contribution guidelines 🧑‍🎓
  • Run go fmt to format your code 🖊
  • Lint your changes via golangci-lint run 🚨 (install golangci-lint here)
  • Update or add tests 🧪
  • Ensure the status checks below are successful ✅

@github-actions github-actions Bot added the feat label Jan 19, 2023
Copy link
Copy Markdown
Contributor

@candiduslynx candiduslynx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that extracting client, transformer & reverse transformer into a separate struct that embeds the aforementioned elements might streamline the code a bit more

Comment thread client.go Outdated
Comment thread client.go Outdated
Comment thread client.go Outdated
Comment thread client.go Outdated
Comment thread client.go Outdated
}

func (s *FileSpec) SetDefaults() {
if s.Delimiter == 0 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delimiter can be the NUL character, so depending on the zero value doesn't do it 100% :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we're unlikely to run into this in practice, but if we want to be safe we could probably change Delimiter to string and use the first rune in the string (with validation that it doesn't have > 1 runes). Then we can check for the empty string here.

Comment thread client.go Outdated
Comment thread csv/spec.go Outdated
Comment thread client.go Outdated
Comment thread json/spec.go Outdated
@github-actions github-actions Bot added feat and removed feat labels Jan 23, 2023
@yevgenypats
Copy link
Copy Markdown
Contributor

yevgenypats commented Jan 23, 2023

I like that. One question - can users still use the old method or now they have to embed this client and it's all or nothing?

@bbernays
Copy link
Copy Markdown
Contributor Author

I like that. One question - can users still use the old method or now they have to embed this client?

All of the old ways are still exposed... They should be used in cases where the default/ managed version is unsuitable

Copy link
Copy Markdown
Contributor

@yevgenypats yevgenypats left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good from quick look, will defer to @hermanschaaf re-review.

Copy link
Copy Markdown
Contributor

@hermanschaaf hermanschaaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think storing *csvSpec and *jsonSpec as state on the file spec is maybe a little bit unusual, but I can see why you went this route: so that you can call Validate() directly on the file spec, as long as UnmarshalSpec() was called first. This way we can add new file types to this library without updating the logic in all the destinations, which is quite a nice property. LGTM 👍

Comment thread client.go
}
return &Client{
spec: spec,
csvTransformer: &csvFile.Transformer{},
Copy link
Copy Markdown
Contributor

@candiduslynx candiduslynx Jan 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought:

  1. make value receiver instead of pointer receiver for csvFile.Transformer{}
  2. drop reverse transformer func from csvFile.Transformer{} as it should be inherited from embedded struct
  3. you can change the field to be value here and not init it al all

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for json, btw

@bbernays bbernays merged commit 97c02e9 into main Jan 24, 2023
@bbernays bbernays deleted the simplify-destinations branch January 24, 2023 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants