Giter VIP home page Giter VIP logo

mold's Introduction

Package mold

Project status Build Status Coverage Status Go Report Card GoDoc License

Package mold is a general library to help modify or set data within data structures and other objects.

How can this help me you ask, please see the examples here

Requirements

  • Go 1.18+

Installation

Use go get.

go get -u github.com/go-playground/mold/v4

Examples

Example Description
simple A basic example with custom function.
full A more real life example combining the usage of multiple packages.

Modifiers

These functions modify the data in-place.

Name Description
camel Camel Cases the data.
default Sets the provided default value only if the data is equal to it's default datatype value.
empty Sets the field equal to the datatype default value. e.g. 0 for int.
lcase lowercases the data.
ltrim Trims spaces from the left of the data provided in the params.
rtrim Trims spaces from the right of the data provided in the params.
set Set the provided value.
slug Converts the field to a slug
snake Snake Cases the data.
strip_alpha Strips all ascii characters from the data.
strip_alpha_unicode Strips all unicode characters from the data.
strip_num Strips all ascii numeric characters from the data.
strip_num_unicode Strips all unicode numeric characters from the data.
strip_punctuation Strips all ascii punctuation from the data.
title Title Cases the data.
tprefix Trims a prefix from the value using the provided param value.
trim Trims space from the data.
tsuffix Trims a suffix from the value using the provided param value.
ucase Uppercases the data.
ucfirst Upper cases the first character of the data.

Special Notes: default and set modifiers are special in that they can be used to set the value of a field or underlying type information or attributes and both use the same underlying function to set the data.

Setting a Param will have the following special effects on data types where it's not just the value being set:

  • Chan - param used to set the buffer size, default = 0.
  • Slice - param used to set the capacity, default = 0.
  • Map - param used to set the size, default = 0.
  • time.Time - param used to set the time format OR value, default = time.Now(), utc = time.Now().UTC(), other tries to parse using RFC3339Nano and set a time value.

Scrubbers

These functions obfuscate the specified types within the data for pii purposes.

Name Description
emails Scrubs multiple emails from data.
email Scrubs the data from and specifies the sha name of the same name.
text Scrubs the data from and specifies the sha name of the same name.
name Scrubs the data from and specifies the sha name of the same name.
fname Scrubs the data from and specifies the sha name of the same name.
lname Scrubs the data from and specifies the sha name of the same name.

Special Information

  • To use a comma(,) within your params replace use it's hex representation instead '0x2C' which will be replaced while caching.

Contributing

I am definitely interested in the communities help in adding more scrubbers and modifiers. Please send a PR with tests, and preferably no extra dependencies, at lease until a solid base has been built.

Complimentary Software

Here is a list of software that compliments using this library post decoding.

  • validator - Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving.
  • form - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

License

Distributed under MIT License, please see license file in code for more details.

mold's People

Contributors

arieroos avatar arkan avatar deankarn avatar frederikhors avatar jcconnell avatar nchelluri avatar trentmillar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mold's Issues

Gin example

Do you have any example how to setup gin with v9 and modifiers/scrubbers?

Coming from other languages this seems like a nice way to handle it without writing a custom validator/processor for every user input. The only thing is, at least for me as a newish guy to golang, I have no clue how to integrate it with gin. The validator-upgrade.go is somewhat understandable, but I'm totally lost on how and where to hook into. Where does gin and the validator do the stuff and how do I inject mold.Transformer and actually execute it, prior to the validator (binding) run?

Can you give any hints or is there any help page I've missed?

Add support for "dive,keys,โ€ฆ,endkeys,dive"

Use case:

type A struct {
    M map[string]*B `mod:"dive"` // WANTED: `mod:"dive,keys,trim,endkeys,dive"`
}
type B struct {
    S string `mod:"trim"`
}

With "dive" on M it will process "trim" on S, but won't process map keys.
With "dive,keys,trim,endkeys" on M it will process map keys but won't process "trim" on S.
And the WANTED string result in an error "invalid dive tag configuration".

Struct func doesn't work on slice fields

Struct(ctx context.Context, v interface{}) error func doesn't work on slice fields.

Here is the example code (inspired by _examples/full/main.go):

import (
	"context"
	"fmt"
	"log"
	"reflect"

	"github.com/go-playground/mold/v3"
	"github.com/go-playground/mold/v3/modifiers"
)

type Address struct {
	Name  string `mod:"trim"`
	Phone string `mod:"trim"`
}

type User struct {
	Name    string           `mod:"trim"`
	Age     uint8
	Gender  string          `mod:"trim"`
	Email   string             `mod:"trim"`
	Address []Address
}

func main() {
        user := User{
		Name:   "test   ",
		Age:    50,
		Gender: "female",
		Email:  "[email protected]",
		Address: []Address{
			{
				Name:  "test   address    ",
				Phone: " 123 456  ",
			},
			{
				Name:  "test   address    ",
				Phone: " 123 456  ",
			},
		},
	}

        conform  := modifiers.New()
	if err := conform.Struct(context.Background(), &user); err != nil {
		log.Panic(err)
	}
	fmt.Printf("Conformed:%+v\n\n", user)
}

