Rework Package Database

Package Database/gorm:
- move package database using gorm, to package database/gorm
- update config component following

Package Database/KVItem:
- create new package to manage item of KV Db
- allow to track change on item model
- allow to store only if changed
- embedded driver function to load / store to make instance portable

Package Database/KVTable:
- create new package to manage a table (list of map key : value)
- embedded driver instance to make instance portable
- allow to walk, list, get items with KVItem instance

Package Database/KVDriver:
- create new package to wrap db KV function to KVTable awaiting function
- Allow to skip function Walk replace by a n internal call of function List and Get

Package Database/Map:
- create new package to wrap KV function usage of map[comparable]any to KVDriver model
- Use json marshall/unmarshall between map[comparable]any to model any
This commit is contained in:
nabbar
2023-08-22 18:29:52 +02:00
parent ffb5724c2c
commit 3a2c52195f
25 changed files with 1030 additions and 34 deletions

View File

@@ -29,8 +29,9 @@ package database
import (
"context"
"github.com/nabbar/golib/database/gorm"
cfgtps "github.com/nabbar/golib/config/types"
libdbs "github.com/nabbar/golib/database"
liberr "github.com/nabbar/golib/errors"
libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper"
@@ -159,8 +160,8 @@ func (o *componentDatabase) _runCli() liberr.Error {
var (
err liberr.Error
prt = ErrorComponentReload
dbo libdbs.Database
cfg *libdbs.Config
dbo gorm.Database
cfg *gorm.Config
)
if !o.IsStarted() {
@@ -171,7 +172,7 @@ func (o *componentDatabase) _runCli() liberr.Error {
return prt.Error(err)
}
if dbo, err = libdbs.New(cfg); err != nil {
if dbo, err = gorm.New(cfg); err != nil {
return prt.Error(err)
}

View File

@@ -29,7 +29,8 @@ package database
import (
"time"
libdbs "github.com/nabbar/golib/database"
"github.com/nabbar/golib/database/gorm"
liberr "github.com/nabbar/golib/errors"
spfcbr "github.com/spf13/cobra"
spfvpr "github.com/spf13/viper"
@@ -107,10 +108,10 @@ func (o *componentDatabase) RegisterFlag(Command *spfcbr.Command) error {
return nil
}
func (o *componentDatabase) _getConfig() (*libdbs.Config, liberr.Error) {
func (o *componentDatabase) _getConfig() (*gorm.Config, liberr.Error) {
var (
key string
cfg libdbs.Config
cfg gorm.Config
vpr *spfvpr.Viper
err liberr.Error
)
@@ -129,7 +130,7 @@ func (o *componentDatabase) _getConfig() (*libdbs.Config, liberr.Error) {
cfg.RegisterContext(o.x.GetContext)
if val := vpr.GetString(key + ".driver"); val != "" {
cfg.Driver = libdbs.DriverFromString(val)
cfg.Driver = gorm.DriverFromString(val)
}
if val := vpr.GetString(key + ".name"); val != "" {
cfg.Name = val

View File

@@ -30,10 +30,11 @@ import (
"sync"
"time"
libdbs "github.com/nabbar/golib/database/gorm"
libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
libdbs "github.com/nabbar/golib/database"
)
type ComponentDatabase interface {

View File

@@ -30,8 +30,9 @@ import (
"sync"
"time"
libdbs "github.com/nabbar/golib/database/gorm"
libctx "github.com/nabbar/golib/context"
libdbs "github.com/nabbar/golib/database"
montps "github.com/nabbar/golib/monitor/types"
)

View File

@@ -27,7 +27,7 @@
package database
import (
libdbs "github.com/nabbar/golib/database"
libdbs "github.com/nabbar/golib/database/gorm"
libmon "github.com/nabbar/golib/monitor"
montps "github.com/nabbar/golib/monitor/types"
libver "github.com/nabbar/golib/version"

View File

@@ -24,7 +24,7 @@
*
*/
package database
package gorm
import (
"database/sql"

View File

@@ -27,7 +27,7 @@
*
*/
package database
package gorm
import (
"strings"

View File

@@ -27,7 +27,7 @@
*
*/
package database
package gorm
import (
"strings"

View File

@@ -24,12 +24,18 @@
*
*/
package database
package gorm
import "github.com/nabbar/golib/errors"
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const pkgName = "golib/database/gorm"
const (
ErrorParamsEmpty errors.CodeError = iota + errors.MinPkgDatabase
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgDatabaseGorm
ErrorDatabaseOpen
ErrorDatabaseOpenPool
ErrorValidatorError
@@ -38,22 +44,18 @@ const (
ErrorDatabasePing
)
var isCodeError = false
func IsCodeError() bool {
return isCodeError
}
func init() {
isCodeError = errors.ExistInMapMessage(ErrorParamsEmpty)
errors.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package %s", pkgName))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code errors.CodeError) (message string) {
func getMessage(code liberr.CodeError) (message string) {
switch code {
case errors.UNK_ERROR:
return ""
case ErrorParamsEmpty:
case liberr.UnknownError:
return liberr.NullMessage
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorDatabaseOpen:
return "database : start connection to dsn"
@@ -69,5 +71,5 @@ func getMessage(code errors.CodeError) (message string) {
return "database : ping error"
}
return ""
return liberr.NullMessage
}

View File

@@ -24,7 +24,7 @@
*
*/
package database
package gorm
import (
"context"

View File

@@ -24,7 +24,7 @@
*
*/
package database
package gorm
import (
"context"

View File

@@ -24,7 +24,7 @@
*
*/
package database
package gorm
import (
"context"

View File

@@ -0,0 +1,72 @@
/*
* MIT License
*
* Copyright (c) 2022 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvdriver
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const pkgName = "golib/database/kvdriver"
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgDatabaseKVDrv
ErrorBadInstance
ErrorGetFunction
ErrorSetFunction
ErrorListFunction
ErrorFunctionParams
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package %s", pkgName))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case liberr.UnknownError:
return liberr.NullMessage
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorBadInstance:
return "bad instance of " + pkgName
case ErrorGetFunction:
return "missing get function of " + pkgName
case ErrorSetFunction:
return "missing set function of " + pkgName
case ErrorListFunction:
return "missing list function of " + pkgName
case ErrorFunctionParams:
return "missing function params"
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,50 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvdriver
type FctWalk[K comparable, M any] func(key K, model M) bool
type KVDriver[K comparable, M any] interface {
Get(key K, model *M) error
Set(key K, model M) error
List() ([]K, error)
Walk(fct FctWalk[K, M]) error
}
type FuncGet[K comparable, M any] func(key K) (M, error)
type FuncSet[K comparable, M any] func(key K, model M) error
type FuncList[K comparable, M any] func() ([]K, error)
type FuncWalk[K comparable, M any] func(fct FctWalk[K, M]) error
type Driver[K comparable, M any] struct {
KVDriver[K, M]
FctGet FuncGet[K, M]
FctSet FuncSet[K, M]
FctList FuncList[K, M]
FctWalk FuncWalk[K, M] // optional
}

View File

@@ -0,0 +1,91 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvdriver
func (o *Driver[K, M]) Get(key K, model *M) error {
if o == nil {
return ErrorBadInstance.Error(nil)
} else if o.FctGet == nil {
return ErrorGetFunction.Error(nil)
} else {
m, e := o.FctGet(key)
*model = m
return e
}
}
func (o *Driver[K, M]) Set(key K, model M) error {
if o == nil {
return ErrorBadInstance.Error(nil)
} else if o.FctSet == nil {
return ErrorSetFunction.Error(nil)
} else {
return o.FctSet(key, model)
}
}
func (o *Driver[K, M]) List() ([]K, error) {
if o == nil {
return nil, ErrorBadInstance.Error(nil)
} else if o.FctList == nil {
return nil, ErrorListFunction.Error(nil)
} else {
return o.FctList()
}
}
func (o *Driver[K, M]) Walk(fct FctWalk[K, M]) error {
if o == nil {
return ErrorBadInstance.Error(nil)
} else if fct == nil {
return ErrorFunctionParams.Error(nil)
} else if o.FctWalk == nil {
return o.fakeWalk(fct)
} else {
return o.FctWalk(fct)
}
}
func (o *Driver[K, M]) fakeWalk(fct FctWalk[K, M]) error {
if l, e := o.List(); e != nil {
return e
} else {
for _, k := range l {
var m = *(new(M))
if er := o.Get(k, &m); er != nil {
return er
}
if !fct(k, m) {
return nil
}
}
}
return nil
}

63
database/kvitem/errors.go Normal file
View File

@@ -0,0 +1,63 @@
/*
* MIT License
*
* Copyright (c) 2022 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvitem
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const pkgName = "golib/database/kvitem"
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgDatabaseKVItm
ErrorLoadFunction
ErrorStoreFunction
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package %s", pkgName))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case liberr.UnknownError:
return liberr.NullMessage
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorLoadFunction:
return "missing load function of " + pkgName
case ErrorStoreFunction:
return "missing store function of " + pkgName
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,65 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvitem
import "sync/atomic"
type FuncLoad[K comparable, M any] func(key K, model *M) error
type FuncStore[K comparable, M any] func(key K, model M) error
type KVItem[K comparable, M any] interface {
Set(model M)
Get() M
Load() error
Store(force bool) error
Clean()
HasChange() bool
RegisterFctLoad(fct FuncLoad[K, M])
RegisterFctStore(fct FuncStore[K, M])
}
func New[K comparable, M any](key K) KVItem[K, M] {
var (
ml = new(atomic.Value)
mw = new(atomic.Value)
)
ml.Store(nil)
mw.Store(nil)
return &itm[K, M]{
k: key,
ml: ml,
ms: mw,
fl: nil,
fs: nil,
}
}

203
database/kvitem/model.go Normal file
View File

@@ -0,0 +1,203 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvitem
import (
"reflect"
"sync/atomic"
)
type itm[K comparable, M any] struct {
k K // key
ml *atomic.Value // model read
ms *atomic.Value // model write
fl *atomic.Value
fs *atomic.Value
}
func (o *itm[K, M]) RegisterFctLoad(fct FuncLoad[K, M]) {
o.fl.Store(fct)
}
func (o *itm[K, M]) getFctLoad() FuncLoad[K, M] {
if o == nil {
return nil
}
i := o.fs.Load()
if i == nil {
return nil
} else if f, k := i.(FuncLoad[K, M]); !k {
return nil
} else {
return f
}
}
func (o *itm[K, M]) RegisterFctStore(fct FuncStore[K, M]) {
o.fs.Store(fct)
}
func (o *itm[K, M]) getFctStore() FuncStore[K, M] {
if o == nil {
return nil
}
i := o.fs.Load()
if i == nil {
return nil
} else if f, k := i.(FuncStore[K, M]); !k {
return nil
} else {
return f
}
}
func (o *itm[K, M]) Set(model M) {
if o == nil {
return
}
m := o.ml.Load()
// model not loaded, so store new model
if m == nil {
o.ms.Store(model)
// model loaded and new model given not same, so store new model
} else if !reflect.DeepEqual(m.(M), model) {
o.ms.Store(model)
// model loaded and given model are same, so don't store new model
} else {
o.ms.Store(nil)
}
}
func (o *itm[K, M]) Get() M {
if o == nil {
return *(new(M))
}
// update exist so latest fresh value
m := o.ms.Load()
if m != nil {
if v, k := m.(M); k {
return v
}
}
// load model exist so return last model load
m = o.ml.Load()
if m != nil {
if v, k := m.(M); k {
return v
}
}
// nothing load, so return new instance
return *(new(M))
}
func (o *itm[K, M]) Load() error {
var fct FuncLoad[K, M]
if fct = o.getFctLoad(); fct == nil {
return ErrorLoadFunction.Error(nil)
}
m := *(new(M))
e := fct(o.k, &m)
if e == nil {
o.ml.Store(m)
}
return e
}
func (o *itm[K, M]) Store(force bool) error {
var fct FuncStore[K, M]
if fct = o.getFctStore(); fct == nil {
return ErrorStoreFunction.Error(nil)
}
m := o.ms.Load()
if m != nil {
return fct(o.k, m.(M))
} else if !force {
return nil
}
// no update, but force store, so use load model
m = o.ml.Load()
if m != nil {
return fct(o.k, m.(M))
}
// no update and no load, but force store, so use new instance of model
m = *(new(M))
return fct(o.k, m.(M))
}
func (o *itm[K, M]) Clean() {
o.ml.Store(nil)
o.ms.Store(nil)
}
func (o *itm[K, M]) HasChange() bool {
r := o.ml.Load()
w := o.ms.Load()
if r == nil && w == nil {
// not loaded and not store, so no change
return false
} else if r == nil {
// not loaded but store is set, so has been updated
return true
} else if w == nil {
// loaded and not store, so no change
return false
}
mr, kr := r.(M)
mw, kw := w.(M)
if !kr && !kw {
// no valid model, so no change
return false
} else if !kr {
// not valid model for load, but valid for store, so has been updated
return true
} else if !kw {
// valid model for load, but not valid for store, so like no change
return false
}
return !reflect.DeepEqual(mr, mw)
}

72
database/kvmap/errors.go Normal file
View File

@@ -0,0 +1,72 @@
/*
* MIT License
*
* Copyright (c) 2022 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvmap
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const pkgName = "golib/database/kvmap"
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgDatabaseKVMap
ErrorBadInstance
ErrorGetFunction
ErrorSetFunction
ErrorListFunction
ErrorFunctionParams
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package %s", pkgName))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case liberr.UnknownError:
return liberr.NullMessage
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorBadInstance:
return "bad instance of " + pkgName
case ErrorGetFunction:
return "missing get function of " + pkgName
case ErrorSetFunction:
return "missing set function of " + pkgName
case ErrorListFunction:
return "missing list function of " + pkgName
case ErrorFunctionParams:
return "missing function params"
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,43 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvmap
import (
libkvd "github.com/nabbar/golib/database/kvdriver"
)
type FuncGet[K comparable, MK comparable] func(key K) (map[MK]any, error)
type FuncSet[K comparable, MK comparable] func(key K, model map[MK]any) error
type FuncList[K comparable, MK comparable] func() ([]K, error)
type Driver[K comparable, MK comparable, M any] struct {
libkvd.KVDriver[K, M]
FctGet FuncGet[K, MK]
FctSet FuncSet[K, MK]
FctList FuncList[K, MK]
}

109
database/kvmap/model.go Normal file
View File

@@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvmap
import (
"encoding/json"
libkvd "github.com/nabbar/golib/database/kvdriver"
)
func (o *Driver[K, MK, M]) serialize(model *M, modelMap *map[MK]any) error {
if p, e := json.Marshal(model); e != nil {
return e
} else {
return json.Unmarshal(p, modelMap)
}
}
func (o *Driver[K, MK, M]) unSerialize(modelMap *map[MK]any, model *M) error {
if p, e := json.Marshal(modelMap); e != nil {
return e
} else {
return json.Unmarshal(p, model)
}
}
func (o *Driver[K, MK, M]) Get(key K, model *M) error {
if o == nil {
return ErrorBadInstance.Error(nil)
} else if o.FctGet == nil {
return ErrorGetFunction.Error(nil)
} else if m, e := o.FctGet(key); e != nil {
return e
} else {
return o.unSerialize(&m, model)
}
}
func (o *Driver[K, MK, M]) Set(key K, model M) error {
var m = make(map[MK]any)
if o == nil {
return ErrorBadInstance.Error(nil)
} else if o.FctSet == nil {
return ErrorSetFunction.Error(nil)
} else if e := o.serialize(&model, &m); e != nil {
return e
} else {
return o.FctSet(key, m)
}
}
func (o *Driver[K, MK, M]) List() ([]K, error) {
if o == nil {
return nil, ErrorBadInstance.Error(nil)
} else if o.FctList == nil {
return nil, ErrorListFunction.Error(nil)
} else {
return o.FctList()
}
}
func (o *Driver[K, MK, M]) Walk(fct libkvd.FctWalk[K, M]) error {
if o == nil {
return ErrorBadInstance.Error(nil)
} else if fct == nil {
return ErrorFunctionParams.Error(nil)
} else if l, e := o.List(); e != nil {
return e
} else {
for _, k := range l {
var m = *(new(M))
if er := o.Get(k, &m); er != nil {
return er
}
if !fct(k, m) {
return nil
}
}
}
return nil
}

View File

@@ -0,0 +1,60 @@
/*
* MIT License
*
* Copyright (c) 2022 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvtable
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const pkgName = "golib/database/kvtable"
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgDatabaseKVTbl
ErrorBadDriver
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package %s", pkgName))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case liberr.UnknownError:
return liberr.NullMessage
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorBadDriver:
return "bad driver of " + pkgName
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,51 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvtable
import (
"sync/atomic"
libkvd "github.com/nabbar/golib/database/kvdriver"
libkvi "github.com/nabbar/golib/database/kvitem"
)
type FuncWalk[K comparable, M any] func(kv libkvi.KVItem[K, M]) bool
type KVTable[K comparable, M any] interface {
Get(key K) (libkvi.KVItem[K, M], error)
List() ([]libkvi.KVItem[K, M], error)
Walk(fct FuncWalk[K, M]) error
}
func New[K comparable, M any](drv libkvd.KVDriver[K, M]) KVTable[K, M] {
d := new(atomic.Value)
d.Store(drv)
return &tbl[K, M]{
d: d,
}
}

107
database/kvtable/model.go Normal file
View File

@@ -0,0 +1,107 @@
/*
* MIT License
*
* Copyright (c) 2023 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package kvtable
import (
"sync/atomic"
libkvd "github.com/nabbar/golib/database/kvdriver"
libkvs "github.com/nabbar/golib/database/kvitem"
)
type tbl[K comparable, M any] struct {
d *atomic.Value
}
func (o *tbl[K, M]) getDriver() libkvd.KVDriver[K, M] {
if o == nil {
return nil
}
i := o.d.Load()
if i == nil {
return nil
} else if d, k := i.(libkvd.KVDriver[K, M]); !k {
return nil
} else {
return d
}
}
func (o *tbl[K, M]) Get(key K) (libkvs.KVItem[K, M], error) {
var kvs = libkvs.New[K, M](key)
if drv := o.getDriver(); drv == nil {
return nil, ErrorBadDriver.Error(nil)
} else {
kvs.RegisterFctLoad(drv.Get)
kvs.RegisterFctStore(drv.Set)
}
return kvs, kvs.Load()
}
func (o *tbl[K, M]) Walk(fct FuncWalk[K, M]) error {
if drv := o.getDriver(); drv == nil {
return ErrorBadDriver.Error(nil)
} else {
return drv.Walk(func(key K, model M) bool {
var kvs = libkvs.New[K, M](key)
kvs.RegisterFctStore(drv.Set)
kvs.RegisterFctLoad(func(k K, m *M) error {
*m = model
return nil
})
_ = kvs.Load()
kvs.RegisterFctLoad(drv.Get)
return fct(kvs)
})
}
}
func (o *tbl[K, M]) List() ([]libkvs.KVItem[K, M], error) {
var res = make([]libkvs.KVItem[K, M], 0)
if drv := o.getDriver(); drv == nil {
return nil, ErrorBadDriver.Error(nil)
} else if l, e := drv.List(); e != nil {
return nil, e
} else {
for _, k := range l {
var kvs = libkvs.New[K, M](k)
kvs.RegisterFctLoad(drv.Get)
kvs.RegisterFctStore(drv.Set)
res = append(res, kvs)
}
return res, nil
}
}

View File

@@ -34,7 +34,11 @@ const (
MinPkgConfig = 500
MinPkgConsole = 800
MinPkgCrypt = 900
MinPkgDatabase = 1000
MinPkgDatabaseGorm = 1000
MinPkgDatabaseKVDrv = 1010
MinPkgDatabaseKVMap = 1020
MinPkgDatabaseKVTbl = 1030
MinPkgDatabaseKVItm = 1040
MinPkgFTPClient = 1100
MinPkgHttpCli = 1200
MinPkgHttpServer = 1300