Search: Add Filters for ISO, FNumber and Focal Length Range #3818

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2023-10-12 14:53:40 +02:00
parent bac10302da
commit 6a452bcf43
10 changed files with 552 additions and 226 deletions

View file

@ -78,12 +78,15 @@ type SearchPhotos struct {
Review bool `form:"review" notes:"Finds pictures in review"` // Find photos in review
Camera string `form:"camera" example:"camera:canon" notes:"Camera Make/Model Name"` // Camera UID or name
Lens string `form:"lens" example:"lens:ef24" notes:"Lens Make/Model Name"` // Lens UID or name
Before time.Time `form:"before" time_format:"2006-01-02" notes:"Finds pictures taken before this date"` // Finds images taken before date
After time.Time `form:"after" time_format:"2006-01-02" notes:"Finds pictures taken after this date"` // Finds images taken after date
Count int `form:"count" binding:"required" serialize:"-"` // Result FILE limit
Offset int `form:"offset" serialize:"-"` // Result FILE offset
Order string `form:"order" serialize:"-"` // Sort order
Merged bool `form:"merged" serialize:"-"` // Merge FILES in response
Iso string `form:"iso" example:"iso:200-400" notes:"ISO Range"`
F string `form:"f" example:"f:2.8-4.5" notes:"F-Number Range"`
Mm string `form:"mm" example:"mm:28-35" notes:"Focal Length Range"`
Before time.Time `form:"before" time_format:"2006-01-02" notes:"Finds pictures taken before this date"` // Finds images taken before date
After time.Time `form:"after" time_format:"2006-01-02" notes:"Finds pictures taken after this date"` // Finds images taken after date
Count int `form:"count" binding:"required" serialize:"-"` // Result FILE limit
Offset int `form:"offset" serialize:"-"` // Result FILE offset
Order string `form:"order" serialize:"-"` // Sort order
Merged bool `form:"merged" serialize:"-"` // Merge FILES in response
}
func (f *SearchPhotos) GetQuery() string {

View file

@ -67,6 +67,9 @@ type SearchPhotosGeo struct {
Color string `form:"color"`
Camera int `form:"camera"`
Lens int `form:"lens"`
Iso string `form:"iso" example:"iso:200-400" notes:"ISO Range"`
F string `form:"f" example:"f:2.8-4.5" notes:"F-Number Range"`
Mm string `form:"mm" example:"mm:28-35" notes:"Focal Length Range"`
Count int `form:"count" serialize:"-"`
Offset int `form:"offset" serialize:"-"`
}

View file

@ -494,6 +494,21 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
s = s.Where("lenses.lens_name LIKE ? OR lenses.lens_model LIKE ? OR lenses.lens_slug LIKE ?", v, v, v)
}
// Filter by ISO Range.
if rangeStart, rangeEnd, rangeErr := txt.IntRange(f.Iso, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_iso >= ? AND photos.photo_iso <= ?", rangeStart, rangeEnd)
}
// Filter by F-Number Range.
if rangeStart, rangeEnd, rangeErr := txt.FloatRange(f.F, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_f_number >= ? AND photos.photo_f_number <= ?", rangeStart-0.01, rangeEnd+0.01)
}
// Filter by Focal Length Range.
if rangeStart, rangeEnd, rangeErr := txt.IntRange(f.Mm, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_focal_length >= ? AND photos.photo_focal_length <= ?", rangeStart, rangeEnd)
}
// Filter by year.
if f.Year != "" {
s = s.Where(AnyInt("photos.photo_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax))

View file

@ -407,6 +407,21 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
s = s.Where("photos.lens_id = ?", f.Lens)
}
// Filter by ISO Range.
if rangeStart, rangeEnd, rangeErr := txt.IntRange(f.Iso, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_iso >= ? AND photos.photo_iso <= ?", rangeStart, rangeEnd)
}
// Filter by F-Number Range.
if rangeStart, rangeEnd, rangeErr := txt.FloatRange(f.F, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_f_number >= ? AND photos.photo_f_number <= ?", rangeStart-0.01, rangeEnd+0.01)
}
// Filter by Focal Length Range.
if rangeStart, rangeEnd, rangeErr := txt.IntRange(f.Mm, 0, 10000000); rangeErr == nil {
s = s.Where("photos.photo_focal_length >= ? AND photos.photo_focal_length <= ?", rangeStart, rangeEnd)
}
// Filter by year.
if f.Year != "" {
s = s.Where(AnyInt("photos.photo_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax))

96
pkg/txt/float.go Normal file
View file

@ -0,0 +1,96 @@
package txt
import (
"errors"
"strconv"
"strings"
)
// IsFloat checks if the string represents a floating point number.
func IsFloat(s string) bool {
if s == "" {
return false
}
s = strings.TrimSpace(s)
for _, r := range s {
if r != '.' && r != ',' && (r < '0' || r > '9') {
return false
}
}
return true
}
// Float converts a string to a 64-bit floating point number or 0 if invalid.
func Float(s string) float64 {
if s == "" {
return 0
}
f, err := strconv.ParseFloat(Numeric(s), 64)
if err != nil {
return 0
}
return f
}
// Float32 converts a string to a 32-bit floating point number or 0 if invalid.
func Float32(s string) float32 {
return float32(Float(s))
}
// FloatRange parses a string as floating point number range and returns an error if it's not a valid range.
func FloatRange(s string, min, max float64) (start float64, end float64, err error) {
if s == "" || len(s) > 40 {
return start, end, errors.New("invalid range")
}
valid := false
p := 0
v := [][]byte{make([]byte, 0, 20), make([]byte, 0, 20)}
for i, r := range s {
if r == 45 {
if i == 0 || p == 1 {
v[p] = append(v[p], byte(r))
} else if p == 0 {
p = 1
}
}
if r == 46 || r >= 48 && r <= 57 {
valid = true
v[p] = append(v[p], byte(r))
}
}
if !valid {
return start, end, errors.New("invalid range")
}
if p == 0 {
start = Float(string(v[0]))
end = start
} else {
start = Float(string(v[0]))
end = Float(string(v[1]))
}
if start > max {
start = max
} else if start < min {
start = min
}
if end > max {
end = max
} else if end < min {
end = min
}
return start, end, nil
}

200
pkg/txt/float_test.go Normal file
View file

@ -0,0 +1,200 @@
package txt
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsFloat(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
assert.False(t, IsFloat(""))
})
t.Run("Zero", func(t *testing.T) {
assert.True(t, IsFloat("0"))
})
t.Run("0.5", func(t *testing.T) {
assert.True(t, IsFloat("0.5"))
})
t.Run("0,5", func(t *testing.T) {
assert.True(t, IsFloat("0,5"))
})
t.Run("123000.45245", func(t *testing.T) {
assert.True(t, IsFloat("123000.45245 "))
})
t.Run("123000.", func(t *testing.T) {
assert.True(t, IsFloat("123000. "))
})
t.Run("01:00", func(t *testing.T) {
assert.False(t, IsFloat("01:00"))
})
t.Run("LeadingZeros", func(t *testing.T) {
assert.True(t, IsFloat(" 000123"))
})
t.Run("Comma", func(t *testing.T) {
assert.True(t, IsFloat(" 123,556\t "))
})
}
func TestFloat(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Float("")
assert.Equal(t, 0.0, result)
})
t.Run("NonNumeric", func(t *testing.T) {
result := Float(" Screenshot ")
assert.Equal(t, 0.0, result)
})
t.Run("Zero", func(t *testing.T) {
result := Float("0")
assert.Equal(t, 0.0, result)
})
t.Run("0.5", func(t *testing.T) {
result := Float("0.5")
assert.Equal(t, 0.5, result)
})
t.Run("01:00", func(t *testing.T) {
result := Float("01:00")
assert.Equal(t, 100.0, result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Float(" 000123")
assert.Equal(t, 123.0, result)
})
t.Run("WhitespacePadding", func(t *testing.T) {
result := Float(" 123,556\t ")
assert.Equal(t, 123.556, result)
})
t.Run("PositiveFloat", func(t *testing.T) {
result := Float("123,000.45245 ")
assert.Equal(t, 123000.45245, result)
})
t.Run("NegativeFloat", func(t *testing.T) {
result := Float(" - 123,000.45245 ")
assert.Equal(t, -123000.45245, result)
})
t.Run("MultipleDots", func(t *testing.T) {
result := Float("123.000.45245.44 m")
assert.Equal(t, 1230004524544.0, result)
})
}
func TestFloat32(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Float32("")
assert.Equal(t, float32(0), result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Float32(" 000123")
assert.Equal(t, float32(123), result)
})
t.Run("LongFloat", func(t *testing.T) {
result := Float32("123.87945632786543786547")
assert.Equal(t, float32(123.87945632786543786547), result)
})
}
func TestFloatRange(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
start, end, err := FloatRange("", 1, 31)
assert.Equal(t, 0.0, start)
assert.Equal(t, 0.0, end)
assert.Error(t, err)
})
t.Run("NonNumeric", func(t *testing.T) {
start, end, err := FloatRange("Screenshot", 1, 31)
assert.Equal(t, 0.0, start)
assert.Equal(t, 0.0, end)
assert.Error(t, err)
})
t.Run("Day", func(t *testing.T) {
start, end, err := FloatRange("5.11-24.64", 1, 31)
assert.Equal(t, 5.11, start)
assert.Equal(t, 24.64, end)
assert.NoError(t, err)
})
t.Run("Zero", func(t *testing.T) {
start, end, err := FloatRange("0", 5, 10)
assert.Equal(t, 5.0, start)
assert.Equal(t, 5.0, end)
assert.NoError(t, err)
})
t.Run("LeadingZeros", func(t *testing.T) {
start, end, err := FloatRange("000123", 1, 1000)
assert.Equal(t, 123.0, start)
assert.Equal(t, 123.0, end)
assert.NoError(t, err)
})
t.Run("WhitespacePadding", func(t *testing.T) {
start, end, err := FloatRange(" 123\t ", 1, 1000)
assert.Equal(t, 123.0, start)
assert.Equal(t, 123.0, end)
assert.NoError(t, err)
})
t.Run("PositiveInt", func(t *testing.T) {
start, end, err := FloatRange("123", 1, 1000)
assert.Equal(t, 123.0, start)
assert.Equal(t, 123.0, end)
assert.NoError(t, err)
})
t.Run("NegativeInt", func(t *testing.T) {
start, end, err := FloatRange("-123", -1000, 1000)
assert.Equal(t, -123.0, start)
assert.Equal(t, -123.0, end)
assert.NoError(t, err)
})
t.Run("ZeroOne", func(t *testing.T) {
start, end, err := FloatRange("0-1", -10, 10)
assert.Equal(t, 0.0, start)
assert.Equal(t, 1.0, end)
assert.NoError(t, err)
})
t.Run("NegativeRange", func(t *testing.T) {
start, end, err := FloatRange("-99.9--50.005", -100, 1000)
assert.Equal(t, -99.9, start)
assert.Equal(t, -50.005, end)
assert.NoError(t, err)
})
t.Run("PositiveRange", func(t *testing.T) {
start, end, err := FloatRange("100 - 201", 1, 1000)
assert.Equal(t, 100.0, start)
assert.Equal(t, 201.0, end)
assert.NoError(t, err)
})
t.Run("NegativeToPositive", func(t *testing.T) {
start, end, err := FloatRange("-99999-123456563", -1000000, 1000000)
assert.Equal(t, -99999.0, start)
assert.Equal(t, 1000000.0, end)
assert.NoError(t, err)
})
}

