FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
adminforth/adminforth/modules/recordId.ts at next · devforth/adminforth · GitHub
devforth
adminforth
Repository navigation
Code
Issues
16
(16)
Pull requests
4
(4)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
adminforth
/
adminforth
/
modules
/
recordId.ts
Copy path
More file actions
More file actions
Latest commit
History
History
History
118 lines (108 loc) · 4.59 KB
Breadcrumbs
adminforth
/
adminforth
/
modules
/
recordId.ts
Copy path
File metadata and controls
118 lines (108 loc) · 4.59 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import
type
{
AdminForthResource
,
AdminForthResourceColumn
}
from
'../types/Back.js'
;
/**
* Separator used to glue values of composite primary key columns into one record id string.
* Values are URI-encoded before gluing, and '~' inside of value is escaped to '%7E',
* so separator can't appear in encoded parts.
*/
export
const
COMPOSITE_RECORD_ID_SEPARATOR
=
'~'
;
/**
* Returns all columns marked with primaryKey: true, in order in which they are defined in resource.
* For resources with composite primary key returns more than one column.
*/
export
function
primaryKeyColumns
(
resource
:
AdminForthResource
)
:
AdminForthResourceColumn
[
]
{
const
columns
=
(
resource
.
dataSourceColumns
?.
length
?
resource
.
dataSourceColumns
:
resource
.
columns
)
||
[
]
;
return
columns
.
filter
(
(
col
)
=>
col
.
primaryKey
)
;
}
export
function
primaryKeyColumnNames
(
resource
:
AdminForthResource
)
:
string
[
]
{
return
primaryKeyColumns
(
resource
)
.
map
(
(
col
)
=>
col
.
name
)
;
}
export
function
isCompositePrimaryKey
(
resource
:
AdminForthResource
)
:
boolean
{
return
primaryKeyColumns
(
resource
)
.
length
>
1
;
}
function
escapeRecordIdPart
(
value
:
any
)
:
string
{
// encodeURIComponent does not escape '~' (it is unreserved), so escape it manually
return
encodeURIComponent
(
String
(
value
)
)
.
replace
(
/
~
/
g
,
'%7E'
)
;
}
function
unescapeRecordIdPart
(
part
:
string
)
:
string
{
return
decodeURIComponent
(
part
)
;
}
/**
* Foreign resource columns are returned to frontend as { pk, label } objects,
* so unwrap them when record id is built from such record
*/
function
unwrapPrimaryKeyValue
(
value
:
any
)
:
any
{
if
(
value
!==
null
&&
typeof
value
===
'object'
&&
'pk'
in
value
)
{
return
(
value
as
any
)
.
pk
;
}
return
value
;
}
/**
* Builds record id (value used in urls and in all AdminForth APIs) from record object.
*
* For resource with single primary key column returns raw value of that column (no encoding is done,
* so behavior is fully backward compatible).
*
* For resource with composite primary key returns string like 'BTC~ERC20' where each part is
* URI-encoded value of corresponding primary key column, in order of definition in resource.
*/
export
function
encodeRecordId
(
resource
:
AdminForthResource
,
record
:
any
)
:
any
{
const
pkColumns
=
primaryKeyColumns
(
resource
)
;
if
(
!
pkColumns
.
length
)
{
throw
new
Error
(
`Resource '
${
resource
.
resourceId
}
' has no primaryKey column`
)
;
}
if
(
pkColumns
.
length
===
1
)
{
return
unwrapPrimaryKeyValue
(
record
?.
[
pkColumns
[
0
]
.
name
]
)
;
}
return
pkColumns
.
map
(
(
col
)
=>
{
const
value
=
unwrapPrimaryKeyValue
(
record
?.
[
col
.
name
]
)
;
if
(
value
===
undefined
||
value
===
null
)
{
throw
new
Error
(
`Can't build record id for resource '
${
resource
.
resourceId
}
': primary key column '
${
col
.
name
}
' has no value in record`
)
;
}
return
escapeRecordIdPart
(
value
)
;
}
)
.
join
(
COMPOSITE_RECORD_ID_SEPARATOR
)
;
}
/**
* Splits record id back into values of primary key columns.
* Returns object like { assetSymbol: 'BTC', networkCode: 'ERC20' }.
*
* Values are returned as strings for composite keys (they come from url/API),
* connectors cast them to column types using setFieldValue.
*/
export
function
decodeRecordId
(
resource
:
AdminForthResource
,
recordId
:
any
)
:
Record
<
string
,
any
>
{
const
pkColumns
=
primaryKeyColumns
(
resource
)
;
if
(
!
pkColumns
.
length
)
{
throw
new
Error
(
`Resource '
${
resource
.
resourceId
}
' has no primaryKey column`
)
;
}
if
(
pkColumns
.
length
===
1
)
{
return
{
[
pkColumns
[
0
]
.
name
]
:
recordId
}
;
}
const
parts
=
String
(
recordId
)
.
split
(
COMPOSITE_RECORD_ID_SEPARATOR
)
;
if
(
parts
.
length
!==
pkColumns
.
length
)
{
throw
new
Error
(
`Record id '
${
recordId
}
' is not valid for resource '
${
resource
.
resourceId
}
': expected
${
pkColumns
.
length
}
`
+
`parts (
${
pkColumns
.
map
(
(
col
)
=>
col
.
name
)
.
join
(
', '
)
}
) separated by '
${
COMPOSITE_RECORD_ID_SEPARATOR
}
', got
${
parts
.
length
}
`
)
;
}
return
pkColumns
.
reduce
(
(
acc
,
col
,
i
)
=>
{
acc
[
col
.
name
]
=
unescapeRecordIdPart
(
parts
[
i
]
)
;
return
acc
;
}
,
{
}
as
Record
<
string
,
any
>
)
;
}
/**
* Returns pkValues argument for connector's updateRecordOriginalValues/deleteRecord.
*
* Returns undefined for resources with single primary key, so connectors receive exactly the same
* arguments as before composite primary key support was added (pure extension, old path untouched).
*/
export
function
compositePkValues
(
connector
:
{
getPrimaryKeyValues
?:
(
resource
:
AdminForthResource
,
recordId
:
any
)
=>
Record
<
string
,
any
>
}
,
resource
:
AdminForthResource
,
recordId
:
any
,
)
:
Record
<
string
,
any
>
|
undefined
{
if
(
!
isCompositePrimaryKey
(
resource
)
)
{
return
undefined
;
}
return
connector
.
getPrimaryKeyValues
?.
(
resource
,
recordId
)
;
}
Back
|
FazBrowse Home
|
New Git URL