From de6ba3e61506275da0957e74372da91227c5240e Mon Sep 17 00:00:00 2001 From: Shivam Kumar Jha Date: Fri, 26 Jul 2024 19:32:01 +0530 Subject: [PATCH 1/3] new option added: stripNull, which removes null in serialised output --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 862c7c83..6bc0c744 100644 --- a/index.js +++ b/index.js @@ -374,7 +374,7 @@ function buildInnerObject (context, location) { code += ` value = obj[${sanitizedKey}] - if (value !== undefined) { + if ${context.options.stripNull ? '(value != null)' : '(value !== undefined)'} { ${addComma} json += ${JSON.stringify(sanitizedKey + ':')} ${buildValue(context, propertyLocation, 'value')} From 5e01a5d8d7fed19c992739f351ba974fe46b0add Mon Sep 17 00:00:00 2001 From: Shivam Kumar Jha Date: Sat, 27 Jul 2024 09:56:53 +0530 Subject: [PATCH 2/3] tests added for strip null feature --- test/stripNull.test.js | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 test/stripNull.test.js diff --git a/test/stripNull.test.js b/test/stripNull.test.js new file mode 100644 index 00000000..c2eedea5 --- /dev/null +++ b/test/stripNull.test.js @@ -0,0 +1,110 @@ +const test = require('tap').test +const build = require('..') + +test('should handle null string values properly', (t) => { + t.plan(3) + + const schema = { + type: 'object', + properties: { + firstName: { type: 'string' }, + lastName: { type: 'string' } + }, + required: ['firstName'] + } + const stringify = build(schema, { stripNull: true }) + + const json1 = { firstName: 'Matteo', lastName: 'Collina' } + t.equal(stringify(json1), '{"firstName":"Matteo","lastName":"Collina"}') + + const json2 = { firstName: 'Matteo', lastName: null } + t.equal(stringify(json2), '{"firstName":"Matteo"}') + + const json3 = { firstName: null, lastName: 'Collina' } + t.throws(() => stringify(json3)) // throw error when required property is missing +}) + +test('should handle null int values properly', (t) => { + t.plan(3) + + const schema = { + type: 'object', + properties: { + name: { type: 'string' }, + age: { type: 'integer' }, + experience: { type: 'integer' } + } + } + const stringify = build(schema, { stripNull: true }) + + const json1 = { name: 'Matteo', age: 32, experience: 12 } + t.equal(stringify(json1), '{"name":"Matteo","age":32,"experience":12}') + + const json2 = { name: 'Matteo', age: null, experience: null } + t.equal(stringify(json2), '{"name":"Matteo"}') + + const json3 = { name: 'Matteo', age: 3, experience: null } + t.equal(stringify(json3), '{"name":"Matteo","age":3}') +}) + +test('should handle arrays properly', (t) => { + t.plan(1) + + const schema = { + type: 'object', + properties: { + name: { type: 'string' }, + experience: { + type: 'array', + items: { + type: 'object', + properties: { + company: { type: 'string' }, + years: { type: 'integer' } + } + } + } + } + } + const stringify = build(schema, { stripNull: true }) + + const json1 = { + name: 'Matteo', + experience: [ + { company: 'C1', years: 12 }, + { company: 'C2', years: null }, + { company: null, years: 6 }, + { company: null, years: null } + ] + } + + t.equal( + stringify(json1), + '{"name":"Matteo","experience":[{"company":"C1","years":12},{"company":"C2"},{"years":6},{}]}' + ) +}) + +test('should handle objects and nested objects properly', (t) => { + t.plan(2) + + const schema = { + type: 'object', + properties: { + name: { type: 'string' }, + address: { + type: 'object', + properties: { + city: { type: 'string' }, + country: { type: 'string' } + } + } + } + } + const stringify = build(schema, { stripNull: true }) + + const json1 = { name: 'Matteo', address: { city: 'Mumbai', country: null } } + t.equal(stringify(json1), '{"name":"Matteo","address":{"city":"Mumbai"}}') + + const json2 = { name: null, address: { city: null, country: 'India' } } + t.equal(stringify(json2), '{"address":{"country":"India"}}') +}) From 8dc2705501235dbd4305581db4fb10c252823975 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Jha Date: Sat, 27 Jul 2024 10:02:38 +0530 Subject: [PATCH 3/3] updated README and type info with strip null details --- README.md | 1 + types/index.d.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index f3a0d206..6a574472 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ const stringify = fastJson(mySchema, { - `rounding`: setup how the `integer` types will be rounded when not integers. [More details](#integer) - `largeArrayMechanism`: set the mechanism that should be used to handle large (by default `20000` or more items) arrays. [More details](#largearrays) +- `stripNull`: removes keys with null values from serialised output. If you have lots of null values, using this will result in smallerpayload and improved performance. diff --git a/types/index.d.ts b/types/index.d.ts index 5ded284d..6dab922f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -187,6 +187,13 @@ declare namespace build { * @default 'default' */ largeArrayMechanism?: 'default' | 'json-stringify' + + /** + * Specify if null key-value are removed from serialised JSON output, for a smaller payload + * + * @default 'false' + */ + stripNull?: boolean } export const validLargeArrayMechanisms: string[]