Skip to content

Commit 798ec60

Browse files
fix: large array serialization (#439)
1 parent 7ff6555 commit 798ec60

File tree

3 files changed

+328
-54
lines changed

3 files changed

+328
-54
lines changed

index.js

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,13 @@ const stringSerializerMap = {
409409
time: 'serializer.asTime.bind(serializer)'
410410
}
411411

412-
function getStringSerializer (format) {
413-
return stringSerializerMap[format] ||
414-
'serializer.asString.bind(serializer)'
412+
function getStringSerializer (format, nullable) {
413+
switch (format) {
414+
case 'date-time': return nullable ? 'serializer.asDatetimeNullable.bind(serializer)' : 'serializer.asDatetime.bind(serializer)'
415+
case 'date': return nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
416+
case 'time': return nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
417+
default: return nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
418+
}
415419
}
416420

417421
function getTestSerializer (format) {
@@ -1025,43 +1029,30 @@ function buildArray (location, code, name, key = null) {
10251029
`
10261030
}
10271031

1028-
code += `
1029-
var l = obj.length
1030-
if (l && l >= ${largeArraySize}) {`
1031-
1032-
const concatSnippet = `
1032+
code += 'const arrayLength = obj.length\n'
1033+
if (largeArrayMechanism !== 'default') {
1034+
if (largeArrayMechanism === 'json-stringify') {
1035+
code += `if (arrayLength && arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
1036+
} else {
1037+
throw new Error(`Unsupported large array mechanism ${largeArrayMechanism}`)
10331038
}
1039+
}
10341040

1035-
var jsonOutput= ''
1036-
for (var i = 0; i < l; i++) {
1037-
var json = ''
1041+
code += `
1042+
let jsonOutput= ''
1043+
for (let i = 0; i < arrayLength; i++) {
1044+
let json = ''
10381045
${result.code}
10391046
jsonOutput += json
10401047
1041-
if (json.length > 0 && i < l - 1) {
1048+
if (json.length > 0 && i < arrayLength - 1) {
10421049
jsonOutput += ','
10431050
}
10441051
}
10451052
return \`[\${jsonOutput}]\`
10461053
}`
10471054

1048-
switch (largeArrayMechanism) {
1049-
case 'default':
1050-
code += `
1051-
return \`[\${obj.map(${result.mapFnName}).join(',')}]\``
1052-
break
1053-
1054-
case 'json-stringify':
1055-
code += `
1056-
return JSON.stringify(obj)`
1057-
break
1058-
1059-
default:
1060-
throw new Error(`Unsupported large array mechanism ${largeArrayMechanism}`)
1061-
}
1062-
10631055
code += `
1064-
${concatSnippet}
10651056
${result.laterCode}
10661057
`
10671058

@@ -1144,9 +1135,6 @@ function asFuncName (str) {
11441135
}
11451136

11461137
function nested (laterCode, name, key, location, subKey, isArray) {
1147-
let code = ''
1148-
let funcName
1149-
11501138
subKey = subKey || ''
11511139

11521140
let schema = location.schema
@@ -1167,47 +1155,44 @@ function nested (laterCode, name, key, location, subKey, isArray) {
11671155

11681156
const accessor = isArray ? key : `[${JSON.stringify(key)}]`
11691157

1158+
let code = ''
1159+
let funcName
1160+
11701161
switch (type) {
11711162
case 'null':
1172-
funcName = '$asNull'
11731163
code += `
11741164
json += serializer.asNull()
11751165
`
11761166
break
11771167
case 'string': {
1178-
funcName = '$asString'
1179-
const stringSerializer = getStringSerializer(schema.format)
1180-
code += nullable ? `json += obj${accessor} === null ? null : ${stringSerializer}(obj${accessor})` : `json += ${stringSerializer}(obj${accessor})`
1168+
funcName = getStringSerializer(schema.format, nullable)
1169+
code += `json += ${funcName}(obj${accessor})`
11811170
break
11821171
}
11831172
case 'integer':
1184-
funcName = '$asInteger'
1185-
code += nullable ? `json += obj${accessor} === null ? null : serializer.asInteger(obj${accessor})` : `json += serializer.asInteger(obj${accessor})`
1173+
funcName = nullable ? 'serializer.asIntegerNullable.bind(serializer)' : 'serializer.asInteger.bind(serializer)'
1174+
code += `json += ${funcName}(obj${accessor})`
11861175
break
11871176
case 'number':
1188-
funcName = '$asNumber'
1189-
code += nullable ? `json += obj${accessor} === null ? null : serializer.asNumber(obj${accessor})` : `json += serializer.asNumber(obj${accessor})`
1177+
funcName = nullable ? 'serializer.asNumberNullable.bind(serializer)' : 'serializer.asNumber.bind(serializer)'
1178+
code += `json += ${funcName}(obj${accessor})`
11901179
break
11911180
case 'boolean':
1192-
funcName = '$asBoolean'
1193-
code += nullable ? `json += obj${accessor} === null ? null : serializer.asBoolean(obj${accessor})` : `json += serializer.asBoolean(obj${accessor})`
1181+
funcName = nullable ? 'serializer.asBooleanNullable.bind(serializer)' : 'serializer.asBoolean.bind(serializer)'
1182+
code += `json += ${funcName}(obj${accessor})`
11941183
break
11951184
case 'object':
11961185
funcName = asFuncName(name + key + subKey)
11971186
laterCode = buildObject(location, laterCode, funcName)
1198-
code += `
1199-
json += ${funcName}(obj${accessor})
1200-
`
1187+
code += `json += ${funcName}(obj${accessor})`
12011188
break
12021189
case 'array':
12031190
funcName = asFuncName('$arr' + name + key + subKey) // eslint-disable-line
12041191
laterCode = buildArray(location, laterCode, funcName, key)
1205-
code += `
1206-
json += ${funcName}(obj${accessor})
1207-
`
1192+
code += `json += ${funcName}(obj${accessor})`
12081193
break
12091194
case undefined:
1210-
funcName = '$asNull'
1195+
funcName = 'serializer.asNull.bind(serializer)'
12111196
if ('anyOf' in schema) {
12121197
// beware: dereferenceOfRefs has side effects and changes schema.anyOf
12131198
const anyOfLocations = dereferenceOfRefs(location, 'anyOf')
@@ -1344,11 +1329,7 @@ function nested (laterCode, name, key, location, subKey, isArray) {
13441329
}
13451330
}
13461331

1347-
return {
1348-
code,
1349-
laterCode,
1350-
mapFnName: funcName
1351-
}
1332+
return { code, laterCode }
13521333
}
13531334

13541335
function isEmpty (schema) {

test/array.test.js

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ buildTest({
344344
})
345345

346346
buildTest({
347-
title: 'large array with json-stringify mechanism',
347+
title: 'large array of objects with json-stringify mechanism',
348348
type: 'object',
349349
properties: {
350350
ids: {
@@ -363,3 +363,83 @@ buildTest({
363363
}, {
364364
largeArrayMechanism: 'json-stringify'
365365
})
366+
367+
buildTest({
368+
title: 'large array of strings with default mechanism',
369+
type: 'object',
370+
properties: {
371+
ids: {
372+
type: 'array',
373+
items: { type: 'string' }
374+
}
375+
}
376+
}, {
377+
ids: new Array(2e4).fill('string')
378+
}, {
379+
largeArraySize: 2e4,
380+
largeArrayMechanism: 'default'
381+
})
382+
383+
buildTest({
384+
title: 'large array of numbers with default mechanism',
385+
type: 'object',
386+
properties: {
387+
ids: {
388+
type: 'array',
389+
items: { type: 'number' }
390+
}
391+
}
392+
}, {
393+
ids: new Array(2e4).fill(42)
394+
}, {
395+
largeArraySize: 2e4,
396+
largeArrayMechanism: 'default'
397+
})
398+
399+
buildTest({
400+
title: 'large array of integers with default mechanism',
401+
type: 'object',
402+
properties: {
403+
ids: {
404+
type: 'array',
405+
items: { type: 'integer' }
406+
}
407+
}
408+
}, {
409+
ids: new Array(2e4).fill(42)
410+
}, {
411+
largeArraySize: 2e4,
412+
largeArrayMechanism: 'default'
413+
})
414+
415+
buildTest({
416+
title: 'large array of booleans with default mechanism',
417+
type: 'object',
418+
properties: {
419+
ids: {
420+
type: 'array',
421+
items: { type: 'boolean' }
422+
}
423+
}
424+
}, {
425+
ids: new Array(2e4).fill(true)
426+
}, {
427+
largeArraySize: 2e4,
428+
largeArrayMechanism: 'default'
429+
})
430+
431+
buildTest({
432+
title: 'large array of null values with default mechanism',
433+
type: 'object',
434+
properties: {
435+
ids: {
436+
type: 'array',
437+
items: { type: 'null' }
438+
}
439+
}
440+
}, {
441+
ids: new Array(2e4).fill(null)
442+
}, {
443+
largeArraySize: 2e4,
444+
largeArrayMechanism: 'default'
445+
})

0 commit comments

Comments
 (0)