mirror of
https://github.com/IBM/fp-go.git
synced 2025-12-11 23:17:16 +02:00
Compare commits
1 Commits
v1.0.75
...
cleue-add-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bf432af49 |
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@v5
|
uses: actions/setup-go@v4
|
||||||
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@v5
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{env.GO_VERSION}}
|
go-version: ${{env.GO_VERSION}}
|
||||||
|
|
||||||
|
|||||||
@@ -308,16 +308,10 @@ func SliceRight[A any](start int) func([]A) []A {
|
|||||||
return G.SliceRight[[]A](start)
|
return G.SliceRight[[]A](start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a shallow copy of the array
|
|
||||||
func Copy[A any](b []A) []A {
|
func Copy[A any](b []A) []A {
|
||||||
return G.Copy(b)
|
return G.Copy(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
|
|
||||||
func Clone[A any](f func(A) A) func(as []A) []A {
|
|
||||||
return G.Clone[[]A](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
||||||
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
|
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
|
||||||
return G.FoldMap[[]A](m)
|
return G.FoldMap[[]A](m)
|
||||||
|
|||||||
@@ -304,11 +304,6 @@ func Copy[AS ~[]A, A any](b AS) AS {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS {
|
|
||||||
// implementation assumes that map does not optimize for the empty array
|
|
||||||
return Map[AS, AS](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
|
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
|
||||||
return func(f func(A) B) func(AS) B {
|
return func(f func(A) B) func(AS) B {
|
||||||
return func(as AS) B {
|
return func(as AS) B {
|
||||||
|
|||||||
115
di/provider.go
115
di/provider.go
@@ -73,46 +73,6 @@ 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 {
|
||||||
@@ -200,81 +160,6 @@ 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)))
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
// 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"
|
|
||||||
M "github.com/IBM/fp-go/monoid"
|
|
||||||
S "github.com/IBM/fp-go/semigroup"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Of converts any function to an [Endomorphism]
|
|
||||||
func Of[ENDO ~func(A) A, F ~func(A) A, A any](f F) ENDO {
|
|
||||||
return func(a A) A {
|
|
||||||
return f(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Identity[ENDO ~func(A) A, A any]() ENDO {
|
|
||||||
return func(a A) A {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Compose[ENDO ~func(A) A, A any](f1, f2 ENDO) ENDO {
|
|
||||||
return func(a A) A {
|
|
||||||
return F.Pipe2(a, f1, f2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
|
||||||
func Semigroup[ENDO ~func(A) A, A any]() S.Semigroup[ENDO] {
|
|
||||||
return S.MakeSemigroup(Compose[ENDO])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
|
||||||
func Monoid[ENDO ~func(A) A, A any]() M.Monoid[ENDO] {
|
|
||||||
return M.MakeMonoid(Compose[ENDO], Identity[ENDO]())
|
|
||||||
}
|
|
||||||
@@ -16,30 +16,17 @@
|
|||||||
package endomorphism
|
package endomorphism
|
||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/endomorphism/generic"
|
F "github.com/IBM/fp-go/function"
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
S "github.com/IBM/fp-go/semigroup"
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Endomorphism is a function that
|
|
||||||
type Endomorphism[A any] func(A) A
|
|
||||||
|
|
||||||
// Of converts any function to an [Endomorphism]
|
|
||||||
func Of[F ~func(A) A, A any](f F) Endomorphism[A] {
|
|
||||||
return G.Of[Endomorphism[A]](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identity returns the identity [Endomorphism]
|
|
||||||
func Identity[A any]() Endomorphism[A] {
|
|
||||||
return G.Identity[Endomorphism[A]]()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
func Semigroup[A any]() S.Semigroup[Endomorphism[A]] {
|
func Semigroup[A any]() S.Semigroup[func(A) A] {
|
||||||
return G.Semigroup[Endomorphism[A]]()
|
return S.MakeSemigroup(F.Flow2[func(A) A, func(A) A])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
func Monoid[A any]() M.Monoid[Endomorphism[A]] {
|
func Monoid[A any]() M.Monoid[func(A) A] {
|
||||||
return G.Monoid[Endomorphism[A]]()
|
return M.MakeMonoid(F.Flow2[func(A) A, func(A) A], F.Identity[A])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
|
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import "path/filepath"
|
||||||
"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 {
|
||||||
@@ -26,13 +23,3 @@ 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.26.0
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -10,8 +10,6 @@ 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=
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
// 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 form
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
|
||||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
|
||||||
F "github.com/IBM/fp-go/function"
|
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
|
||||||
LA "github.com/IBM/fp-go/optics/lens/array"
|
|
||||||
LRG "github.com/IBM/fp-go/optics/lens/record/generic"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// FormEndomorphism returns an [ENDO.Endomorphism] that transforms a form
|
|
||||||
FormEndomorphism = ENDO.Endomorphism[url.Values]
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Default is the default form field
|
|
||||||
Default = make(url.Values)
|
|
||||||
|
|
||||||
noField = O.None[string]()
|
|
||||||
|
|
||||||
// AtValues is a [L.Lens] that focusses on the values of a form field
|
|
||||||
AtValues = LRG.AtRecord[url.Values, []string]
|
|
||||||
|
|
||||||
composeHead = F.Pipe1(
|
|
||||||
LA.AtHead[string](),
|
|
||||||
L.ComposeOptions[url.Values, string](A.Empty[string]()),
|
|
||||||
)
|
|
||||||
|
|
||||||
// AtValue is a [L.Lens] that focusses on first value in form fields
|
|
||||||
AtValue = F.Flow2(
|
|
||||||
AtValues,
|
|
||||||
composeHead,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithValue creates a [FormBuilder] for a certain field
|
|
||||||
func WithValue(name string) func(value string) FormEndomorphism {
|
|
||||||
return F.Flow3(
|
|
||||||
O.Of[string],
|
|
||||||
AtValue(name).Set,
|
|
||||||
ENDO.Of[func(url.Values) url.Values],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithoutValue creates a [FormBuilder] that removes a field
|
|
||||||
func WithoutValue(name string) FormEndomorphism {
|
|
||||||
return AtValue(name).Set(noField)
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
// 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 form
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
|
||||||
"github.com/IBM/fp-go/eq"
|
|
||||||
F "github.com/IBM/fp-go/function"
|
|
||||||
LT "github.com/IBM/fp-go/optics/lens/testing"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
|
||||||
RG "github.com/IBM/fp-go/record/generic"
|
|
||||||
S "github.com/IBM/fp-go/string"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
sEq = eq.FromEquals(S.Eq)
|
|
||||||
valuesEq = RG.Eq[url.Values](A.Eq(sEq))
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLaws(t *testing.T) {
|
|
||||||
name := "Content-Type"
|
|
||||||
fieldLaws := LT.AssertLaws[url.Values, O.Option[string]](t, O.Eq(sEq), valuesEq)(AtValue(name))
|
|
||||||
|
|
||||||
n := O.None[string]()
|
|
||||||
s1 := O.Some("s1")
|
|
||||||
|
|
||||||
v1 := F.Pipe1(
|
|
||||||
Default,
|
|
||||||
WithValue(name)("v1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
v2 := F.Pipe1(
|
|
||||||
Default,
|
|
||||||
WithValue("Other-Header")("v2"),
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.True(t, fieldLaws(Default, n))
|
|
||||||
assert.True(t, fieldLaws(v1, n))
|
|
||||||
assert.True(t, fieldLaws(v2, n))
|
|
||||||
|
|
||||||
assert.True(t, fieldLaws(Default, s1))
|
|
||||||
assert.True(t, fieldLaws(v1, s1))
|
|
||||||
assert.True(t, fieldLaws(v2, s1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormField(t *testing.T) {
|
|
||||||
|
|
||||||
v1 := F.Pipe1(
|
|
||||||
Default,
|
|
||||||
WithValue("h1")("v1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
v2 := F.Pipe1(
|
|
||||||
v1,
|
|
||||||
WithValue("h2")("v2"),
|
|
||||||
)
|
|
||||||
|
|
||||||
// make sure the code does not change structures
|
|
||||||
assert.False(t, valuesEq.Equals(Default, v1))
|
|
||||||
assert.False(t, valuesEq.Equals(Default, v2))
|
|
||||||
assert.False(t, valuesEq.Equals(v1, v2))
|
|
||||||
|
|
||||||
// check for existence of values
|
|
||||||
assert.Equal(t, "v1", v1.Get("h1"))
|
|
||||||
assert.Equal(t, "v1", v2.Get("h1"))
|
|
||||||
assert.Equal(t, "v2", v2.Get("h2"))
|
|
||||||
|
|
||||||
// check getter on lens
|
|
||||||
|
|
||||||
l1 := AtValue("h1")
|
|
||||||
l2 := AtValue("h2")
|
|
||||||
|
|
||||||
assert.Equal(t, O.Of("v1"), l1.Get(v1))
|
|
||||||
assert.Equal(t, O.Of("v1"), l1.Get(v2))
|
|
||||||
assert.Equal(t, O.Of("v2"), l2.Get(v2))
|
|
||||||
}
|
|
||||||
@@ -49,16 +49,6 @@ 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,
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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))
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
// 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"
|
|
||||||
|
|
||||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
|
||||||
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]]
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuilderEndomorphism returns an [ENDO.Endomorphism] that transforms a builder
|
|
||||||
BuilderEndomorphism = ENDO.Endomorphism[*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) BuilderEndomorphism {
|
|
||||||
return F.Flow3(
|
|
||||||
O.Of[string],
|
|
||||||
Header(name).Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithoutHeader creates a [BuilderBuilder] to remove a certain header
|
|
||||||
func WithoutHeader(name string) BuilderEndomorphism {
|
|
||||||
return Header(name).Set(noHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithFormData creates a [BuilderBuilder] to send form data payload
|
|
||||||
func WithFormData(value url.Values) BuilderEndomorphism {
|
|
||||||
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) BuilderEndomorphism {
|
|
||||||
return F.Flow2(
|
|
||||||
F.Pipe3(
|
|
||||||
data,
|
|
||||||
J.Marshal[T],
|
|
||||||
IOE.FromEither[error, []byte],
|
|
||||||
WithBody,
|
|
||||||
),
|
|
||||||
WithContentType("application/json"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// 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))
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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,12 +16,10 @@
|
|||||||
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"
|
||||||
@@ -53,24 +51,6 @@ 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,7 +20,6 @@ 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"
|
||||||
@@ -77,48 +76,8 @@ 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 optiont.Chain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], f)
|
return F.Bind2nd(MonadChain[GA, GB, A, 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 {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
// 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,7 +18,6 @@ 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"
|
||||||
@@ -144,23 +143,3 @@ 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)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
AA "github.com/IBM/fp-go/array/generic"
|
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AtHead focusses on the head of an array. The setter works as follows
|
|
||||||
// - if the new value is none, the result will be an empty array
|
|
||||||
// - if the new value is some and the array is empty, it creates a new array with one element
|
|
||||||
// - if the new value is some and the array is not empty, it replaces the head
|
|
||||||
func AtHead[AS []A, A any]() L.Lens[AS, O.Option[A]] {
|
|
||||||
return L.MakeLens(AA.Head[AS, A], func(as AS, a O.Option[A]) AS {
|
|
||||||
return O.MonadFold(a, AA.Empty[AS], func(v A) AS {
|
|
||||||
if AA.IsEmpty(as) {
|
|
||||||
return AA.Of[AS, A](v)
|
|
||||||
}
|
|
||||||
cpy := AA.Copy(as)
|
|
||||||
cpy[0] = v
|
|
||||||
return cpy
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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 array
|
|
||||||
|
|
||||||
import (
|
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
|
||||||
G "github.com/IBM/fp-go/optics/lens/array/generic"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AtHead focusses on the head of an array. The setter works as follows
|
|
||||||
// - if the new value is none, the result will be an empty array
|
|
||||||
// - if the new value is some and the array is empty, it creates a new array with one element
|
|
||||||
// - if the new value is some and the array is not empty, it replaces the head
|
|
||||||
func AtHead[A any]() L.Lens[[]A, O.Option[A]] {
|
|
||||||
return G.AtHead[[]A]()
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// 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 array
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
|
||||||
"github.com/IBM/fp-go/eq"
|
|
||||||
LT "github.com/IBM/fp-go/optics/lens/testing"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
|
||||||
S "github.com/IBM/fp-go/string"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
sEq = eq.FromEquals(S.Eq)
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLaws(t *testing.T) {
|
|
||||||
headLaws := LT.AssertLaws(t, O.Eq(sEq), A.Eq(sEq))(AtHead[string]())
|
|
||||||
|
|
||||||
assert.True(t, headLaws(A.Empty[string](), O.None[string]()))
|
|
||||||
assert.True(t, headLaws(A.Empty[string](), O.Of("a")))
|
|
||||||
assert.True(t, headLaws(A.From("a", "b"), O.None[string]()))
|
|
||||||
assert.True(t, headLaws(A.From("a", "b"), O.Of("c")))
|
|
||||||
}
|
|
||||||
@@ -531,12 +531,3 @@ func MonadFlap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](fab G
|
|||||||
func Flap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](a A) func(GFAB) GB {
|
func Flap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](a A) func(GFAB) GB {
|
||||||
return FC.Flap(MonadMap[GFAB, GB], a)
|
return FC.Flap(MonadMap[GFAB, GB], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Copy[M ~map[K]V, K comparable, V any](m M) M {
|
|
||||||
return duplicate(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Clone[M ~map[K]V, K comparable, V any](f func(V) V) func(m M) M {
|
|
||||||
// impementation assumes that map does not optimize for the empty map
|
|
||||||
return Map[M, M](f)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -284,13 +284,3 @@ func MonadFlap[B any, K comparable, A any](fab map[K]func(A) B, a A) map[K]B {
|
|||||||
func Flap[B any, K comparable, A any](a A) func(map[K]func(A) B) map[K]B {
|
func Flap[B any, K comparable, A any](a A) func(map[K]func(A) B) map[K]B {
|
||||||
return G.Flap[map[K]func(A) B, map[K]B](a)
|
return G.Flap[map[K]func(A) B, map[K]B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a shallow copy of the map
|
|
||||||
func Copy[K comparable, V any](m map[K]V) map[K]V {
|
|
||||||
return G.Copy[map[K]V](m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone creates a deep copy of the map using the provided endomorphism to clone the values
|
|
||||||
func Clone[K comparable, V any](f func(V) V) func(m map[K]V) map[K]V {
|
|
||||||
return G.Clone[map[K]V](f)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
|
||||||
"github.com/IBM/fp-go/internal/utils"
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
S "github.com/IBM/fp-go/string"
|
S "github.com/IBM/fp-go/string"
|
||||||
@@ -132,20 +131,3 @@ func ExampleValuesOrd() {
|
|||||||
// Output: [c b a]
|
// Output: [c b a]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCopyVsClone(t *testing.T) {
|
|
||||||
slc := []string{"b", "c"}
|
|
||||||
src := map[string][]string{
|
|
||||||
"a": slc,
|
|
||||||
}
|
|
||||||
// make a shallow copy
|
|
||||||
cpy := Copy(src)
|
|
||||||
// make a deep copy
|
|
||||||
cln := Clone[string](A.Copy[string])(src)
|
|
||||||
|
|
||||||
assert.Equal(t, cpy, cln)
|
|
||||||
// make a modification to the original slice
|
|
||||||
slc[0] = "d"
|
|
||||||
assert.NotEqual(t, cpy, cln)
|
|
||||||
assert.Equal(t, src, cpy)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user