View file

@ -1,6 +1,7 @@
package txt
import (
"errors"
"strconv"
"strings"
)
@ -45,6 +46,58 @@ func IntVal(s string, min, max, def int) (i int) {
return i
}
// IntRange parses a string as integer range and returns an error if it's not a valid range.
func IntRange(s string, min, max int) (start int, end int, err error) {
if s == "" || len(s) > 40 {
return start, end, errors.New("invalid range")
}
valid := false
p := 0
v := [][]byte{make([]byte, 0, 20), make([]byte, 0, 20)}
for i, r := range s {
if r == 45 {
if i == 0 || p == 1 {
v[p] = append(v[p], byte(r))
} else if p == 0 {
p = 1
}
}
if r == 46 || r >= 48 && r <= 57 {
valid = true
v[p] = append(v[p], byte(r))
}
}
if !valid {
return start, end, errors.New("invalid range")
}
if p == 0 {
start = Int(string(v[0]))
end = start
} else {
start = Int(string(v[0]))
end = Int(string(v[1]))
}
if start > max {
start = max
} else if start < min {
start = min
}
if end > max {
end = max
} else if end < min {
end = min
}
return start, end, nil
}
// UInt converts a string to an unsigned integer or 0 if invalid.
func UInt(s string) uint {
if s == "" {
@ -62,6 +115,23 @@ func UInt(s string) uint {
return uint(result)
}
// Int64 converts a string to a signed 64-bit integer or 0 if invalid.
func Int64(s string) int64 {
if s == "" {
return 0
}
i := strings.SplitN(Numeric(s), ".", 2)
result, err := strconv.ParseInt(i[0], 10, 64)
if err != nil {
return 0
}
return result
}
// IsUInt tests if a string represents an unsigned integer.
func IsUInt(s string) bool {
if s == "" {

View file

@ -80,23 +80,90 @@ func TestIntVal(t *testing.T) {
})
}
func TestIsUInt(t *testing.T) {
assert.False(t, IsUInt(""))
assert.False(t, IsUInt("12 3"))
assert.True(t, IsUInt("123"))
}
func TestIntRange(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
start, end, err := IntRange("", 1, 31)
assert.Equal(t, 0, start)
assert.Equal(t, 0, end)
assert.Error(t, err)
})
func TestIsPosInt(t *testing.T) {
assert.False(t, IsPosInt(""))
assert.False(t, IsPosInt("12 3"))
assert.True(t, IsPosInt("123"))
assert.False(t, IsPosInt(" "))
assert.False(t, IsPosInt("-1"))
assert.False(t, IsPosInt("0"))
assert.False(t, IsPosInt("0.1"))
assert.False(t, IsPosInt("0,1"))
assert.True(t, IsPosInt("1"))
assert.True(t, IsPosInt("99943546356"))
t.Run("NonNumeric", func(t *testing.T) {
start, end, err := IntRange("Screenshot", 1, 31)
assert.Equal(t, 0, start)
assert.Equal(t, 0, end)
assert.Error(t, err)
})
t.Run("Day", func(t *testing.T) {
start, end, err := IntRange("5-24", 1, 31)
assert.Equal(t, 5, start)
assert.Equal(t, 24, end)
assert.NoError(t, err)
})
t.Run("Zero", func(t *testing.T) {
start, end, err := IntRange("0", 5, 10)
assert.Equal(t, 5, start)
assert.Equal(t, 5, end)
assert.NoError(t, err)
})
t.Run("LeadingZeros", func(t *testing.T) {
start, end, err := IntRange("000123", 1, 1000)
assert.Equal(t, 123, start)
assert.Equal(t, 123, end)
assert.NoError(t, err)
})
t.Run("WhitespacePadding", func(t *testing.T) {
start, end, err := IntRange(" 123\t ", 1, 1000)
assert.Equal(t, 123, start)
assert.Equal(t, 123, end)
assert.NoError(t, err)
})
t.Run("PositiveInt", func(t *testing.T) {
start, end, err := IntRange("123", 1, 1000)
assert.Equal(t, 123, start)
assert.Equal(t, 123, end)
assert.NoError(t, err)
})
t.Run("NegativeInt", func(t *testing.T) {
start, end, err := IntRange("-123", -1000, 1000)
assert.Equal(t, -123, start)
assert.Equal(t, -123, end)
assert.NoError(t, err)
})
t.Run("ZeroOne", func(t *testing.T) {
start, end, err := IntRange("0-1", -10, 10)
assert.Equal(t, 0, start)
assert.Equal(t, 1, end)
assert.NoError(t, err)
})
t.Run("NegativeRange", func(t *testing.T) {
start, end, err := IntRange("-100--50", -100, 1000)
assert.Equal(t, -100, start)
assert.Equal(t, -50, end)
assert.NoError(t, err)
})
t.Run("PositiveRange", func(t *testing.T) {
start, end, err := IntRange("100 - 201", 1, 1000)
assert.Equal(t, 100, start)
assert.Equal(t, 201, end)
assert.NoError(t, err)
})
t.Run("NegativeToPositive", func(t *testing.T) {
start, end, err := IntRange("-99999-123456563", -1000000, 1000000)
assert.Equal(t, -99999, start)
assert.Equal(t, 1000000, end)
assert.NoError(t, err)
})
}
func TestUInt(t *testing.T) {
@ -130,3 +197,64 @@ func TestUInt(t *testing.T) {
assert.Equal(t, uint(0), result)
})
}
func TestInt64(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Int64("")
assert.Equal(t, int64(0), result)
})
t.Run("NonNumeric", func(t *testing.T) {
result := Int64(" Screenshot ")
assert.Equal(t, int64(0), result)
})
t.Run("Zero", func(t *testing.T) {
result := Int64("0")
assert.Equal(t, int64(0), result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Int64(" 000123")
assert.Equal(t, int64(123), result)
})
t.Run("WhitespacePadding", func(t *testing.T) {
result := Int64(" 123,556\t ")
assert.Equal(t, int64(123), result)
})
t.Run("PositiveFloat", func(t *testing.T) {
result := Int64("123,000.45245 ")
assert.Equal(t, int64(123000), result)
})
t.Run("NegativeFloat", func(t *testing.T) {
result := Int64(" - 123,000.45245 ")
assert.Equal(t, int64(-123000), result)
})
t.Run("MultipleDots", func(t *testing.T) {
result := Int64("123.000.45245.44 m")
assert.Equal(t, int64(1230004524544), result)
})
}
func TestIsUInt(t *testing.T) {
assert.False(t, IsUInt(""))
assert.False(t, IsUInt("12 3"))
assert.True(t, IsUInt("123"))
}
func TestIsPosInt(t *testing.T) {
assert.False(t, IsPosInt(""))
assert.False(t, IsPosInt("12 3"))
assert.True(t, IsPosInt("123"))
assert.False(t, IsPosInt(" "))
assert.False(t, IsPosInt("-1"))
assert.False(t, IsPosInt("0"))
assert.False(t, IsPosInt("0.1"))
assert.False(t, IsPosInt("0,1"))
assert.True(t, IsPosInt("1"))
assert.True(t, IsPosInt("99943546356"))
}

