2022/12/14

big array goroutine

 - https://qiita.com/tutuz/items/057452fbbe9a5ae26d37

- multi goroutine to loop array
```
slice := []string{"a", "b", "c", "d", "e"}
sliceLength := len(slice)
var wg sync.WaitGroup
wg.Add(sliceLength)
fmt.Println("Running for loop…")
for i := 0; i < sliceLength; i++ {
go func(i int) {
defer wg.Done()
val := slice[i]
fmt.Printf("i: %v, val: %v\n", i, val)
}(i)
}
wg.Wait()
fmt.Println("Finished for loop")
```
- 課題はエラー検知とgoroutineの数の制御、errgroupの登場
- golang.org/x/sync/errgroup は、複数の goroutine を実行して、それらのうちにエラーがあったときにエラーを知る、ということを可能にしてくれるライブラリ
- sync.WaitGroup は実行した goroutine が終わるのを待ちますが、エラーがあったかどうかはわかりません
- errgroup は sync.WaitGroup+error といったイメージで、どれかの goroutine でエラーがあったら最初のひとつを知ることができ
```
// You can edit this code!
// Click here and start typing.
package main

import (
"context"
"fmt"

"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)

func main() {
fmt.Println("Hello, 世界")
ctx := context.TODO()
ms := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
mcs := make([]int, len(ms))

eg := errgroup.Group{}
sem := semaphore.NewWeighted(3)
for i := range ms {
if err := sem.Acquire(ctx, 1); err != nil {
panic(err)
}
func(i int) {
eg.Go(
func() error {
defer sem.Release(1)
fmt.Printf("i is %v\n", i)
mcs[i] = ms[i] + 100
return nil
})
}(i)
}

if err := eg.Wait(); err != nil {
panic(err)
}
fmt.Printf("ms is %v\n", ms)
fmt.Printf("msc is %v\n", mcs)
}
```

2022/12/08

golang fmt %q

文字列を””で囲んで出力する。
これで実際の を””に表現して、わかりやすい 

spannerのgolang clientで%qを使っている
It's just quite a strange decision made by Google here, to assume that the String() function is only used for logging and it's ok to add quotes...

package main


import (

"fmt"

)


func main() {

str := "Gopherくん"

slice := []string{"g", "o", "h", "e", "r"}

integer := 12450

fmt.Printf("1:出力は %q となります。\n", str)

fmt.Printf("2:出力は %s となります。\n", str)


fmt.Printf("3:出力は %q となります。\n", slice)

fmt.Printf("4:出力は %s となります。\n", slice)


fmt.Printf("5:出力は %d となります。\n", integer)

fmt.Printf("6:出力は %q となります。\n", integer)

}


//1:出力は "Gopherくん" となります。

//2:出力は Gopherくん となります。

//3:出力は ["g" "o" "h" "e" "r"] となります。

//4:出力は [g o h e r] となります。

//5:出力は 12450 となります。

//6:出力は 'ア' となります。 (アのunicode の十進制は12345)


2022/12/07

spanner nullable data type golang

 spanner nullable data type

```
// NullableValue is the interface implemented by all null value wrapper types.
type NullableValue interface {
// IsNull returns true if the underlying database value is null.
IsNull() bool
}
```
- how to use
- difference between null,"","someValue"
- null
- spanner.NullString(valid=false)
- ""
- spanner.NullString(valid=true,value="")
- update(value[*NullableValue]->model[NullableValue])
- update target items
- value is not nil
- not update target items
- value is nil
- vo is all pointer

by the way, another orm tool,gorm , don't solve this problem well.
var user User
db.First(&user)

db.Model(&user).Updates(User{Age: 18, Name: nil})
// 実行 SQL : UPDATE `users` SET `age` = '18'  WHERE `users`.`id` = '1'

GORM のドキュメントを見ると以下のように書いてあったので、構造体で実行すると無視されてしまうようです。 When query with struct, GORM will only query with those fields has non-zero value,

that means if your field's value is 0, '', false or other zero values,

it won't be used to build query conditions,

go instal where ?

