mirror of
https://github.com/IBM/fp-go.git
synced 2025-12-09 23:11:40 +02:00
Compare commits
12 Commits
cleue-fix-
...
v1.0.73
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7ec18c83e | ||
|
|
96686425fb | ||
|
|
1f675e08fa | ||
|
|
4d2f410c98 | ||
|
|
8f49c1328c | ||
|
|
2a1d5821db | ||
|
|
6abbdc5ee1 | ||
|
|
5fea9858a9 | ||
|
|
e6426c90c0 | ||
|
|
54ce59105e | ||
|
|
8bb006c741 | ||
|
|
b6efa35b03 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up go ${{ matrix.go-version }}
|
- name: Set up go ${{ matrix.go-version }}
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
-
|
-
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
- name: Set up go ${{env.GO_VERSION}}
|
- name: Set up go ${{env.GO_VERSION}}
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{env.GO_VERSION}}
|
go-version: ${{env.GO_VERSION}}
|
||||||
|
|
||||||
|
|||||||
32
array/generic/uniq.go
Normal file
32
array/generic/uniq.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package generic
|
||||||
|
|
||||||
|
import F "github.com/IBM/fp-go/function"
|
||||||
|
|
||||||
|
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||||
|
// where uniqueness is determined by the built-in uniqueness constraint
|
||||||
|
func StrictUniq[AS ~[]A, A comparable](as AS) AS {
|
||||||
|
return Uniq[AS](F.Identity[A])(as)
|
||||||
|
}
|
||||||
|
|
||||||
|
// uniquePredUnsafe returns a predicate on a map for uniqueness
|
||||||
|
func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool {
|
||||||
|
lookup := make(map[K]bool)
|
||||||
|
return func(_ int, a A) bool {
|
||||||
|
k := f(a)
|
||||||
|
_, has := lookup[k]
|
||||||
|
if has {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
lookup[k] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniq converts an array of arbitrary items into an array or unique items
|
||||||
|
// where uniqueness is determined based on a key extractor function
|
||||||
|
func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS {
|
||||||
|
return func(as AS) AS {
|
||||||
|
// we need to create a new predicate for each iteration
|
||||||
|
return filterWithIndex(as, uniquePredUnsafe(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
17
array/uniq.go
Normal file
17
array/uniq.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||||
|
// where uniqueness is determined by the built-in uniqueness constraint
|
||||||
|
func StrictUniq[A comparable](as []A) []A {
|
||||||
|
return G.StrictUniq[[]A](as)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniq converts an array of arbitrary items into an array or unique items
|
||||||
|
// where uniqueness is determined based on a key extractor function
|
||||||
|
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
|
||||||
|
return G.Uniq[[]A](f)
|
||||||
|
}
|
||||||
14
array/uniq_test.go
Normal file
14
array/uniq_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUniq(t *testing.T) {
|
||||||
|
data := From(1, 2, 3, 2, 4, 1)
|
||||||
|
|
||||||
|
uniq := StrictUniq(data)
|
||||||
|
assert.Equal(t, From(1, 2, 3, 4), uniq)
|
||||||
|
}
|
||||||
115
di/provider.go
115
di/provider.go
@@ -73,6 +73,46 @@ func eraseProviderFactory2[T1, T2 any, R any](
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func eraseProviderFactory3[T1, T2, T3 any, R any](
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
f func(T1, T2, T3) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||||
|
ft := T.Tupled3(f)
|
||||||
|
t1 := lookupAt[T1](0, d1)
|
||||||
|
t2 := lookupAt[T2](1, d2)
|
||||||
|
t3 := lookupAt[T3](2, d3)
|
||||||
|
return func(params ...any) IOE.IOEither[error, any] {
|
||||||
|
return F.Pipe3(
|
||||||
|
E.SequenceT3(t1(params), t2(params), t3(params)),
|
||||||
|
IOE.FromEither[error, T.Tuple3[T1, T2, T3]],
|
||||||
|
IOE.Chain(ft),
|
||||||
|
IOE.Map[error](F.ToAny[R]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func eraseProviderFactory4[T1, T2, T3, T4 any, R any](
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
d4 Dependency[T4],
|
||||||
|
f func(T1, T2, T3, T4) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||||
|
ft := T.Tupled4(f)
|
||||||
|
t1 := lookupAt[T1](0, d1)
|
||||||
|
t2 := lookupAt[T2](1, d2)
|
||||||
|
t3 := lookupAt[T3](2, d3)
|
||||||
|
t4 := lookupAt[T4](3, d4)
|
||||||
|
return func(params ...any) IOE.IOEither[error, any] {
|
||||||
|
return F.Pipe3(
|
||||||
|
E.SequenceT4(t1(params), t2(params), t3(params), t4(params)),
|
||||||
|
IOE.FromEither[error, T.Tuple4[T1, T2, T3, T4]],
|
||||||
|
IOE.Chain(ft),
|
||||||
|
IOE.Map[error](F.ToAny[R]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MakeProviderFactory0[R any](
|
func MakeProviderFactory0[R any](
|
||||||
fct func() IOE.IOEither[error, R],
|
fct func() IOE.IOEither[error, R],
|
||||||
) DIE.ProviderFactory {
|
) DIE.ProviderFactory {
|
||||||
@@ -160,6 +200,81 @@ func MakeProvider2[T1, T2, R any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MakeProviderFactory3[T1, T2, T3, R any](
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
fct func(T1, T2, T3) IOE.IOEither[error, R],
|
||||||
|
) DIE.ProviderFactory {
|
||||||
|
|
||||||
|
return DIE.MakeProviderFactory(
|
||||||
|
A.From[DIE.Dependency](d1, d2, d3),
|
||||||
|
eraseProviderFactory3(d1, d2, d3, fct),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeTokenWithDefault3 create a unique `InjectionToken` for a specific type with an attached default provider
|
||||||
|
func MakeTokenWithDefault3[T1, T2, T3, R any](name string,
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
fct func(T1, T2, T3) IOE.IOEither[error, R]) InjectionToken[R] {
|
||||||
|
return MakeTokenWithDefault[R](name, MakeProviderFactory3(d1, d2, d3, fct))
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeProvider3[T1, T2, T3, R any](
|
||||||
|
token InjectionToken[R],
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
fct func(T1, T2, T3) IOE.IOEither[error, R],
|
||||||
|
) DIE.Provider {
|
||||||
|
|
||||||
|
return DIE.MakeProvider(
|
||||||
|
token,
|
||||||
|
MakeProviderFactory3(d1, d2, d3, fct),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeProviderFactory4[T1, T2, T3, T4, R any](
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
d4 Dependency[T4],
|
||||||
|
fct func(T1, T2, T3, T4) IOE.IOEither[error, R],
|
||||||
|
) DIE.ProviderFactory {
|
||||||
|
|
||||||
|
return DIE.MakeProviderFactory(
|
||||||
|
A.From[DIE.Dependency](d1, d2, d3, d4),
|
||||||
|
eraseProviderFactory4(d1, d2, d3, d4, fct),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeTokenWithDefault4 create a unique `InjectionToken` for a specific type with an attached default provider
|
||||||
|
func MakeTokenWithDefault4[T1, T2, T3, T4, R any](name string,
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
d4 Dependency[T4],
|
||||||
|
fct func(T1, T2, T3, T4) IOE.IOEither[error, R]) InjectionToken[R] {
|
||||||
|
return MakeTokenWithDefault[R](name, MakeProviderFactory4(d1, d2, d3, d4, fct))
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeProvider4[T1, T2, T3, T4, R any](
|
||||||
|
token InjectionToken[R],
|
||||||
|
d1 Dependency[T1],
|
||||||
|
d2 Dependency[T2],
|
||||||
|
d3 Dependency[T3],
|
||||||
|
d4 Dependency[T4],
|
||||||
|
fct func(T1, T2, T3, T4) IOE.IOEither[error, R],
|
||||||
|
) DIE.Provider {
|
||||||
|
|
||||||
|
return DIE.MakeProvider(
|
||||||
|
token,
|
||||||
|
MakeProviderFactory4(d1, d2, d3, d4, fct),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// ConstProvider simple implementation for a provider with a constant value
|
// ConstProvider simple implementation for a provider with a constant value
|
||||||
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
||||||
return MakeProvider0[R](token, F.Constant(IOE.Of[error](value)))
|
return MakeProvider0[R](token, F.Constant(IOE.Of[error](value)))
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
|
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import "path/filepath"
|
import (
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
// Join appends a filename to a root path
|
// Join appends a filename to a root path
|
||||||
func Join(name string) func(root string) string {
|
func Join(name string) func(root string) string {
|
||||||
@@ -23,3 +26,13 @@ func Join(name string) func(root string) string {
|
|||||||
return filepath.Join(root, name)
|
return filepath.Join(root, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToReader converts a [io.Reader]
|
||||||
|
func ToReader[R io.Reader](r R) io.Reader {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCloser converts a [io.Closer]
|
||||||
|
func ToCloser[C io.Closer](c C) io.Closer {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.20
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/urfave/cli/v2 v2.25.7
|
github.com/urfave/cli/v2 v2.26.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -10,6 +10,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
|
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
|
||||||
|
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ func MonadChain[A, B, HKTFA, HKTFB any](
|
|||||||
return fchain(ma, O.Fold(F.Nullary2(O.None[B], fof), f))
|
return fchain(ma, O.Fold(F.Nullary2(O.None[B], fof), f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Chain[A, B, HKTFA, HKTFB any](
|
||||||
|
fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB,
|
||||||
|
fof func(O.Option[B]) HKTFB,
|
||||||
|
f func(A) HKTFB) func(ma HKTFA) HKTFB {
|
||||||
|
// dispatch to the even more generic implementation
|
||||||
|
return func(ma HKTFA) HKTFB {
|
||||||
|
return MonadChain(fchain, fof, ma, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||||
fap func(HKTFGAB, HKTFA) HKTFB,
|
fap func(HKTFGAB, HKTFA) HKTFB,
|
||||||
fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB,
|
fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB,
|
||||||
|
|||||||
30
io/generic/resource.go
Normal file
30
io/generic/resource.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||||
|
func WithResource[
|
||||||
|
GA ~func() A,
|
||||||
|
GR ~func() R,
|
||||||
|
GANY ~func() ANY,
|
||||||
|
R, A, ANY any](onCreate GR, onRelease func(R) GANY) func(func(R) GA) GA {
|
||||||
|
// simply map to implementation of bracket
|
||||||
|
return F.Bind13of3(Bracket[GR, GA, GANY, R, A, ANY])(onCreate, F.Ignore2of2[A](onRelease))
|
||||||
|
}
|
||||||
27
io/resource.go
Normal file
27
io/resource.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package io
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/io/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||||
|
func WithResource[
|
||||||
|
R, A, ANY any](onCreate IO[R], onRelease func(R) IO[ANY]) func(func(R) IO[A]) IO[A] {
|
||||||
|
// just dispatch
|
||||||
|
return G.WithResource[IO[A], IO[R], IO[ANY]](onCreate, onRelease)
|
||||||
|
}
|
||||||
248
ioeither/http/builder/builder.go
Normal file
248
ioeither/http/builder/builder.go
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
IOEH "github.com/IBM/fp-go/ioeither/http"
|
||||||
|
J "github.com/IBM/fp-go/json"
|
||||||
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
S "github.com/IBM/fp-go/string"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Builder struct {
|
||||||
|
method O.Option[string]
|
||||||
|
url string
|
||||||
|
headers http.Header
|
||||||
|
body O.Option[IOE.IOEither[error, []byte]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuilderBuilder returns a function that transforms a builder
|
||||||
|
BuilderBuilder = func(*Builder) *Builder
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Default is the default builder
|
||||||
|
Default = &Builder{method: O.Some(defaultMethod()), headers: make(http.Header), body: noBody}
|
||||||
|
|
||||||
|
defaultMethod = F.Constant(http.MethodGet)
|
||||||
|
|
||||||
|
// Url is a [L.Lens] for the URL
|
||||||
|
Url = L.MakeLensRef((*Builder).GetUrl, (*Builder).SetUrl)
|
||||||
|
// Method is a [L.Lens] for the HTTP method
|
||||||
|
Method = L.MakeLensRef((*Builder).GetMethod, (*Builder).SetMethod)
|
||||||
|
// Body is a [L.Lens] for the request body
|
||||||
|
Body = L.MakeLensRef((*Builder).GetBody, (*Builder).SetBody)
|
||||||
|
// Headers is a [L.Lens] for the complete set of request headers
|
||||||
|
Headers = L.MakeLensRef((*Builder).GetHeaders, (*Builder).SetHeaders)
|
||||||
|
|
||||||
|
getHeader = F.Bind2of2((*Builder).GetHeader)
|
||||||
|
delHeader = F.Bind2of2((*Builder).DelHeader)
|
||||||
|
setHeader = F.Bind2of3((*Builder).SetHeader)
|
||||||
|
|
||||||
|
noHeader = O.None[string]()
|
||||||
|
noBody = O.None[IOE.IOEither[error, []byte]]()
|
||||||
|
|
||||||
|
// WithMethod creates a [BuilderBuilder] for a certain method
|
||||||
|
WithMethod = Method.Set
|
||||||
|
// WithUrl creates a [BuilderBuilder] for a certain method
|
||||||
|
WithUrl = Url.Set
|
||||||
|
// WithHeaders creates a [BuilderBuilder] for a set of headers
|
||||||
|
WithHeaders = Headers.Set
|
||||||
|
// WithBody creates a [BuilderBuilder] for a request body
|
||||||
|
WithBody = F.Flow2(
|
||||||
|
O.Of[IOE.IOEither[error, []byte]],
|
||||||
|
Body.Set,
|
||||||
|
)
|
||||||
|
// WithContentType adds the content type header
|
||||||
|
WithContentType = WithHeader("Content-Type")
|
||||||
|
|
||||||
|
// WithGet adds the [http.MethodGet] method
|
||||||
|
WithGet = WithMethod(http.MethodGet)
|
||||||
|
// WithPost adds the [http.MethodPost] method
|
||||||
|
WithPost = WithMethod(http.MethodPost)
|
||||||
|
// WithPut adds the [http.MethodPut] method
|
||||||
|
WithPut = WithMethod(http.MethodPut)
|
||||||
|
// WithDelete adds the [http.MethodDelete] method
|
||||||
|
WithDelete = WithMethod(http.MethodDelete)
|
||||||
|
|
||||||
|
// Requester creates a requester from a builder
|
||||||
|
Requester = (*Builder).Requester
|
||||||
|
|
||||||
|
// WithoutBody creates a [BuilderBuilder] to remove the body
|
||||||
|
WithoutBody = Body.Set(noBody)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (builder *Builder) clone() *Builder {
|
||||||
|
cpy := *builder
|
||||||
|
cpy.headers = cpy.headers.Clone()
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetUrl() string {
|
||||||
|
return builder.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetMethod() string {
|
||||||
|
return F.Pipe1(
|
||||||
|
builder.method,
|
||||||
|
O.GetOrElse(defaultMethod),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeaders() http.Header {
|
||||||
|
return builder.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetBody() O.Option[IOE.IOEither[error, []byte]] {
|
||||||
|
return builder.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetMethod(method string) *Builder {
|
||||||
|
builder.method = O.Some(method)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetUrl(url string) *Builder {
|
||||||
|
builder.url = url
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetHeaders(headers http.Header) *Builder {
|
||||||
|
builder.headers = headers
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetBody(body O.Option[IOE.IOEither[error, []byte]]) *Builder {
|
||||||
|
builder.body = body
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetHeader(name, value string) *Builder {
|
||||||
|
builder.headers.Set(name, value)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) DelHeader(name string) *Builder {
|
||||||
|
builder.headers.Del(name)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeader(name string) O.Option[string] {
|
||||||
|
return F.Pipe2(
|
||||||
|
name,
|
||||||
|
builder.headers.Get,
|
||||||
|
O.FromPredicate(S.IsNonEmpty),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeaderValues(name string) []string {
|
||||||
|
return builder.headers.Values(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) AddHeaderHeader(name, value string) *Builder {
|
||||||
|
builder.headers.Add(name, value)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) Requester() IOEH.Requester {
|
||||||
|
return F.Pipe3(
|
||||||
|
builder.GetBody(),
|
||||||
|
O.Map(IOE.Map[error](bytes.NewReader)),
|
||||||
|
O.GetOrElse(F.Constant(IOE.Of[error, *bytes.Reader](nil))),
|
||||||
|
IOE.Chain(func(rdr *bytes.Reader) IOE.IOEither[error, *http.Request] {
|
||||||
|
return IOE.TryCatchError(func() (*http.Request, error) {
|
||||||
|
req, err := http.NewRequest(builder.GetMethod(), builder.GetUrl(), rdr)
|
||||||
|
if err == nil {
|
||||||
|
for name, value := range builder.GetHeaders() {
|
||||||
|
req.Header[name] = value
|
||||||
|
}
|
||||||
|
if rdr != nil {
|
||||||
|
req.Header.Set("Content-Length", strconv.FormatInt(rdr.Size(), 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header returns a [L.Lens] for a single header
|
||||||
|
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
||||||
|
get := getHeader(name)
|
||||||
|
set := F.Bind1of2(setHeader(name))
|
||||||
|
del := F.Flow2(
|
||||||
|
LZ.Of[*Builder],
|
||||||
|
LZ.Map(delHeader(name)),
|
||||||
|
)
|
||||||
|
|
||||||
|
return L.MakeLens[*Builder, O.Option[string]](get, func(b *Builder, value O.Option[string]) *Builder {
|
||||||
|
cpy := b.clone()
|
||||||
|
return F.Pipe1(
|
||||||
|
value,
|
||||||
|
O.Fold(del(cpy), set(cpy)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeader creates a [BuilderBuilder] for a certain header
|
||||||
|
func WithHeader(name string) func(value string) BuilderBuilder {
|
||||||
|
return F.Flow2(
|
||||||
|
O.Of[string],
|
||||||
|
Header(name).Set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutHeader creates a [BuilderBuilder] to remove a certain header
|
||||||
|
func WithoutHeader(name string) BuilderBuilder {
|
||||||
|
return Header(name).Set(noHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFormData creates a [BuilderBuilder] to send form data payload
|
||||||
|
func WithFormData(value url.Values) BuilderBuilder {
|
||||||
|
return F.Flow2(
|
||||||
|
F.Pipe4(
|
||||||
|
value,
|
||||||
|
url.Values.Encode,
|
||||||
|
S.ToBytes,
|
||||||
|
IOE.Of[error, []byte],
|
||||||
|
WithBody,
|
||||||
|
),
|
||||||
|
WithContentType("application/x-www-form-urlencoded"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithJson creates a [BuilderBuilder] to send JSON payload
|
||||||
|
func WithJson[T any](data T) BuilderBuilder {
|
||||||
|
return F.Flow2(
|
||||||
|
F.Pipe3(
|
||||||
|
data,
|
||||||
|
J.Marshal[T],
|
||||||
|
IOE.FromEither[error, []byte],
|
||||||
|
WithBody,
|
||||||
|
),
|
||||||
|
WithContentType("application/json"),
|
||||||
|
)
|
||||||
|
}
|
||||||
51
ioeither/http/builder/builder_test.go
Normal file
51
ioeither/http/builder/builder_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuiler(t *testing.T) {
|
||||||
|
|
||||||
|
name := "Content-type"
|
||||||
|
withContentType := WithHeader(name)
|
||||||
|
withoutContentType := WithoutHeader(name)
|
||||||
|
|
||||||
|
b1 := F.Pipe1(
|
||||||
|
Default,
|
||||||
|
withContentType("application/json"),
|
||||||
|
)
|
||||||
|
|
||||||
|
b2 := F.Pipe1(
|
||||||
|
b1,
|
||||||
|
withContentType("text/plain"),
|
||||||
|
)
|
||||||
|
|
||||||
|
b3 := F.Pipe1(
|
||||||
|
b2,
|
||||||
|
withoutContentType,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, O.None[string](), Default.GetHeader(name))
|
||||||
|
assert.Equal(t, O.Of("application/json"), b1.GetHeader(name))
|
||||||
|
assert.Equal(t, O.Of("text/plain"), b2.GetHeader(name))
|
||||||
|
assert.Equal(t, O.None[string](), b3.GetHeader(name))
|
||||||
|
}
|
||||||
32
ioeither/http/di.go
Normal file
32
ioeither/http/di.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
DI "github.com/IBM/fp-go/di"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// InjHttpClient is the injection token for the default http client
|
||||||
|
InjHttpClient = DI.MakeTokenWithDefault0("HTTP_CLIENT", L.Of(IOE.Of[error](http.DefaultClient)))
|
||||||
|
|
||||||
|
// InjClient is the injection token for the default [Client]
|
||||||
|
InjClient = DI.MakeTokenWithDefault1("CLIENT", InjHttpClient.IOEither(), IOE.Map[error](MakeClient))
|
||||||
|
)
|
||||||
@@ -16,10 +16,12 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
B "github.com/IBM/fp-go/bytes"
|
B "github.com/IBM/fp-go/bytes"
|
||||||
|
FL "github.com/IBM/fp-go/file"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
H "github.com/IBM/fp-go/http"
|
H "github.com/IBM/fp-go/http"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
@@ -51,6 +53,24 @@ var (
|
|||||||
MakeGetRequest = makeRequest("GET", nil)
|
MakeGetRequest = makeRequest("GET", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MakeBodyRequest creates a request that carries a body
|
||||||
|
func MakeBodyRequest(method string, body IOE.IOEither[error, []byte]) func(url string) IOE.IOEither[error, *http.Request] {
|
||||||
|
onBody := F.Pipe1(
|
||||||
|
body,
|
||||||
|
IOE.Map[error](F.Flow2(
|
||||||
|
bytes.NewReader,
|
||||||
|
FL.ToReader[*bytes.Reader],
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
onRelease := IOE.Of[error, io.Reader]
|
||||||
|
withMethod := F.Bind1of3(MakeRequest)(method)
|
||||||
|
|
||||||
|
return F.Flow2(
|
||||||
|
F.Bind1of2(withMethod),
|
||||||
|
IOE.WithResource[*http.Request](onBody, onRelease),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (client client) Do(req Requester) IOE.IOEither[error, *http.Response] {
|
func (client client) Do(req Requester) IOE.IOEither[error, *http.Response] {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
FI "github.com/IBM/fp-go/internal/fromio"
|
FI "github.com/IBM/fp-go/internal/fromio"
|
||||||
"github.com/IBM/fp-go/internal/optiont"
|
"github.com/IBM/fp-go/internal/optiont"
|
||||||
IO "github.com/IBM/fp-go/io/generic"
|
IO "github.com/IBM/fp-go/io/generic"
|
||||||
@@ -76,8 +77,48 @@ func MonadChain[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA,
|
|||||||
return optiont.MonadChain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], fa, f)
|
return optiont.MonadChain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func MonadChainFirst[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](ma GA, f func(A) GB) GA {
|
||||||
|
return C.MonadChainFirst(
|
||||||
|
MonadChain[GA, GA, A, A],
|
||||||
|
MonadMap[GB, GA, B, A],
|
||||||
|
ma,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func ChainFirst[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](f func(A) GB) func(GA) GA {
|
||||||
|
return C.ChainFirst(
|
||||||
|
MonadChain[GA, GA, A, A],
|
||||||
|
MonadMap[GB, GA, B, A],
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func MonadChainFirstIOK[GA ~func() O.Option[A], GIOB ~func() B, A, B any](first GA, f func(A) GIOB) GA {
|
||||||
|
return FI.MonadChainFirstIOK(
|
||||||
|
MonadChain[GA, GA, A, A],
|
||||||
|
MonadMap[func() O.Option[B], GA, B, A],
|
||||||
|
FromIO[func() O.Option[B], GIOB, B],
|
||||||
|
first,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func ChainFirstIOK[GA ~func() O.Option[A], GIOB ~func() B, A, B any](f func(A) GIOB) func(GA) GA {
|
||||||
|
return FI.ChainFirstIOK(
|
||||||
|
MonadChain[GA, GA, A, A],
|
||||||
|
MonadMap[func() O.Option[B], GA, B, A],
|
||||||
|
FromIO[func() O.Option[B], GIOB, B],
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func Chain[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](f func(A) GB) func(GA) GB {
|
func Chain[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](f func(A) GB) func(GA) GB {
|
||||||
return F.Bind2nd(MonadChain[GA, GB, A, B], f)
|
return optiont.Chain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainOptionK[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](ma GA, f func(A) O.Option[B]) GB {
|
func MonadChainOptionK[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](ma GA, f func(A) O.Option[B]) GB {
|
||||||
|
|||||||
31
iooption/generic/resource.go
Normal file
31
iooption/generic/resource.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||||
|
func WithResource[
|
||||||
|
GA ~func() O.Option[A],
|
||||||
|
GR ~func() O.Option[R],
|
||||||
|
GANY ~func() O.Option[ANY],
|
||||||
|
R, A, ANY any](onCreate GR, onRelease func(R) GANY) func(func(R) GA) GA {
|
||||||
|
// simply map to implementation of bracket
|
||||||
|
return F.Bind13of3(Bracket[GR, GA, GANY, R, A, ANY])(onCreate, F.Ignore2of2[O.Option[A]](onRelease))
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ package iooption
|
|||||||
import (
|
import (
|
||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
I "github.com/IBM/fp-go/io"
|
I "github.com/IBM/fp-go/io"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
G "github.com/IBM/fp-go/iooption/generic"
|
G "github.com/IBM/fp-go/iooption/generic"
|
||||||
L "github.com/IBM/fp-go/lazy"
|
L "github.com/IBM/fp-go/lazy"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
@@ -143,3 +144,23 @@ func MonadAlt[A any](first IOOption[A], second L.Lazy[IOOption[A]]) IOOption[A]
|
|||||||
func Alt[A any](second L.Lazy[IOOption[A]]) func(IOOption[A]) IOOption[A] {
|
func Alt[A any](second L.Lazy[IOOption[A]]) func(IOOption[A]) IOOption[A] {
|
||||||
return G.Alt(second)
|
return G.Alt(second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func MonadChainFirst[A, B any](ma IOOption[A], f func(A) IOOption[B]) IOOption[A] {
|
||||||
|
return G.MonadChainFirst[IOOption[A], IOOption[B]](ma, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func ChainFirst[A, B any](f func(A) IOOption[B]) func(IOOption[A]) IOOption[A] {
|
||||||
|
return G.ChainFirst[IOOption[A], IOOption[B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO.IO[B]) IOOption[A] {
|
||||||
|
return G.MonadChainFirstIOK[IOOption[A], IO.IO[B]](first, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||||
|
func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(IOOption[A]) IOOption[A] {
|
||||||
|
return G.ChainFirstIOK[IOOption[A], IO.IO[B]](f)
|
||||||
|
}
|
||||||
|
|||||||
27
iooption/resource.go
Normal file
27
iooption/resource.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package iooption
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/iooption/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||||
|
func WithResource[
|
||||||
|
R, A, ANY any](onCreate IOOption[R], onRelease func(R) IOOption[ANY]) func(func(R) IOOption[A]) IOOption[A] {
|
||||||
|
// just dispatch
|
||||||
|
return G.WithResource[IOOption[A], IOOption[R], IOOption[ANY]](onCreate, onRelease)
|
||||||
|
}
|
||||||
@@ -19,13 +19,13 @@ import (
|
|||||||
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StrictUniq converts an [Iterator] or arbitrary items into an [Iterator] or unique items
|
// StrictUniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items
|
||||||
// where uniqueness is determined by the built-in uniqueness constraint
|
// where uniqueness is determined by the built-in uniqueness constraint
|
||||||
func StrictUniq[A comparable](as Iterator[A]) Iterator[A] {
|
func StrictUniq[A comparable](as Iterator[A]) Iterator[A] {
|
||||||
return G.StrictUniq[Iterator[A]](as)
|
return G.StrictUniq[Iterator[A]](as)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniq converts an [Iterator] or arbitrary items into an [Iterator] or unique items
|
// Uniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items
|
||||||
// where uniqueness is determined based on a key extractor function
|
// where uniqueness is determined based on a key extractor function
|
||||||
func Uniq[A any, K comparable](f func(A) K) func(as Iterator[A]) Iterator[A] {
|
func Uniq[A any, K comparable](f func(A) K) func(as Iterator[A]) Iterator[A] {
|
||||||
return G.Uniq[Iterator[A], K](f)
|
return G.Uniq[Iterator[A], K](f)
|
||||||
|
|||||||
Reference in New Issue
Block a user