@@ -4,17 +4,27 @@ import { error } from '../error'
44 * Checks if data is valid for serialisation
55 *
66 * @param {Object } obj The data
7- * @param {string } method Request type
7+ * @param {string } method Request type - `PATCH` or `POST`
88 * @private
99 */
10- function isValid ( obj , method , type ) {
11- // Check if obj is not an object or empty
12- if ( obj . constructor !== Object || Object . keys ( obj ) . length === 0 ) {
13- throw new Error ( `${ method } requires a JSON object body` )
14- }
15- // A POST request is the only request to not require an ID
16- if ( method !== 'POST' && ! obj . id ) {
17- throw new Error ( `${ method } requires an ID for the ${ type } type` )
10+ function isValid ( isArray , type , payload , method ) {
11+ const requireID = new Error ( `${ method } requires an ID for the ${ type } type` )
12+
13+ if ( isArray ) {
14+ // A POST request is the only request to not require an ID in spec
15+ if ( method !== 'POST' && payload . length > 0 ) {
16+ for ( const resource of payload ) {
17+ if ( ! resource . id ) throw requireID
18+ }
19+ }
20+ } else {
21+ if ( payload . constructor !== Object || Object . keys ( payload ) . length === 0 ) {
22+ throw new Error ( `${ method } requires a JSON object body` )
23+ }
24+ // A POST request is the only request to not require an ID in spec
25+ if ( method !== 'POST' && ! payload . id ) {
26+ throw requireID
27+ }
1828 }
1929}
2030
@@ -86,11 +96,44 @@ function hasID (node) {
8696 return Object . prototype . hasOwnProperty . call ( node , 'id' )
8797}
8898
99+ function serialiseRootArray ( type , payload , method , options ) {
100+ isValid ( true , type , payload , method )
101+ const data = [ ]
102+ for ( const resource of payload ) {
103+ data . push ( serialiseRootObject ( type , resource , method , options ) . data )
104+ }
105+ return { data }
106+ }
107+
108+ function serialiseRootObject ( type , payload , method , options ) {
109+ isValid ( false , type , payload , method )
110+ let data = { type }
111+
112+ if ( payload ?. id ) data . id = String ( payload . id )
113+
114+ for ( const key in payload ) {
115+ const node = payload [ key ]
116+ const nodeType = options . pluralTypes ( options . camelCaseTypes ( key ) )
117+ // 1. Skip null nodes, 2. Only grab objects, 3. Filter to only serialise relationable objects
118+ if ( node !== null && node . constructor === Object && hasID ( node ) ) {
119+ data = serialiseObject ( node , nodeType , key , data , method )
120+ // 1. Skip null nodes, 2. Only grab arrays, 3. Filter to only serialise relationable arrays
121+ } else if ( node !== null && Array . isArray ( node ) && ( node . length > 0 && hasID ( node [ 0 ] ) ) ) {
122+ data = serialiseArray ( node , nodeType , key , data , method )
123+ // 1. Don't place id/key inside attributes object
124+ } else if ( key !== 'id' && key !== 'type' ) {
125+ data = serialiseAttr ( node , key , data )
126+ }
127+ }
128+
129+ return { data }
130+ }
131+
89132/**
90133 * Serialises an object into a JSON-API structure
91134 *
92135 * @param {string } model Request model
93- * @param {Object } obj The data
136+ * @param {Object|Array } data The data
94137 * @param {string } method Request type (PATCH, POST, DELETE)
95138 * @param {Object } options Optional configuration for camelCase and pluralisation handling
96139 * @param {Function } options.camelCaseTypes Convert library-entries and library_entries to libraryEntries (default no conversion). To use parameter, import camel from kitsu-core
@@ -116,36 +159,17 @@ function hasID (node) {
116159 * // { data: { id: '1', type: 'anime', attributes: { slug: 'shirobako' } } }
117160 * const output = serialise(model, obj, 'PATCH')
118161 */
119- export function serialise ( model , obj = { } , method = 'POST' , options = { } ) {
162+ export function serialise ( model , data = { } , method = 'POST' , options = { } ) {
120163 try {
121164 if ( ! options . camelCaseTypes ) options . camelCaseTypes = s => s
122165 if ( ! options . pluralTypes ) options . pluralTypes = s => s
123166 // Delete relationship to-one (data: null) or to-many (data: [])
124- if ( obj === null || ( Array . isArray ( obj ) && obj . length === 0 ) ) return { data : obj }
167+ if ( data === null || ( Array . isArray ( data ) && data . length === 0 ) ) return { data }
125168
126169 const type = options . pluralTypes ( options . camelCaseTypes ( model ) )
127- let data = { type }
128-
129- isValid ( obj , method , type )
130-
131- if ( obj . id ) data . id = String ( obj . id )
132-
133- for ( const key in obj ) {
134- const node = obj [ key ]
135- const nodeType = options . pluralTypes ( options . camelCaseTypes ( key ) )
136- // 1. Skip null nodes, 2. Only grab objects, 3. Filter to only serialise relationable objects
137- if ( node !== null && node . constructor === Object && hasID ( node ) ) {
138- data = serialiseObject ( node , nodeType , key , data , method )
139- // 1. Skip null nodes, 2. Only grab arrays, 3. Filter to only serialise relationable arrays
140- } else if ( node !== null && Array . isArray ( node ) && ( node . length > 0 && hasID ( node [ 0 ] ) ) ) {
141- data = serialiseArray ( node , nodeType , key , data , method )
142- // 1. Don't place id/key inside attributes object
143- } else if ( key !== 'id' && key !== 'type' ) {
144- data = serialiseAttr ( node , key , data )
145- }
146- }
147170
148- return { data }
171+ if ( Array . isArray ( data ) && data ?. length > 0 ) return serialiseRootArray ( type , data , method , options )
172+ else return serialiseRootObject ( type , data , method , options )
149173 } catch ( E ) {
150174 throw error ( E )
151175 }
0 commit comments