go install xxx..xxx

==>the location is ~/go/bin
so ,set the ~/go/bin to .bash_profiles 's PATH


go version

go help environment

```

GOBIN

The directory where 'go install' will install a command.

GOPATH

For more details see: 'go help gopath'.

GOROOT

The root of the go tree.

```

go help gopath

```

If the environment variable is unset, GOPATH defaults

to a subdirectory named "go" in the user's home directory

($HOME/go on Unix, %USERPROFILE%\go on Windows),

unless that directory holds a Go distribution.

Run "go env GOPATH" to see the current GOPATH.

```

go env GOPATH

==>~/go

go help install

````

usage: go install [build flags] [packages]


Install compiles and installs the packages named by the import paths.


Executables are installed in the directory named by the GOBIN environment

variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH

environment variable is not set. Executables in $GOROOT

are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN.

```

golang model

https://go.dev/play/p/B7ErJjt8JqU 

modelの役割ですが、
① entity,usecase,repo,querierなど繋ぐ
② validationなどの業務ロジックの担保
②の配慮でmodelのfiledは非公開で、Setter都度Validationする、常に完璧な状態を求めて、
trade-offで使いにくく、①の役割を損する。
なので、①の役割をPrimativeなstruct(一旦voと呼ぶ)に分担する方いいかなと思う。
vo<=>modelの変換は手間ですが、複雑ではないので、ある程度自動作成できる。

-- go.mod --

module sample

go 1.19
-- model/name.go --
package model

import "errors"

type Name struct {
string
}

func NewName(v string) (Name, error) {
n := Name{v}
if err := n.validate(); err != nil {
return Name{}, err
}

return n, nil
}

func (n Name) validate() error {
if len(n.string) > 10 {
return errors.New("name length must be less than equal 10")
}
return nil
}

func (n Name) String() string {
return n.string
}
-- model/user.go --
package model

import "errors"

// entity
type User struct {
id string
name Name
age *int
}

func (u User) validate() error {
if u.id == "" {
return errors.New("id must not be empty")
}
if err := u.name.validate(); err != nil {
return err
}
return nil
}

func NewUser(vo UserVO) (User, error) {
return vo.ToModel()
}

func InitUser(vo UserVO) (User, error) {
vo.ID = "1234567890" // random
return vo.ToModel()
}

func (u User) ToVO() UserVO {
return UserVO{
ID: u.id,
Name: u.name.String(),
Age: u.age,
}
}

type UserVO struct {
ID string
Name string
Age *int
}

func (uvo UserVO) ToModel() (User, error) {
u := User{
id: uvo.ID,
name: Name{uvo.Name},
age: uvo.Age,
}
if err := u.validate(); err != nil {
return User{}, err
}
return u, nil
}
-- main.go --
package main

import (
"fmt"
"sample/model"
)

func main() {
fmt.Println("success pattern")
age := 12
//New
vo := model.UserVO{
ID: "s11600",
Name: "kume",
Age: &age}
u, err := model.NewUser(vo)
if err != nil {
fmt.Println("err:", err)
}
fmt.Printf("valid user, %+v\n", u)

//Init
vo = model.UserVO{
Name: "ku",
Age: &age}
u, err = model.InitUser(vo)
if err != nil {
fmt.Println("err:", err)
}
fmt.Printf("valid user, %+v\n", u)

//update
vo = u.ToVO()
vo.Name = "updated"
vo.Age = nil
u, err = vo.ToModel()
if err != nil {
fmt.Println("err:", err)
}
fmt.Printf("update success, %+v\n", u)



fmt.Println("--------------")
fmt.Println("failed pattern")
vo.Name = "invalid name"
u, err = vo.ToModel()
if err != nil {
fmt.Println("err:", err)
}
fmt.Printf("update failed, %+v\n", u)
}


2022/12/02

2022/11/25

2022/11/22

sql join on using


select * from join1 inner join join2 on join1.join1_id = join2.join1_id;

select * from join1 inner join join2 using(join1_id);


usingで同じ名の列は一つになり、列減少する
基本、usingの方が便利と思う。