View file

@ -1,7 +1,6 @@
package txt
import (
"strconv"
"strings"
)
@ -32,57 +31,3 @@ func Numeric(s string) string {
return s
}
// IsFloat checks if the string represents a floating point number.
func IsFloat(s string) bool {
if s == "" {
return false
}
s = strings.TrimSpace(s)
for _, r := range s {
if r != '.' && r != ',' && (r < '0' || r > '9') {
return false
}
}
return true
}
// Float converts a string to a 64-bit floating point number or 0 if invalid.
func Float(s string) float64 {
if s == "" {
return 0
}
f, err := strconv.ParseFloat(Numeric(s), 64)
if err != nil {
return 0
}
return f
}
// Float32 converts a string to a 32-bit floating point number or 0 if invalid.
func Float32(s string) float32 {
return float32(Float(s))
}
// Int64 converts a string to a signed 64-bit integer or 0 if invalid.
func Int64(s string) int64 {
if s == "" {
return 0
}
i := strings.SplitN(Numeric(s), ".", 2)
result, err := strconv.ParseInt(i[0], 10, 64)
if err != nil {
return 0
}
return result
}

View file

@ -57,152 +57,3 @@ func TestNumeric(t *testing.T) {
assert.Equal(t, "1230004524544", result)
})
}
func TestIsFloat(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
assert.False(t, IsFloat(""))
})
t.Run("Zero", func(t *testing.T) {
assert.True(t, IsFloat("0"))
})
t.Run("0.5", func(t *testing.T) {
assert.True(t, IsFloat("0.5"))
})
t.Run("0,5", func(t *testing.T) {
assert.True(t, IsFloat("0,5"))
})
t.Run("123000.45245", func(t *testing.T) {
assert.True(t, IsFloat("123000.45245 "))
})
t.Run("123000.", func(t *testing.T) {
assert.True(t, IsFloat("123000. "))
})
t.Run("01:00", func(t *testing.T) {
assert.False(t, IsFloat("01:00"))
})
t.Run("LeadingZeros", func(t *testing.T) {
assert.True(t, IsFloat(" 000123"))
})
t.Run("Comma", func(t *testing.T) {
assert.True(t, IsFloat(" 123,556\t "))
})
}
func TestFloat(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Float("")
assert.Equal(t, 0.0, result)
})
t.Run("NonNumeric", func(t *testing.T) {
result := Float(" Screenshot ")
assert.Equal(t, 0.0, result)
})
t.Run("Zero", func(t *testing.T) {
result := Float("0")
assert.Equal(t, 0.0, result)
})
t.Run("0.5", func(t *testing.T) {
result := Float("0.5")
assert.Equal(t, 0.5, result)
})
t.Run("01:00", func(t *testing.T) {
result := Float("01:00")
assert.Equal(t, 100.0, result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Float(" 000123")
assert.Equal(t, 123.0, result)
})
t.Run("WhitespacePadding", func(t *testing.T) {
result := Float(" 123,556\t ")
assert.Equal(t, 123.556, result)
})
t.Run("PositiveFloat", func(t *testing.T) {
result := Float("123,000.45245 ")
assert.Equal(t, 123000.45245, result)
})
t.Run("NegativeFloat", func(t *testing.T) {
result := Float(" - 123,000.45245 ")
assert.Equal(t, -123000.45245, result)
})
t.Run("MultipleDots", func(t *testing.T) {
result := Float("123.000.45245.44 m")
assert.Equal(t, 1230004524544.0, result)
})
}
func TestFloat32(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Float32("")
assert.Equal(t, float32(0), result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Float32(" 000123")
assert.Equal(t, float32(123), result)
})
t.Run("LongFloat", func(t *testing.T) {
result := Float32("123.87945632786543786547")
assert.Equal(t, float32(123.87945632786543786547), result)
})
}
func TestInt64(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
result := Int64("")
assert.Equal(t, int64(0), result)
})
t.Run("NonNumeric", func(t *testing.T) {
result := Int64(" Screenshot ")
assert.Equal(t, int64(0), result)
})
t.Run("Zero", func(t *testing.T) {
result := Int64("0")
assert.Equal(t, int64(0), result)
})
t.Run("LeadingZeros", func(t *testing.T) {
result := Int64(" 000123")
assert.Equal(t, int64(123), result)
})
t.Run("WhitespacePadding", func(t *testing.T) {
result := Int64(" 123,556\t ")
assert.Equal(t, int64(123), result)
})
t.Run("PositiveFloat", func(t *testing.T) {
result := Int64("123,000.45245 ")
assert.Equal(t, int64(123000), result)
})
t.Run("NegativeFloat", func(t *testing.T) {
result := Int64(" - 123,000.45245 ")
assert.Equal(t, int64(-123000), result)
})
t.Run("MultipleDots", func(t *testing.T) {
result := Int64("123.000.45245.44 m")
assert.Equal(t, int64(1230004524544), result)
})
}