-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(asset): implement file system repository and zip decompressor #66
Open
kasugamirai
wants to merge
60
commits into
main
Choose a base branch
from
feat/asset-management
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
5f1b183
feat(asset): implement file system repository and zip decompressor
kasugamirai 7ea0393
chore: add .idea to .gitignore
kasugamirai db64520
feat(asset): enhance asset management with status tracking and zip ex…
kasugamirai 11e654a
feat(asset): implement CRUD operations for asset management
kasugamirai 8ad88c8
refactor(asset): restructure repository interfaces for improved asset…
kasugamirai 61b504b
feat(asset): enhance zip decompression with improved error handling a…
kasugamirai c3743ed
feat(asset): refactor ZipDecompressor for improved async processing a…
kasugamirai bb09b06
refactor(asset): remove legacy GCS repository implementation
kasugamirai 60b401e
refactor(asset): rename Repository to GCS and update methods for impr…
kasugamirai 9d62ead
refactor(asset): remove GCS repository implementation to streamline a…
kasugamirai 8faee9e
refactor(asset): remove repository interface and update import paths
kasugamirai c4b9036
refactor(asset): rename GCSClient to Client and update methods for co…
kasugamirai ce054b9
refactor(asset): remove decompressor and GCS implementations, update …
kasugamirai 375edef
refactor(asset): enhance ZipDecompressor with new methods and improve…
kasugamirai 2412515
feat(asset): implement asynchronous and direct content compression in…
kasugamirai 1d356a9
refactor(asset): update NewZipDecompressor return type for improved i…
kasugamirai c3717b2
refactor(asset): remove ZipDecompressor implementation to streamline …
kasugamirai 3957926
refactor(asset): simplify ZipDecompressor and enhance decompression f…
kasugamirai 0645e35
refactor(asset): enhance CompressWithContent for improved concurrency…
kasugamirai c0b0f15
feat(asset): enhance GCS client with new asset management methods
kasugamirai 15af103
feat(asset): add projectID and workspaceID to Asset struct
kasugamirai 7824b48
refactor(gcs): remove redundant name assignment in CRUD tests
kasugamirai 9a4f777
refactor(asset): improve error handling and logging in ZipDecompresso…
kasugamirai 129d3f0
refactor(asset): remove deprecated repository and asset types to stre…
kasugamirai 667821d
refactor(asset): comment out service methods and remove utils for cod…
kasugamirai afeaaa3
refactor(gcs): remove GCS client test file to streamline codebase
kasugamirai acbcaad
refactor(asset): remove asset service implementation to streamline co…
kasugamirai 3f2bc9c
feat(asset): implement asset management queries and mutations
kasugamirai fd1e4b6
feat(asset): implement asset movement and deletion functionality
kasugamirai 6e99c4a
feat(asset): enhance asset management with new fields and methods
kasugamirai 1248cc6
feat(asset): add decompression and compression methods to asset service
kasugamirai 5375f2f
feat(asset): refactor compression to use channels for asynchronous pr…
kasugamirai 460e01f
refactor(asset): improve zip decompression concurrency and error hand…
kasugamirai 7352cb9
feat(asset): enhance asset event handling with new event types and me…
kasugamirai 4078a4c
refactor(asset): remove pubsub implementation to streamline codebase
kasugamirai 82d9d8e
feat(asset): integrate pubsub functionality for asset event publishing
kasugamirai 4185ab4
feat(asset): reintroduce pubsub functionality for asset event handling
kasugamirai f8f8301
feat(asset): enhance pubsub functionality with subscription and event…
kasugamirai 17bae14
fix(account): improve error handling in user credential retrieval and…
kasugamirai 29326af
feat(account): add test for asset
kasugamirai abbb723
refactor(asset): streamline asset event handling and improve error ma…
kasugamirai 4d828d5
feat(asset): add deleteAssetsInGroup mutation for bulk asset deletion
kasugamirai 1428f87
refactor(asset): rename Builder to AssetBuilder and update related tests
kasugamirai 7af2ba8
chore(asset): remove group service implementation and related tests
kasugamirai dd556f2
feat(asset): add SetSize method and refactor resolver to use asset us…
kasugamirai 6d890f9
refactor(asset): remove unused asset usecase and interactor implement…
kasugamirai 8b3514b
refactor(asset): update import path for asset usecase in resolver
kasugamirai 9798ad9
refactor(asset): migrate ID types to new id package and clean up doma…
kasugamirai afda58a
refactor(asset): remove deprecated domain files and update references…
kasugamirai 39b0572
feat(asset): implement validation for Asset and Group entities
kasugamirai 4abf753
feat(asset): enhance asset usecase and resolver error handling
kasugamirai ae39bf0
fix(asset): improve error handling in builders and tests
kasugamirai 44df313
refactor(asset): remove unused repository interface and clean up vali…
kasugamirai ede3ff9
refactor(asset): streamline CreatedAt methods in builders
kasugamirai c545a1a
refactor(asset): remove event package and clean up builder error hand…
kasugamirai ebcfc72
Revert
kasugamirai b88d638
refactor(asset): simplify loop syntax in DecompressZipContent method
kasugamirai ae883ae
refactor(asset): improve asset and group entity handling and error ma…
kasugamirai f06a63e
refactor(asset): update ID methods and improve error handling in deco…
kasugamirai 9124c84
refactor(asset): remove unused NewValidationResult function
kasugamirai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.env | ||
.env.* | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package builder | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/reearth/reearthx/asset/domain" | ||
"github.com/reearth/reearthx/asset/domain/entity" | ||
"github.com/reearth/reearthx/asset/domain/id" | ||
) | ||
|
||
type AssetBuilder struct { | ||
a *entity.Asset | ||
} | ||
|
||
func NewAssetBuilder() *AssetBuilder { | ||
return &AssetBuilder{a: &entity.Asset{}} | ||
} | ||
|
||
func (b *AssetBuilder) Build() (*entity.Asset, error) { | ||
if b.a.ID() == (id.ID{}) { | ||
return nil, id.ErrInvalidID | ||
} | ||
if b.a.WorkspaceID() == (id.WorkspaceID{}) { | ||
return nil, domain.ErrEmptyWorkspaceID | ||
} | ||
if b.a.URL() == "" { | ||
return nil, domain.ErrEmptyURL | ||
} | ||
if b.a.Size() <= 0 { | ||
return nil, domain.ErrEmptySize | ||
} | ||
if b.a.CreatedAt().IsZero() { | ||
now := time.Now() | ||
b.a.SetCreatedAt(now) | ||
b.a.SetUpdatedAt(now) | ||
} | ||
if b.a.Status() == "" { | ||
b.a.UpdateStatus(entity.StatusPending, b.a.Error()) | ||
} | ||
return b.a, nil | ||
} | ||
|
||
func (b *AssetBuilder) MustBuild() *entity.Asset { | ||
r, err := b.Build() | ||
if err != nil { | ||
panic(err) | ||
} | ||
return r | ||
} | ||
|
||
func (b *AssetBuilder) ID(id id.ID) *AssetBuilder { | ||
b.a = entity.NewAsset(id, b.a.Name(), b.a.Size(), b.a.ContentType()) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) NewID() *AssetBuilder { | ||
return b.ID(id.NewID()) | ||
} | ||
|
||
func (b *AssetBuilder) GroupID(groupID id.GroupID) *AssetBuilder { | ||
b.a.MoveToGroup(groupID) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) ProjectID(projectID id.ProjectID) *AssetBuilder { | ||
b.a.MoveToProject(projectID) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) WorkspaceID(workspaceID id.WorkspaceID) *AssetBuilder { | ||
b.a.MoveToWorkspace(workspaceID) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) Name(name string) *AssetBuilder { | ||
b.a.UpdateMetadata(name, b.a.URL(), b.a.ContentType()) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) Size(size int64) *AssetBuilder { | ||
b.a.SetSize(size) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) URL(url string) *AssetBuilder { | ||
b.a.UpdateMetadata(b.a.Name(), url, b.a.ContentType()) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) ContentType(contentType string) *AssetBuilder { | ||
b.a.UpdateMetadata(b.a.Name(), b.a.URL(), contentType) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) Status(status entity.Status) *AssetBuilder { | ||
b.a.UpdateStatus(status, b.a.Error()) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) Error(err string) *AssetBuilder { | ||
b.a.UpdateStatus(b.a.Status(), err) | ||
return b | ||
} | ||
|
||
// CreatedAt sets the creation time of the asset | ||
func (b *AssetBuilder) CreatedAt(createdAt time.Time) *AssetBuilder { | ||
b.a.SetCreatedAt(createdAt) | ||
return b | ||
} | ||
|
||
func (b *AssetBuilder) UpdatedAt(updatedAt time.Time) *AssetBuilder { | ||
b.a.SetUpdatedAt(updatedAt) | ||
return b | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package builder | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/reearth/reearthx/asset/domain" | ||
"github.com/reearth/reearthx/asset/domain/entity" | ||
"github.com/reearth/reearthx/asset/domain/id" | ||
) | ||
|
||
type GroupBuilder struct { | ||
g *entity.Group | ||
} | ||
|
||
func NewGroupBuilder() *GroupBuilder { | ||
return &GroupBuilder{g: &entity.Group{}} | ||
} | ||
|
||
func (b *GroupBuilder) Build() (*entity.Group, error) { | ||
if b.g.ID() == (id.GroupID{}) { | ||
return nil, id.ErrInvalidID | ||
} | ||
if b.g.Name() == "" { | ||
return nil, domain.ErrEmptyGroupName | ||
} | ||
if b.g.CreatedAt().IsZero() { | ||
now := time.Now() | ||
b.CreatedAt(now) | ||
} | ||
return b.g, nil | ||
} | ||
|
||
func (b *GroupBuilder) MustBuild() *entity.Group { | ||
r, err := b.Build() | ||
if err != nil { | ||
panic(err) | ||
} | ||
return r | ||
} | ||
|
||
func (b *GroupBuilder) ID(id id.GroupID) *GroupBuilder { | ||
b.g = entity.NewGroup(id, b.g.Name()) | ||
return b | ||
} | ||
|
||
func (b *GroupBuilder) NewID() *GroupBuilder { | ||
return b.ID(id.NewGroupID()) | ||
} | ||
|
||
func (b *GroupBuilder) Name(name string) *GroupBuilder { | ||
if err := b.g.UpdateName(name); err != nil { | ||
return b | ||
} | ||
return b | ||
} | ||
|
||
func (b *GroupBuilder) Policy(policy string) *GroupBuilder { | ||
if err := b.g.UpdatePolicy(policy); err != nil { | ||
return b | ||
} | ||
return b | ||
} | ||
|
||
func (b *GroupBuilder) Description(description string) *GroupBuilder { | ||
if err := b.g.UpdateDescription(description); err != nil { | ||
return b | ||
} | ||
return b | ||
} | ||
|
||
// CreatedAt sets the creation time of the group | ||
func (b *GroupBuilder) CreatedAt(createdAt time.Time) *GroupBuilder { | ||
b.g.SetCreatedAt(createdAt) | ||
return b | ||
} | ||
|
||
func (b *GroupBuilder) UpdatedAt(updatedAt time.Time) *GroupBuilder { | ||
return b | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package builder_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/reearth/reearthx/asset/domain" | ||
"github.com/reearth/reearthx/asset/domain/builder" | ||
"github.com/reearth/reearthx/asset/domain/entity" | ||
"github.com/reearth/reearthx/asset/domain/id" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAssetBuilder_Build(t *testing.T) { | ||
assetID := id.NewID() | ||
workspaceID := id.NewWorkspaceID() | ||
|
||
tests := []struct { | ||
name string | ||
builder func() *builder.AssetBuilder | ||
want *entity.Asset | ||
wantErr error | ||
}{ | ||
{ | ||
name: "success", | ||
builder: func() *builder.AssetBuilder { | ||
return builder.NewAssetBuilder(). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID). | ||
URL("https://example.com/test.jpg") | ||
}, | ||
want: func() *entity.Asset { | ||
asset := entity.NewAsset(assetID, "test.jpg", 1024, "image/jpeg") | ||
asset.MoveToWorkspace(workspaceID) | ||
asset.UpdateMetadata("test.jpg", "https://example.com/test.jpg", "image/jpeg") | ||
return asset | ||
}(), | ||
wantErr: nil, | ||
}, | ||
{ | ||
name: "missing ID", | ||
builder: func() *builder.AssetBuilder { | ||
return builder.NewAssetBuilder(). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID). | ||
URL("https://example.com/test.jpg") | ||
}, | ||
wantErr: id.ErrInvalidID, | ||
}, | ||
{ | ||
name: "missing workspace ID", | ||
builder: func() *builder.AssetBuilder { | ||
return builder.NewAssetBuilder(). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
URL("https://example.com/test.jpg") | ||
}, | ||
wantErr: domain.ErrEmptyWorkspaceID, | ||
}, | ||
{ | ||
name: "missing URL", | ||
builder: func() *builder.AssetBuilder { | ||
return builder.NewAssetBuilder(). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID) | ||
}, | ||
wantErr: domain.ErrEmptyURL, | ||
}, | ||
{ | ||
name: "invalid size", | ||
builder: func() *builder.AssetBuilder { | ||
return builder.NewAssetBuilder(). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(0). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID). | ||
URL("https://example.com/test.jpg") | ||
}, | ||
wantErr: domain.ErrEmptySize, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := tt.builder().Build() | ||
if tt.wantErr != nil { | ||
assert.Equal(t, tt.wantErr, err) | ||
assert.Nil(t, got) | ||
return | ||
} | ||
assert.NoError(t, err) | ||
assert.NotNil(t, got) | ||
if tt.want != nil { | ||
assert.Equal(t, tt.want.ID(), got.ID()) | ||
assert.Equal(t, tt.want.Name(), got.Name()) | ||
assert.Equal(t, tt.want.Size(), got.Size()) | ||
assert.Equal(t, tt.want.ContentType(), got.ContentType()) | ||
assert.Equal(t, tt.want.URL(), got.URL()) | ||
assert.Equal(t, tt.want.WorkspaceID(), got.WorkspaceID()) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestAssetBuilder_MustBuild(t *testing.T) { | ||
assetID := id.NewID() | ||
workspaceID := id.NewWorkspaceID() | ||
|
||
// Test successful build | ||
assert.NotPanics(t, func() { | ||
asset := builder.NewAssetBuilder(). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID). | ||
URL("https://example.com/test.jpg"). | ||
MustBuild() | ||
assert.NotNil(t, asset) | ||
}) | ||
|
||
// Test panic on invalid build | ||
assert.Panics(t, func() { | ||
_ = builder.NewAssetBuilder().MustBuild() | ||
}) | ||
} | ||
|
||
func TestAssetBuilder_Setters(t *testing.T) { | ||
assetID := id.NewID() | ||
workspaceID := id.NewWorkspaceID() | ||
projectID := id.NewProjectID() | ||
groupID := id.NewGroupID() | ||
now := time.Now() | ||
|
||
b := builder.NewAssetBuilder(). | ||
CreatedAt(now). | ||
ID(assetID). | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(workspaceID). | ||
ProjectID(projectID). | ||
GroupID(groupID). | ||
URL("https://example.com/test.jpg"). | ||
Status(entity.StatusActive). | ||
Error("test error") | ||
|
||
asset, err := b.Build() | ||
assert.NoError(t, err) | ||
assert.NotNil(t, asset) | ||
|
||
assert.Equal(t, assetID, asset.ID()) | ||
assert.Equal(t, workspaceID, asset.WorkspaceID()) | ||
assert.Equal(t, projectID, asset.ProjectID()) | ||
assert.Equal(t, groupID, asset.GroupID()) | ||
assert.Equal(t, "test.jpg", asset.Name()) | ||
assert.Equal(t, int64(1024), asset.Size()) | ||
assert.Equal(t, "https://example.com/test.jpg", asset.URL()) | ||
assert.Equal(t, "image/jpeg", asset.ContentType()) | ||
assert.Equal(t, entity.StatusActive, asset.Status()) | ||
assert.Equal(t, "test error", asset.Error()) | ||
assert.Equal(t, now.Unix(), asset.CreatedAt().Unix()) | ||
} | ||
|
||
func TestAssetBuilder_NewID(t *testing.T) { | ||
b := builder.NewAssetBuilder().NewID() | ||
// Add required fields to make the build succeed | ||
b = b. | ||
Name("test.jpg"). | ||
Size(1024). | ||
ContentType("image/jpeg"). | ||
WorkspaceID(id.NewWorkspaceID()). | ||
URL("https://example.com/test.jpg") | ||
|
||
asset, err := b.Build() | ||
assert.NoError(t, err) | ||
assert.NotNil(t, asset) | ||
assert.NotEqual(t, id.ID{}, asset.ID()) // ID should be set | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid re-initializing the asset in the
ID
methodThe
ID
method re-initializes theAsset
instance usingentity.NewAsset
, which can overwrite fields previously set by other builder methods, potentially leading to data loss. Instead, consider updating only theid
field of the existing asset to preserve all other fields.Since the
id
field inentity.Asset
is unexported and there's noSetID
method, you might need to modify theentity.Asset
struct to allow setting theid
field. One approach is to add aSetID
method toentity.Asset
. Here's how you could adjust theID
method:Ensure that you implement
SetID
withinentity.Asset
: