Skip to content

Commit

Permalink
Rearrange pkgs to be usable as an importable library (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
peppys authored Feb 10, 2022
1 parent c5b3ada commit 0ef7591
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 106 deletions.
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ $ curl -L https://github.com/peppys/crib/releases/download/1.0.1/crib_1.0.1_Darw
$ tar -xzvf crib.tar.gz
```

## Usage
## CLI Usage
```shell
$ ./crib value --help
Checks the estimated valuation of your property
Expand All @@ -23,5 +23,32 @@ Flags:
-h, --help help for value
```

## Demo
## Library Usage
```go
package main

import (
"github.com/peppys/crib/pkg/crib"
"github.com/peppys/crib/pkg/crib/estimators"
"log"
)

func main() {
c := crib.NewCrib(
crib.WithEstimators(
estimators.DefaultZillowEstimator(),
estimators.DefaultRedfinEstimator(),
),
)

estimates, err := c.Estimate("1443 delvin dr los angeles, ca")
if err != nil {
log.Fatal(err)
}

log.Printf("found estimates: %+v", estimates)
}
```

## CLI Demo
![demo](demo.gif)
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.17

require (
github.com/leekchan/accounting v1.0.0
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.34
github.com/spf13/cobra v1.3.0
)
Expand All @@ -14,7 +15,6 @@ require (
github.com/gookit/color v1.4.2 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,9 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
34 changes: 20 additions & 14 deletions internal/commands/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@ package commands
import (
"fmt"
"github.com/leekchan/accounting"
"github.com/peppys/crib/internal/services/property"
"github.com/peppys/crib/internal/services/property/estimators"
"github.com/peppys/crib/pkg/redfin"
"github.com/peppys/crib/pkg/zillow"
"github.com/peppys/crib/internal/redfin"
"github.com/peppys/crib/internal/zillow"
"github.com/peppys/crib/pkg/crib"
"github.com/peppys/crib/pkg/crib/estimators"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"log"
"net/http"
"os"
"strings"
)

var valueCmd = &cobra.Command{
Use: "value",
Short: "Checks the estimated valuation of your property",
Long: "Checks the estimated valuation of your property",
PreRun: func(cmd *cobra.Command, args []string) {
if strings.TrimSpace(address) == "" {
pterm.Error.Println("address must be provided")
cmd.Help()
os.Exit(1)
}
},
Run: func(cmd *cobra.Command, args []string) {
_ = pterm.DefaultBigText.WithLetters(pterm.NewLettersFromStringWithStyle("crib", pterm.NewStyle(pterm.FgLightMagenta))).Render()
introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(true).WithRemoveWhenDone(true).Start(fmt.Sprintf("estimating valuation for crib '%s'...", address))
estimates, err := manager.Valuation(address)

estimates, err := theCrib.Estimate(address)
introSpinner.Stop()
if err != nil {
pterm.Error.Println(err)
log.Fatal(err)
os.Exit(1)
}
data := pterm.TableData{
{"Vendor", "Estimate"},
Expand All @@ -38,19 +46,17 @@ var valueCmd = &cobra.Command{
},
}

var manager *property.Manager
var theCrib *crib.Crib
var address string

func init() {
valueCmd.Flags().StringVarP(&address, "address", "a", "", "Address of your crib")
valueCmd.MarkFlagRequired("address")
rootCmd.AddCommand(valueCmd)
manager = property.NewManager(
property.WithEstimator(
estimators.NewBulkEstimator(
estimators.NewZillowEstimator(zillow.NewClient(http.DefaultClient)),
estimators.NewRedfinEstimator(redfin.NewClient(http.DefaultClient)),
),
theCrib = crib.NewCrib(
crib.WithEstimators(
estimators.NewZillowEstimator(zillow.NewClient(http.DefaultClient)),
estimators.NewRedfinEstimator(redfin.NewClient(http.DefaultClient)),
),
)
}
File renamed without changes.
24 changes: 0 additions & 24 deletions internal/services/property/estimators/bulk.go

This file was deleted.

50 changes: 0 additions & 50 deletions internal/services/property/manager.go

This file was deleted.

File renamed without changes.
43 changes: 43 additions & 0 deletions pkg/crib/crib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package crib

import (
"fmt"
"github.com/peppys/crib/pkg/crib/estimators"
)

type Crib struct {
estimate estimators.Estimator
}

type Option func(c *Crib)

func NewCrib(opts ...Option) *Crib {
c := &Crib{}

for _, opt := range opts {
opt(c)
}

return c
}

func WithEstimator(e estimators.Estimator) Option {
return func(c *Crib) {
c.estimate = e
}
}

func WithEstimators(e ...estimators.Estimator) Option {
return func(c *Crib) {
c.estimate = estimators.NewBulkEstimator(e...)
}
}

func (c *Crib) Estimate(address string) ([]estimators.Estimate, error) {
estimate, err := c.estimate(address)
if err != nil {
return nil, fmt.Errorf("error while estimating valuation: %w", err)
}

return estimate, nil
}
40 changes: 40 additions & 0 deletions pkg/crib/estimators/bulk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package estimators

import (
"github.com/pkg/errors"
"sync"
)

func NewBulkEstimator(estimators ...Estimator) func(address string) ([]Estimate, error) {
return func(address string) ([]Estimate, error) {
var wg sync.WaitGroup
var estimatorErrors []error
var estimates []Estimate

for _, estimator := range estimators {
wg.Add(1)

go func(estimator Estimator) {
defer wg.Done()
result, err := estimator(address)
if err != nil {
estimatorErrors = append(estimatorErrors, err)
} else {
estimates = append(estimates, result...)
}
}(estimator)
}

wg.Wait()
if len(estimatorErrors) > 0 {
err := errors.New("")
for _, e := range estimatorErrors {
err = errors.Wrapf(err, "estimator failed: %s", e.Error())
}

return nil, err
}

return estimates, nil
}
}
15 changes: 15 additions & 0 deletions pkg/crib/estimators/estimator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package estimators

type Vendor string

const (
Zillow Vendor = "ZILLOW"
Redfin = "REDFIN"
)

type Estimate struct {
Vendor Vendor
Value float64
}

type Estimator func(string) ([]Estimate, error)
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,32 @@ package estimators

import (
"fmt"
"github.com/peppys/crib/internal/services/property"
"github.com/peppys/crib/pkg/redfin"
"github.com/peppys/crib/internal/redfin"
"net/http"
"strings"
)

func NewRedfinEstimator(client *redfin.Client) func(address string) ([]property.Estimate, error) {
return func(address string) ([]property.Estimate, error) {
func DefaultRedfinEstimator() func(address string) ([]Estimate, error) {
return NewRedfinEstimator(redfin.NewClient(http.DefaultClient))
}

func NewRedfinEstimator(client *redfin.Client) func(address string) ([]Estimate, error) {
return func(address string) ([]Estimate, error) {
searchResponse, err := client.SearchProperties(address)
if err != nil {
return nil, fmt.Errorf("error searching redfin properties: %v", err)
}
if !strings.HasPrefix(searchResponse.Payload.ExactMatch.ID, "1_") {
return nil, fmt.Errorf("todo")
return nil, fmt.Errorf("failed to find redfin property ID")
}
avmResponse, err := client.GetAutomatedValuationModel(strings.TrimPrefix(searchResponse.Payload.ExactMatch.ID, "1_"))
if err != nil {
return nil, fmt.Errorf("error getting redfin avm: %v", err)
}

return []property.Estimate{
return []Estimate{
{
Vendor: property.Redfin,
Vendor: Redfin,
Value: avmResponse.Payload.Root.AVMInfo.PredictedValue,
},
}, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ package estimators

import (
"fmt"
"github.com/peppys/crib/internal/services/property"
"github.com/peppys/crib/pkg/zillow"
"github.com/peppys/crib/internal/zillow"
"net/http"
)

func NewZillowEstimator(client *zillow.Client) func(address string) ([]property.Estimate, error) {
return func(address string) ([]property.Estimate, error) {
func DefaultZillowEstimator() func(address string) ([]Estimate, error) {
return NewZillowEstimator(zillow.NewClient(http.DefaultClient))
}

func NewZillowEstimator(client *zillow.Client) func(address string) ([]Estimate, error) {
return func(address string) ([]Estimate, error) {
searchResponse, err := client.SearchProperties(address)
if err != nil {
return nil, fmt.Errorf("error looking up address on zillow: %w", err)
}
if len(searchResponse.Results) == 0 {
if searchResponse.Results[0].MetaData.Zpid == 0 {
return nil, fmt.Errorf("could not find property on zillow")
}
propertyResponse, err := client.LookupProperty(searchResponse.Results[0].MetaData.Zpid)
if err != nil {
return nil, fmt.Errorf("error looking up property on zillow: %w", err)
}

return []property.Estimate{
return []Estimate{
{
Vendor: property.Zillow,
Vendor: Zillow,
Value: float64(propertyResponse.LookupResults[0].Estimates.Zestimate),
},
}, nil
Expand Down

0 comments on commit 0ef7591

Please sign in to comment.