-
-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
597 additions
and
6 deletions.
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
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
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
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,92 @@ | ||
// Copyright (c) 2023 Onur Cinar. All Rights Reserved. | ||
// The source code is provided under MIT License. | ||
// https://github.com/cinar/indicator | ||
|
||
package asset | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"github.com/cinar/indicator/helper" | ||
) | ||
|
||
// InMemoryRepository stores and retrieves asset snapshots using | ||
// an in memory storage. | ||
type InMemoryRepository struct { | ||
Repository | ||
|
||
// storage is the in memory storage for assets. | ||
storage map[string][]*Snapshot | ||
} | ||
|
||
// NewInMemoryRepository initializes an in memory repository. | ||
func NewInMemoryRepository() *InMemoryRepository { | ||
return &InMemoryRepository{ | ||
storage: make(map[string][]*Snapshot), | ||
} | ||
} | ||
|
||
// Assets returns the names of all assets in the repository. | ||
func (r *InMemoryRepository) Assets() ([]string, error) { | ||
assets := make([]string, 0, len(r.storage)) | ||
for name := range r.storage { | ||
assets = append(assets, name) | ||
} | ||
|
||
return assets, nil | ||
} | ||
|
||
// Get attempts to return a channel of snapshots for the asset with the given name. | ||
func (r *InMemoryRepository) Get(name string) (<-chan *Snapshot, error) { | ||
snapshots, ok := r.storage[name] | ||
if !ok { | ||
return nil, errors.New("not found") | ||
} | ||
|
||
return helper.SliceToChan(snapshots), nil | ||
} | ||
|
||
// GetSince attempts to return a channel of snapshots for the asset with the given name since the given date. | ||
func (r *InMemoryRepository) GetSince(name string, date time.Time) (<-chan *Snapshot, error) { | ||
snapshots, err := r.Get(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
snapshots = helper.Filter(snapshots, func(s *Snapshot) bool { | ||
return s.Date.Equal(date) || s.Date.After(date) | ||
}) | ||
|
||
return snapshots, nil | ||
} | ||
|
||
// LastDate returns the date of the last snapshot for the asset with the given name. | ||
func (r *InMemoryRepository) LastDate(name string) (time.Time, error) { | ||
var last time.Time | ||
|
||
snapshots, err := r.Get(name) | ||
if err != nil { | ||
return last, err | ||
} | ||
|
||
snapshot, ok := <-helper.Last(snapshots, 1) | ||
if !ok { | ||
return last, errors.New("empty asset") | ||
} | ||
|
||
return snapshot.Date, nil | ||
} | ||
|
||
// Append adds the given snapshows to the asset with the given name. | ||
func (r *InMemoryRepository) Append(name string, snapshots <-chan *Snapshot) error { | ||
combined := r.storage[name] | ||
|
||
for snapshot := range snapshots { | ||
combined = append(combined, snapshot) | ||
} | ||
|
||
r.storage[name] = combined | ||
|
||
return nil | ||
} |
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,161 @@ | ||
// Copyright (c) 2023 Onur Cinar. All Rights Reserved. | ||
// The source code is provided under MIT License. | ||
// https://github.com/cinar/indicator | ||
|
||
package asset_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/cinar/indicator/asset" | ||
"github.com/cinar/indicator/helper" | ||
) | ||
|
||
func TestInMemoryRepositoryAssets(t *testing.T) { | ||
repository := asset.NewInMemoryRepository() | ||
|
||
assets, err := repository.Assets() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if len(assets) != 0 { | ||
t.Fatal("not empty") | ||
} | ||
|
||
name := "A" | ||
|
||
snapshots := []*asset.Snapshot{ | ||
{Date: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, | ||
{Date: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC)}, | ||
} | ||
|
||
err = repository.Append(name, helper.SliceToChan(snapshots)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
assets, err = repository.Assets() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if len(assets) != 1 { | ||
t.Fatalf("more assets found %v", assets) | ||
} | ||
|
||
if assets[0] != name { | ||
t.Fatalf("actual %v expected %v", assets[0], name) | ||
} | ||
|
||
} | ||
|
||
func TestInMemoryRepositoryGet(t *testing.T) { | ||
repository := asset.NewInMemoryRepository() | ||
|
||
name := "A" | ||
|
||
_, err := repository.Get(name) | ||
if err == nil { | ||
t.Fatal("expected error") | ||
} | ||
|
||
snapshots := []*asset.Snapshot{ | ||
{Date: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, | ||
{Date: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC)}, | ||
} | ||
|
||
err = repository.Append(name, helper.SliceToChan(snapshots)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
actual, err := repository.Get(name) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := helper.SliceToChan(snapshots) | ||
|
||
err = helper.CheckEquals(actual, expected) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestInMemoryRepositoryGetSince(t *testing.T) { | ||
repository := asset.NewInMemoryRepository() | ||
|
||
name := "A" | ||
date := time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC) | ||
|
||
_, err := repository.GetSince(name, date) | ||
if err == nil { | ||
t.Fatal("expected error") | ||
} | ||
|
||
snapshots := []*asset.Snapshot{ | ||
{Date: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, | ||
{Date: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC)}, | ||
} | ||
|
||
err = repository.Append(name, helper.SliceToChan(snapshots)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
actual, err := repository.GetSince(name, date) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := helper.SliceToChan(snapshots[1:]) | ||
|
||
err = helper.CheckEquals(actual, expected) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestInMemoryRepositoryLastDate(t *testing.T) { | ||
repository := asset.NewInMemoryRepository() | ||
|
||
name := "A" | ||
|
||
_, err := repository.LastDate(name) | ||
if err == nil { | ||
t.Fatal("expected error") | ||
} | ||
|
||
err = repository.Append(name, helper.SliceToChan([]*asset.Snapshot{})) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
_, err = repository.LastDate(name) | ||
if err == nil { | ||
t.Fatal("expected error") | ||
} | ||
|
||
snapshots := []*asset.Snapshot{ | ||
{Date: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, | ||
{Date: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC)}, | ||
} | ||
|
||
err = repository.Append(name, helper.SliceToChan(snapshots)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
actual, err := repository.LastDate(name) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := snapshots[1].Date | ||
|
||
if !expected.Equal(actual) { | ||
t.Fatalf("actual %v expected %v", actual, expected) | ||
} | ||
} |
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
Oops, something went wrong.