Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
perxis-go
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Package registry
Operate
Terraform modules
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
perxis
perxis-go
Commits
9b0d4c3a
Commit
9b0d4c3a
authored
1 month ago
by
Semyon Krestyaninov
Committed by
Pavel Antonov
1 month ago
Browse files
Options
Downloads
Patches
Plain Diff
fix(core): Исправлена выгрузка полей Item в JSON, приведены к camelCase
Issue:
https://git.perx.ru/perxis/perxis/-/issues/3296
parent
58478a6b
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
pkg/items/item.go
+89
-6
89 additions, 6 deletions
pkg/items/item.go
pkg/items/item_test.go
+240
-0
240 additions, 0 deletions
pkg/items/item_test.go
with
329 additions
and
6 deletions
pkg/items/item.go
+
89
−
6
View file @
9b0d4c3a
...
...
@@ -13,6 +13,7 @@ import (
"git.perx.ru/perxis/perxis-go/pkg/schema/localizer"
"git.perx.ru/perxis/perxis-go/pkg/schema/walk"
pb
"git.perx.ru/perxis/perxis-go/proto/items"
"github.com/mitchellh/mapstructure"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
)
...
...
@@ -106,7 +107,7 @@ type Item struct {
// При создании или обновлении идентификатор локали в котором создается запись, опционально.
// Если указан, то создается перевод для указанного языка, поле translations игнорируется
LocaleID
string
`json:"locale
_id
" bson:"-"`
LocaleID
string
`json:"locale
Id,omitempty
" bson:"-"`
// Позволяет одновременно установить/получить несколько переводов и производить манипуляции с переводами
// Ключами является идентификатор локали, значениями - данные переводы
...
...
@@ -117,11 +118,11 @@ type Item struct {
// - {"lang":map{...}} - установка перевода для языка
// - {"lang":map{...}, "*":nil} - установка перевода для языка, сброс остальных переводов
// - {"*":nil} - сброс всех переводов
Translations
map
[
string
]
map
[
string
]
interface
{}
`json:"translations" bson:"translations,omitempty"`
Translations
map
[
string
]
map
[
string
]
interface
{}
`json:"translations
,omitempty
" bson:"translations,omitempty"`
// Список идентификаторов локалей, для которых есть переводы.
// Соответствует ключам в translations
TranslationsIDs
[]
string
`json:"translations
_ids
" bson:"translations_ids,omitempty"`
TranslationsIDs
[]
string
`json:"translations
Ids,omitempty
" bson:"translations_ids,omitempty"`
RevisionID
string
`json:"revId,omitempty" bson:"revision_id"`
RevisionDescription
string
`json:"revDescription,omitempty" bson:"revision_description"`
...
...
@@ -130,9 +131,9 @@ type Item struct {
// Релеватность элемента при полнотекстовом поиске
SearchScore
float64
`json:"searchScore,omitempty" bson:"search_score,omitempty"`
Deleted
bool
`json:"deleted
"
bson:"deleted,omitempty"`
Hidden
bool
`json:"hidden
"
bson:"hidden,omitempty"`
Template
bool
`json:"template" bson:"template,omitempty"`
Deleted
bool
`json:"deleted
,omitempty"
bson:"deleted,omitempty"`
Hidden
bool
`json:"hidden
,omitempty"
bson:"hidden,omitempty"`
Template
bool
`json:"template
,omitempty
" bson:"template,omitempty"`
}
func
NewItem
(
spaceID
,
envID
,
collID
,
id
string
,
data
map
[
string
]
interface
{},
translations
map
[
string
]
map
[
string
]
interface
{})
*
Item
{
...
...
@@ -169,6 +170,8 @@ func (i *Item) Clone() *Item {
return
&
itm
}
// ToMap конвертирует текущий элемент в map[string]any.
// DEPRECATED, используйте ToMap.
func
(
i
*
Item
)
ToMap
()
map
[
string
]
interface
{}
{
return
map
[
string
]
interface
{}{
"id"
:
i
.
ID
,
...
...
@@ -194,6 +197,86 @@ func (i *Item) ToMap() map[string]interface{} {
}
}
// ToMap конвертирует переданный Item в map[string]any, кодируя данные согласно схеме.
// Вычисляемые поля удаляются из результата.
func
ToMap
(
item
*
Item
,
sch
*
schema
.
Schema
)
(
map
[
string
]
any
,
error
)
{
if
item
==
nil
{
return
nil
,
errors
.
New
(
"item must not be nil"
)
}
if
sch
==
nil
{
return
nil
,
errors
.
New
(
"schema must not be nil"
)
}
output
:=
make
(
map
[
string
]
any
)
decoder
,
err
:=
mapstructure
.
NewDecoder
(
&
mapstructure
.
DecoderConfig
{
TagName
:
"json"
,
Result
:
&
output
,
})
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to create decoder"
)
}
item
,
err
=
item
.
Encode
(
context
.
Background
(),
sch
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to encode item by schema"
)
}
err
=
decoder
.
Decode
(
item
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to encode item"
)
}
// Кодируем системные поля со временем
output
[
"createdRevAt"
]
=
item
.
CreatedRevAt
.
Format
(
time
.
RFC3339
)
output
[
"createdAt"
]
=
item
.
CreatedAt
.
Format
(
time
.
RFC3339
)
output
[
"updatedAt"
]
=
item
.
UpdatedAt
.
Format
(
time
.
RFC3339
)
// Удаляем вычисляемые поля
delete
(
output
,
"permissions"
)
delete
(
output
,
"searchScore"
)
return
output
,
nil
}
// FromMap конвертирует переданный map[string]any в Item, декодируя данные согласно схеме.
// Вычисляемые поля игнорируются при декодировании.
func
FromMap
(
input
map
[
string
]
any
,
sch
*
schema
.
Schema
)
(
*
Item
,
error
)
{
if
len
(
input
)
==
0
{
return
nil
,
errors
.
New
(
"input map must not be empty or nil"
)
}
if
sch
==
nil
{
return
nil
,
errors
.
New
(
"schema must not be nil"
)
}
item
:=
&
Item
{}
decoder
,
err
:=
mapstructure
.
NewDecoder
(
&
mapstructure
.
DecoderConfig
{
DecodeHook
:
mapstructure
.
StringToTimeHookFunc
(
time
.
RFC3339
),
TagName
:
"json"
,
Result
:
item
,
})
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to create decoder"
)
}
// Удаляем вычисляемые поля
delete
(
input
,
"permissions"
)
delete
(
input
,
"searchScore"
)
err
=
decoder
.
Decode
(
input
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to decode"
)
}
item
,
err
=
item
.
Decode
(
context
.
Background
(),
sch
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to decode item by schema"
)
}
return
item
,
nil
}
// SetData устанавливает перевод в нужное поле записи
func
(
i
*
Item
)
SetData
(
dt
map
[
string
]
interface
{},
localeID
string
)
{
if
localeID
==
""
||
localeID
==
locales
.
DefaultID
{
...
...
This diff is collapsed.
Click to expand it.
pkg/items/item_test.go
+
240
−
0
View file @
9b0d4c3a
...
...
@@ -506,3 +506,243 @@ func Test_mergeItemData(t *testing.T) {
})
}
}
func
TestToMap
(
t
*
testing
.
T
)
{
sch
:=
schema
.
New
(
"str"
,
field
.
String
(),
"num"
,
field
.
Number
(
field
.
NumberFormatFloat
),
"embedded"
,
field
.
Object
(
"now"
,
field
.
Time
(),
),
"timestamp"
,
field
.
Timestamp
(),
)
tests
:=
[]
struct
{
name
string
input
*
Item
sch
*
schema
.
Schema
want
map
[
string
]
any
assertErr
assert
.
ErrorAssertionFunc
}{
{
name
:
"nil item"
,
input
:
nil
,
sch
:
nil
,
want
:
nil
,
assertErr
:
assert
.
Error
,
},
{
name
:
"nil schema"
,
input
:
&
Item
{},
sch
:
nil
,
want
:
nil
,
assertErr
:
assert
.
Error
,
},
{
name
:
"simple"
,
input
:
&
Item
{
ID
:
"item_id"
,
SpaceID
:
"space_id"
,
EnvID
:
"env_id"
,
CollectionID
:
"coll_id"
,
State
:
StatePublished
,
CreatedRevAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
CreatedBy
:
"created_by"
,
CreatedAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
UpdatedAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
UpdatedBy
:
"updated_by"
,
Data
:
map
[
string
]
any
{
"str"
:
"string"
,
"num"
:
2.7
,
"embedded"
:
map
[
string
]
any
{
"now"
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
},
"timestamp"
:
1723420800
,
},
LocaleID
:
"locale_id"
,
Translations
:
map
[
string
]
map
[
string
]
any
{
"ru"
:
{
"str"
:
"строка"
,
"num"
:
3.14
,
},
},
TranslationsIDs
:
[]
string
{
"ru"
},
RevisionID
:
"rev_id"
,
RevisionDescription
:
"rev_desc"
,
Permissions
:
&
Permissions
{
Edit
:
true
,
Archive
:
false
,
Publish
:
true
,
SoftDelete
:
false
,
HardDelete
:
false
,
},
SearchScore
:
123.0
,
Deleted
:
false
,
Hidden
:
true
,
Template
:
true
,
},
sch
:
sch
,
want
:
map
[
string
]
any
{
"id"
:
"item_id"
,
"spaceId"
:
"space_id"
,
"envId"
:
"env_id"
,
"collectionId"
:
"coll_id"
,
"state"
:
StatePublished
,
"createdRevAt"
:
"2024-08-12T00:00:00Z"
,
"createdBy"
:
"created_by"
,
"createdAt"
:
"2024-08-12T00:00:00Z"
,
"updatedAt"
:
"2024-08-12T00:00:00Z"
,
"updatedBy"
:
"updated_by"
,
"data"
:
map
[
string
]
any
{
"str"
:
"string"
,
"num"
:
2.7
,
"embedded"
:
map
[
string
]
any
{
"now"
:
"2024-08-12T00:00:00Z"
,
},
"timestamp"
:
int64
(
1723420800
),
},
"localeId"
:
"locale_id"
,
"translations"
:
map
[
string
]
map
[
string
]
any
{
"ru"
:
{
"str"
:
"строка"
,
"num"
:
3.14
,
},
},
"translationsIds"
:
[]
string
{
"ru"
},
"revId"
:
"rev_id"
,
"revDescription"
:
"rev_desc"
,
"hidden"
:
true
,
"template"
:
true
,
},
assertErr
:
assert
.
NoError
,
},
}
for
_
,
tc
:=
range
tests
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
ToMap
(
tc
.
input
,
tc
.
sch
)
tc
.
assertErr
(
t
,
err
)
assert
.
Equal
(
t
,
tc
.
want
,
got
)
})
}
}
func
TestFromMap
(
t
*
testing
.
T
)
{
sch
:=
schema
.
New
(
"str"
,
field
.
String
(),
"num"
,
field
.
Number
(
field
.
NumberFormatFloat
),
"embedded"
,
field
.
Object
(
"now"
,
field
.
Time
(),
),
"timestamp"
,
field
.
Timestamp
(),
)
tests
:=
[]
struct
{
name
string
input
map
[
string
]
any
want
*
Item
sch
*
schema
.
Schema
assertErr
assert
.
ErrorAssertionFunc
}{
{
name
:
"nil item"
,
input
:
nil
,
sch
:
nil
,
want
:
nil
,
assertErr
:
assert
.
Error
,
},
{
name
:
"empty item"
,
input
:
map
[
string
]
any
{},
sch
:
nil
,
want
:
nil
,
assertErr
:
assert
.
Error
,
},
{
name
:
"nil schema"
,
input
:
map
[
string
]
any
{},
sch
:
nil
,
assertErr
:
assert
.
Error
,
},
{
name
:
"simple"
,
input
:
map
[
string
]
any
{
"id"
:
"item_id"
,
"spaceId"
:
"space_id"
,
"envId"
:
"env_id"
,
"collectionId"
:
"coll_id"
,
"state"
:
StatePublished
,
"createdRevAt"
:
"2024-08-12T00:00:00Z"
,
"createdBy"
:
"created_by"
,
"createdAt"
:
"2024-08-12T00:00:00Z"
,
"updatedAt"
:
"2024-08-12T00:00:00Z"
,
"updatedBy"
:
"updated_by"
,
"data"
:
map
[
string
]
any
{
"str"
:
"string"
,
"num"
:
2.7
,
"embedded"
:
map
[
string
]
any
{
"now"
:
"2024-08-12T00:00:00Z"
,
},
"timestamp"
:
1723420800
,
},
"localeId"
:
"locale_id"
,
"translations"
:
map
[
string
]
map
[
string
]
any
{
"ru"
:
{
"str"
:
"строка"
,
"num"
:
3.14
,
},
},
"translationsIds"
:
[]
string
{
"ru"
},
"revId"
:
"rev_id"
,
"revDescription"
:
"rev_desc"
,
"deleted"
:
false
,
"hidden"
:
true
,
"template"
:
true
,
},
sch
:
sch
,
want
:
&
Item
{
ID
:
"item_id"
,
SpaceID
:
"space_id"
,
EnvID
:
"env_id"
,
CollectionID
:
"coll_id"
,
State
:
StatePublished
,
CreatedRevAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
CreatedBy
:
"created_by"
,
CreatedAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
UpdatedAt
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
UpdatedBy
:
"updated_by"
,
Data
:
map
[
string
]
any
{
"str"
:
"string"
,
"num"
:
2.7
,
"embedded"
:
map
[
string
]
any
{
"now"
:
time
.
Date
(
2024
,
time
.
August
,
12
,
00
,
0
,
0
,
0
,
time
.
UTC
),
},
"timestamp"
:
int64
(
1723420800
),
},
LocaleID
:
"locale_id"
,
Translations
:
map
[
string
]
map
[
string
]
any
{
"ru"
:
{
"str"
:
"строка"
,
"num"
:
3.14
,
},
},
TranslationsIDs
:
[]
string
{
"ru"
},
RevisionID
:
"rev_id"
,
RevisionDescription
:
"rev_desc"
,
Permissions
:
nil
,
SearchScore
:
0.0
,
Deleted
:
false
,
Hidden
:
true
,
Template
:
true
,
},
assertErr
:
assert
.
NoError
,
},
}
for
_
,
tc
:=
range
tests
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
got
,
err
:=
FromMap
(
tc
.
input
,
sch
)
tc
.
assertErr
(
t
,
err
)
assert
.
Equal
(
t
,
tc
.
want
,
got
)
})
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment