Skip to content

Commit

Permalink
Merge branch 'skip_undefined' into star_schema
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Pollak committed Sep 18, 2019
2 parents 7a80a82 + c93c329 commit 2ebdacd
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 11 deletions.
40 changes: 34 additions & 6 deletions lib/es/serializr.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ function serializeWithSchema(schema, obj) {
if (propDef === false)
return
var jsonValue = propDef.serializer(obj[key], key, obj);
console.warn({schema, obj, key, value: obj[key], jsonValue});
if (jsonValue === SKIP){
return
}
Expand Down Expand Up @@ -1084,6 +1085,38 @@ function object(modelSchema, additionalArgs) {
return result
}

/**
* Optional indicates that this model property shouldn't be serialized if it isn't present.
*
* @example
* createModelSchema(Todo, {
* title: optional(primitive()),
* });
*
* console.dir(serialize(new Todo()));
* // {}
*
* @param {PropSchema} propSchema propSchema to (de)serialize the contents of this field
* @returns {PropSchema}
*/
function optional(name, propSchema) {
propSchema = (!propSchema || propSchema === true) ? _defaultPrimitiveProp : propSchema;
invariant(isPropSchema(propSchema), "expected prop schema as second argument");
const propSerializer = propSchema.serializer;
invariant(typeof propSerializer === "function", "expected prop schema to have a callable serializer");
function serializer(...args) {
const result = propSerializer(...args);
if (result === undefined) {
return SKIP
}
return result
}
return {
...propSchema,
serializer,
}
}

function createDefaultRefLookup(modelSchema) {
return function resolve(uuid, cb, context) {
context.rootContext.await(modelSchema, uuid, cb);
Expand Down Expand Up @@ -1434,9 +1467,4 @@ function raw(additionalArgs) {
return result
}

/*
* ## Managing model schemas
*/
// ~ deprecated

export { SKIP, alias, cancelDeserialize, object as child, createModelSchema, createSimpleSchema, custom, date, deserialize, getDefaultModelSchema, identifier, list, map, mapAsArray, object, primitive, raw, reference as ref, reference, serializable, serialize, serializeAll, setDefaultModelSchema, update };
export { SKIP, alias, cancelDeserialize, object as child, createModelSchema, createSimpleSchema, custom, date, deserialize, getDefaultModelSchema, identifier, list, map, mapAsArray, object, optional, primitive, raw, reference as ref, reference, serializable, serialize, serializeAll, setDefaultModelSchema, update };
39 changes: 34 additions & 5 deletions lib/serializr.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@
if (propDef === false)
return
var jsonValue = propDef.serializer(obj[key], key, obj);
console.warn({schema, obj, key, value: obj[key], jsonValue});
if (jsonValue === SKIP){
return
}
Expand Down Expand Up @@ -1091,6 +1092,38 @@
return result
}

/**
* Optional indicates that this model property shouldn't be serialized if it isn't present.
*
* @example
* createModelSchema(Todo, {
* title: optional(primitive()),
* });
*
* console.dir(serialize(new Todo()));
* // {}
*
* @param {PropSchema} propSchema propSchema to (de)serialize the contents of this field
* @returns {PropSchema}
*/
function optional(name, propSchema) {
propSchema = (!propSchema || propSchema === true) ? _defaultPrimitiveProp : propSchema;
invariant(isPropSchema(propSchema), "expected prop schema as second argument");
const propSerializer = propSchema.serializer;
invariant(typeof propSerializer === "function", "expected prop schema to have a callable serializer");
function serializer(...args) {
const result = propSerializer(...args);
if (result === undefined) {
return SKIP
}
return result
}
return {
...propSchema,
serializer,
}
}

function createDefaultRefLookup(modelSchema) {
return function resolve(uuid, cb, context) {
context.rootContext.await(modelSchema, uuid, cb);
Expand Down Expand Up @@ -1441,11 +1474,6 @@
return result
}

/*
* ## Managing model schemas
*/
// ~ deprecated

exports.SKIP = SKIP;
exports.alias = alias;
exports.cancelDeserialize = cancelDeserialize;
Expand All @@ -1461,6 +1489,7 @@
exports.map = map;
exports.mapAsArray = mapAsArray;
exports.object = object;
exports.optional = optional;
exports.primitive = primitive;
exports.raw = raw;
exports.ref = reference;
Expand Down
1 change: 1 addition & 0 deletions serializr.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function identifier(additionalArgs: AdditionalPropArgs): PropSchema;
export function date(additionalArgs?: AdditionalPropArgs): PropSchema;

export function alias(jsonName: string, propSchema?: PropSchema | boolean): PropSchema;
export function optional(propSchema?: PropSchema | boolean): PropSchema;

export function child(modelschema: ClazzOrModelSchema<any>, additionalArgs?: AdditionalPropArgs): PropSchema;
export function object(modelschema: ClazzOrModelSchema<any>, additionalArgs?: AdditionalPropArgs): PropSchema;
Expand Down
1 change: 1 addition & 0 deletions src/core/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function serializeWithSchema(schema, obj) {
if (propDef === false)
return
var jsonValue = propDef.serializer(obj[key], key, obj)
console.warn({schema, obj, key, value: obj[key], jsonValue})
if (jsonValue === SKIP){
return
}
Expand Down
1 change: 1 addition & 0 deletions src/serializr.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export { default as date } from "./types/date"
export { default as alias } from "./types/alias"
export { default as custom } from "./types/custom"
export { default as object } from "./types/object"
export { default as optional } from "./types/optional"
export { default as reference } from "./types/reference"
export { default as list } from "./types/list"
export { default as map } from "./types/map"
Expand Down
34 changes: 34 additions & 0 deletions src/types/optional.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { invariant, isPropSchema } from "../utils/utils"
import { _defaultPrimitiveProp, SKIP } from "../constants"

/**
* Optional indicates that this model property shouldn't be serialized if it isn't present.
*
* @example
* createModelSchema(Todo, {
* title: optional(primitive()),
* });
*
* console.dir(serialize(new Todo()));
* // {}
*
* @param {PropSchema} propSchema propSchema to (de)serialize the contents of this field
* @returns {PropSchema}
*/
export default function optional(name, propSchema) {
propSchema = (!propSchema || propSchema === true) ? _defaultPrimitiveProp : propSchema
invariant(isPropSchema(propSchema), "expected prop schema as second argument")
const propSerializer = propSchema.serializer
invariant(typeof propSerializer === "function", "expected prop schema to have a callable serializer")
function serializer(...args) {
const result = propSerializer(...args)
if (result === undefined) {
return SKIP
}
return result
}
return {
...propSchema,
serializer,
}
}
57 changes: 57 additions & 0 deletions test/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var test = require("tape")
var _ = require("..")
var serialize = _.serialize
var deserialize = _.deserialize
var optional = _.optional
var primitive = _.primitive
var update = _.update

Expand Down Expand Up @@ -38,6 +39,31 @@ test("it should serialize simple object", t1 => {
t.end()
})

test("it should (de)serialize all fields in the schema even if they're not defined on the object (existing behavior)", t => {
var a = { y: 1337 }
var s = serialize(schema, a)

t.deepEqual(s, { x: undefined })
t.deepEqual(deserialize(schema, s), {})

var d = { x: 1 }
update(schema, a, d)
t.deepEqual(a, {
y: 1337, x: 1
})

test("it should skip missing attrs", t3 => {
update(schema, a, {}, (err, res) => {
t3.ok(res === a)
t3.notOk(err)
t3.equal(res.x, 1)
t3.end()
})
})

t.end()
})

test("it should (de)serialize arrays", t => {
var data = [ { x: 1 }, { x: 2}]

Expand Down Expand Up @@ -171,6 +197,37 @@ test("it should not set values for custom serializers/deserializer that return S
t.end()
})

test("it should not serialize values for optional properties", t => {
var schema = {
factory: () => ({}),
props: {
x: optional(primitive())
}
}
var a = { y: 1337 }
var s = serialize(schema, a)

t.deepEqual(s, {})
t.deepEqual(deserialize(schema, s), {})

var d = { x: 1 }
update(schema, a, d)
t.deepEqual(a, {
y: 1337, x: 1
})

test("it should skip missing attrs", t3 => {
update(schema, a, {}, (err, res) => {
t3.ok(res === a)
t3.notOk(err)
t3.equal(res.x, 1)
t3.end()
})
})

t.end()
})

test("it should pass key and object to custom schemas", t => {
var s = _.createSimpleSchema({
a: primitive(),
Expand Down
11 changes: 11 additions & 0 deletions test/typescript/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
map,
mapAsArray,
object,
optional,
identifier,
reference,
primitive,
Expand Down Expand Up @@ -74,6 +75,9 @@ test("typescript class with constructor params", t => {
@serializable(alias("identifier", identifier()))
public id: string;

@serializable(alias("desc", optional()))
public description?: string;

@serializable(alias("width", true))
public width: number

Expand All @@ -95,13 +99,20 @@ test("typescript class with constructor params", t => {
a.someNumber = 123;

let json = serialize(a);
t.equal(false, json.hasOwnProperty("desc"));
t.equal(false, json.hasOwnProperty("description"));
const b = deserialize(Rectangle, json);
t.equal(a.id, b.id);
t.equal(a.width, b.width);
t.equal(a.height, b.height);
t.equal(a.someNumber, b.someNumber);
t.equal(b.getArea(), 200);

a.description = "example";
json = serialize(a);
t.equal("example", json["desc"]);
t.equal(false, json.hasOwnProperty("description"));

t.end();
});

Expand Down

0 comments on commit 2ebdacd

Please sign in to comment.