Output:

Conformed:{Name:test Age:50 Gender:female Email:[email protected] Address:[{Name:test   address     Phone: 123 456  } {Name:test   address     Phone: 123 456  }]}

So, Name and Phone fields of the Address struct weren't trimmed.

If I add dive tag to the Address field the Struct func will panic:

type User struct {
        ...
	Address []Address `mod:"dive"`
}

Panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x32 pc=0x10c0c19]

goroutine 1 [running]:
github.com/go-playground/mold/v3.(*Transformer).setByField(0xc000021ac0, 0x11cf500, 0xc0000160a0, 0x1176760, 0xc000021b00, 0x199, 0xc00018ae70, 0x0, 0x0, 0x0)
/Users/myuser/go/pkg/mod/github.com/go-playground/mold/[email protected]/mold.go:202 +0x79
github.com/go-playground/mold/v3.(*Transformer).setByField(0xc000021ac0, 0x11cf500, 0xc0000160a0, 0x115af80, 0xc00009adf8, 0x197, 0xc00018ae40, 0x0, 0x0, 0x0)
...

The reason for the panic is that the dive tag could not be used alone, so you'll have to add some tag after it (endkeys tag doesn't work as well).

The workaround for that issue is to register a dummy transform function:

func items(_ context.Context, _ *mold.Transformer, _ reflect.Value, _ string) error {
	return nil
}

...

conform.Register("items", items)

... and add a mod:"dive,items" tag to the slice field:

type User struct {
        ...
	Address []Address `mod:"dive,items"`
}

I think that the issue should be addressed either by fixing this in the lib or by adding that to the documentation.

What do you think?

P.S.
I can help with a PR if you need it.

Thanks.

question: plans to port validator on top of this?

Seems like the Transform is a refactoring of the basic struct traversal logic from validator. Was thinking it would be really useful to have a re-usable struct visitor library like this, to build focussed struct processing packages, like one which sets default values, initializes values from environment variables, or validates.

One thing I see missing from mold, which validator uses, is that the Func doesn't know where it is in the hierarchy, so it isn't possible to include that information in error messages or validation problems.

I'm interested in the idea of building other types of struct processors on top of this core because I use a number of them currently, and they are all slightly different in how they work. For example, whether they allow setting the tag name, what they do with fields with no tags, how many tag names that package uses, how they traverse embedded structs, which types they handle, etc. Would be really nice to have a core traversal logic which encouraged some patterns, like one (configurable) tag per package/processor, consistent handling of untagged fields, etc.

Support for more transformers like "max length" on string etc

I'm coming from a Node.js background. My company is switching a lot of text processing stuff from Node to Go and we're looking for validation and sanitization libraries.

We used to use a library called "schema-inspector"
(https://www.npmjs.com/package/schema-inspector) which broke this into two steps. They have a "sanitize" step where the rules are used to modify the data. Then they have a "validate" step where if the data doesn't fit the rule, it throws an error. We use this for strings with rules like "max length". For example, if you have a rule where the username property has a max length of 5 and this object:

{
  "username": "bobbytables"
}

then after the sanitize step, you'll end up with this object:

{
  "username": "bobby"
}

And then after the validate step, this would pass because the data has been transformed to meet the rule during the sanitization step. Usually situations where the data would pass sanitization but fail validation are when you've got broad rules like "max length on a string" in the sanitize step but more focussed rules like a regexp match on the validate step.

I was wondering if as the library authors, you are willing to accept PRs to add these features? I notice the following source code in the library:

// New returns a modifier with defaults registered
func New() *mold.Transformer {
	mod := mold.New()
	mod.SetTagName("mod")
	mod.Register("trim", TrimSpace)
	mod.Register("ltrim", TrimLeft)
	mod.Register("rtrim", TrimRight)
	mod.Register("tprefix", TrimPrefix)
	mod.Register("tsuffix", TrimSuffix)
	mod.Register("lcase", ToLower)
	mod.Register("ucase", ToUpper)
	mod.Register("snake", SnakeCase)
	return mod
}

This is really simple to understand even as a Go novice. I can see how I would extend this by adding more modules I can register. There could be a module added to handle trimming based on a max length for example. If you're willing to accept PRs, I can direct the work here instead of us rolling our own.

Looking forward to hearing back from you!

Register() on modifiers.New()

If I try to register on modifiers.New() it compiles but doesn't work.

var conform = modifiers.New()

func init() {
	conform.Register("set", transformMyData)
}

func transformMyData(ctx context.Context, t *mold.Transformer, value reflect.Value, param string) error {
	value.SetString("test")
	return nil
}

func Struct(myStruct interface{}) error {
	if err := conform.Struct(context.Background(), myStruct); err != nil {
		return err
	}
	return nil
}

Am I right?

*string to nil if empty string

Let's say I have this struct:

type User struct {
  Username *string
}

and I need to sanitize it from empty string: I want Username to be nil if is an empty string (maybe because previous modifiers made it empty).

Is it correct to do this with this package?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.