>;
194 |
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/spec/src/decorator_options.spec.ts:
--------------------------------------------------------------------------------
1 | import chai = require('chai');
2 |
3 | import { deflate, inflate, Serializable, Serialize } from 'serialazy';
4 |
5 | const { expect } = chai;
6 |
7 | describe('decorator options', () => {
8 |
9 | describe('"name" option', () => {
10 |
11 | describe('when option is empty/null/undefined (default)', () => {
12 |
13 | class Person extends Serializable {
14 | @Serialize({ name: undefined }) public name: string;
15 | @Serialize({ name: null }) public age: number;
16 | @Serialize({ name: '' }) public notes : string;
17 | }
18 |
19 | it('doesn\'t affect property name in resulting serialized object', () => {
20 | const person = Person.create({ name: 'Joe', age: 35, notes: 'None' });
21 | const serialized = deflate(person);
22 | expect(serialized).to.deep.equal({ name: 'Joe', age: 35, notes: 'None' });
23 | const deserialized = inflate(Person, serialized);
24 | expect(deserialized).to.deep.equal(person);
25 | });
26 |
27 | });
28 |
29 | describe('when option is a non-empty string', () => {
30 |
31 | class Person extends Serializable {
32 | @Serialize() public name: string;
33 | @Serialize({ name: 'years' }) public age: number;
34 | }
35 |
36 | it('overrides property name in resulting serialized object', () => {
37 | const person = Person.create({ name: 'John', age: 35 });
38 | const serialized = deflate(person);
39 | expect(serialized).to.deep.equal({ name: 'John', years: 35 });
40 | const deserialized = inflate(Person, serialized);
41 | expect(deserialized).to.deep.equal(person);
42 | });
43 |
44 | it('should be impossible to use the same name for multiple properties', () => {
45 | [
46 | () => {
47 | class Person {
48 | @Serialize() public age: number;
49 | @Serialize({ name: 'age' }) public years: number;
50 | }
51 | },
52 | () => {
53 | class Person {
54 | @Serialize({ name: 'age' }) public foo: number;
55 | @Serialize({ name: 'age' }) public bar: number;
56 | }
57 | }
58 | ].forEach(func => expect(func).to.throw('"age" tag already used'));
59 | });
60 |
61 | });
62 |
63 | });
64 |
65 | describe('"nullable" option', () => {
66 |
67 | describe('when value is null and option is false/undefined (default)', () => {
68 |
69 | class Pet extends Serializable {
70 | @Serialize() public name: string;
71 | }
72 |
73 | class Person extends Serializable {
74 | @Serialize() public age: number;
75 | @Serialize({ nullable: false }) public pet: Pet;
76 | }
77 |
78 | it('should fail to serialize', () => {
79 |
80 | const pet = Pet.create({ name: null });
81 | expect(
82 | () => deflate(pet)
83 | ).to.throw('Unable to serialize property "name": Value is null');
84 |
85 | const person = Person.create({ age: 35, pet: null });
86 | expect(
87 | () => deflate(person)
88 | ).to.throw('Unable to serialize property "pet": Value is null');
89 |
90 | });
91 |
92 | it('should fail to deserialize', () => {
93 |
94 | expect(
95 | () => inflate(Pet, { name: null })
96 | ).to.throw('Unable to deserialize property "name": Value is null');
97 |
98 | expect(
99 | () => inflate(Person, { age: 35, pet: null })
100 | ).to.throw('Unable to deserialize property "pet": Value is null');
101 |
102 | });
103 |
104 | });
105 |
106 | describe('when value is null and option is true', () => {
107 |
108 | class Pet extends Serializable {
109 | @Serialize({ nullable: true }) public name: string;
110 | }
111 |
112 | class Person extends Serializable {
113 | @Serialize({ nullable: true }) public age: number;
114 | @Serialize({ nullable: true }) public pet: Pet;
115 | }
116 |
117 | it('serializes to null', () => {
118 |
119 | const pet = Pet.create({ name: null });
120 | expect(
121 | deflate(pet)
122 | ).to.deep.equal({ name: null });
123 |
124 | const person = Person.create({ age: 35, pet: null });
125 | expect(
126 | deflate(person)
127 | ).to.deep.equal({ age: 35, pet: null });
128 |
129 | });
130 |
131 | it('deserializes to null', () => {
132 |
133 | const pet = inflate(Pet, { name: null });
134 | expect(pet).to.be.instanceOf(Pet);
135 | expect(pet).to.deep.equal({ name: null });
136 |
137 | const person = inflate(Person, { age: 35, pet: null });
138 | expect(person).to.be.instanceOf(Person);
139 | expect(person).to.deep.equal({ age: 35, pet: null });
140 |
141 | });
142 |
143 | });
144 |
145 | });
146 |
147 | describe('"optional" option', () => {
148 |
149 | describe('when value is undefined and option is false/undefined (default)', () => {
150 |
151 | class Pet extends Serializable {
152 | @Serialize() public name: string;
153 | }
154 |
155 | class Person extends Serializable {
156 | @Serialize() public age: number;
157 | @Serialize({ optional: false }) public pet: Pet;
158 | }
159 |
160 | it('should fail to serialize', () => {
161 |
162 | const pet = new Pet(); // name is undefined
163 | expect(
164 | () => deflate(pet)
165 | ).to.throw('Unable to serialize property "name": Value is undefined');
166 |
167 | const person = Person.create({ age: 35, pet: undefined });
168 | expect(
169 | () => deflate(person)
170 | ).to.throw('Unable to serialize property "pet": Value is undefined');
171 |
172 | });
173 |
174 | it('should fail to deserialize', () => {
175 |
176 | const petObj = {}; // name is undefined
177 | expect(
178 | () => inflate(Pet, petObj)
179 | ).to.throw('Unable to deserialize property "name": Value is undefined');
180 |
181 | const personObj = { age: 35 }; // pet is undefined
182 | expect(
183 | () => inflate(Person, personObj)
184 | ).to.throw('Unable to deserialize property "pet": Value is undefined');
185 |
186 | });
187 |
188 | });
189 |
190 | describe('when value is undefined and option is true', () => {
191 |
192 | class Pet extends Serializable {
193 | @Serialize({ optional: true }) public name: string;
194 | }
195 |
196 | class Person extends Serializable {
197 | @Serialize({ optional: true }) public age: number;
198 | @Serialize({ optional: true }) public pet: Pet;
199 | }
200 |
201 | it('serializes to undefined', () => {
202 |
203 | const pet = new Pet(); // name is undefined
204 | expect(
205 | deflate(pet)
206 | ).to.deep.equal({}); // name is not serialized
207 |
208 | const person = Person.create({ age: 35, pet: undefined });
209 | expect(
210 | deflate(person)
211 | ).to.deep.equal({ age: 35 }); // pet is not serialized
212 |
213 | });
214 |
215 | it('deserializes to undefined', () => {
216 |
217 | const pet = inflate(Pet, {}); // name is undefined
218 | expect(pet).to.be.instanceOf(Pet);
219 | expect(pet).to.deep.equal({});
220 |
221 | const person = inflate(Person, { age: 35 }); // pet is undefined
222 | expect(person).to.be.instanceOf(Person);
223 | expect(person).to.deep.equal({ age: 35 });
224 |
225 | });
226 |
227 | });
228 |
229 | });
230 |
231 | });
232 |
--------------------------------------------------------------------------------
/docs/_next/data/7of8QfVFcgerx6lX1Jut2/inheritance.json:
--------------------------------------------------------------------------------
1 | {"pageProps":{"slug":"inheritance","frontmatter":{"title":"Class Inheritance"},"githubLink":"https://github.com/teq/serialazy/tree/main/website/content/inheritance.page.md","markdown":"Class Inheritance
\nProperty bag serializables inherit all property serializers from parent (property bag) class
\nimport { deflate, inflate, Serialize } from 'serialazy';\n\nabstract class Shape {\n @Serialize() public x: number;\n @Serialize() public y: number;\n}\n\nclass Rectangle extends Shape {\n @Serialize({ name: 'w' }) public width: number;\n @Serialize({ name: 'h' }) public height: number;\n}\n\nconst rect = Object.assign(new Rectangle(), {\n x: 1, y: 2, width: 5, height: 3\n});\n\nconst serialized = deflate(rect);\n// serialized includes all props from Rectangle + Shape\nexpect(serialized).to.deep.equal({\n x: 1, y: 2, w: 5, h: 3\n});\n\nconst deserialized = inflate(Rectangle, serialized);\n// deserialized includes all props from Rectangle + Shape\nexpect(deserialized).to.deep.equal(rect);\n
\n\nNote: Child class can shadow parent's property serializers.
\n
"},"__N_SSG":true}
--------------------------------------------------------------------------------
/spec/src/default_type_serializer.spec.ts:
--------------------------------------------------------------------------------
1 | import chai = require('chai');
2 |
3 | import { deflate, inflate, Serializable, Serialize } from 'serialazy';
4 |
5 | const { expect } = chai;
6 |
7 | describe('default type serializer', () => {
8 |
9 | describe('for boolean properties', () => {
10 |
11 | class Book extends Serializable {
12 | @Serialize() public read: boolean;
13 | }
14 |
15 | describe('when the value is a boolean', () => {
16 |
17 | describe('of primitive type', () => {
18 |
19 | it('serializes to a boolean primitive', () => {
20 | const book = Book.create({ read: true });
21 | const serialized = deflate(book);
22 | expect(serialized).to.deep.equal({ read: true });
23 | });
24 |
25 | it('deserializes to a boolean primitive', () => {
26 | const deserialized = inflate(Book, { read: false });
27 | expect(deserialized instanceof Book).to.equal(true);
28 | expect(deserialized).to.deep.equal({ read: false });
29 | });
30 |
31 | });
32 |
33 | describe('of object type', () => {
34 |
35 | it('serializes to a boolean primitive', () => {
36 | const book = Book.create({ read: new Boolean(true) });
37 | const serialized = deflate(book);
38 | expect(serialized).to.deep.equal({ read: true });
39 | });
40 |
41 | it('deserializes to a boolean primitive', () => {
42 | const deserialized = inflate(Book, { read: new Boolean(false) as boolean });
43 | expect(deserialized instanceof Book).to.equal(true);
44 | expect(deserialized).to.deep.equal({ read: false });
45 | });
46 |
47 | });
48 |
49 | });
50 |
51 | describe('when the value is a non-boolean', () => {
52 |
53 | it('should fail to serialize', () => {
54 | const book = Book.create({ read: new Date() as any });
55 | expect(() => deflate(book)).to.throw('Unable to serialize property "read": Not a boolean');
56 | });
57 |
58 | it('should fail to deserialize', () => {
59 | expect(() => inflate(Book, { read: new Date() as any })).to.throw('Unable to deserialize property "read": Not a boolean');
60 | });
61 |
62 | });
63 |
64 | });
65 |
66 | describe('for number properties', () => {
67 |
68 | class Person extends Serializable {
69 | @Serialize() public age: number;
70 | }
71 |
72 | describe('when the value is a number', () => {
73 |
74 | describe('of primitive type', () => {
75 |
76 | it('serializes to a number primitive', () => {
77 | const person = Person.create({ age: 40 });
78 | const serialized = deflate(person);
79 | expect(serialized).to.deep.equal({ age: 40 });
80 | });
81 |
82 | it('deserializes to a number primitive', () => {
83 | const deserialized = inflate(Person, { age: 45 });
84 | expect(deserialized instanceof Person).to.equal(true);
85 | expect(deserialized).to.deep.equal({ age: 45 });
86 | });
87 |
88 | });
89 |
90 | describe('of object type', () => {
91 |
92 | it('serializes to a number primitive', () => {
93 | const person = Person.create({ age: new Number(40) });
94 | const serialized = deflate(person);
95 | expect(serialized).to.deep.equal({ age: 40 });
96 | });
97 |
98 | it('deserializes to a number primitive', () => {
99 | const deserialized = inflate(Person, { age: new Number(45) as number });
100 | expect(deserialized instanceof Person).to.equal(true);
101 | expect(deserialized).to.deep.equal({ age: 45 });
102 | });
103 |
104 | });
105 |
106 | });
107 |
108 | describe('when the value is a non-number', () => {
109 |
110 | it('should fail to serialize', () => {
111 | const person = Person.create({ age: new Date() as any });
112 | expect(() => deflate(person)).to.throw('Unable to serialize property "age": Not a number');
113 | });
114 |
115 | it('should fail to deserialize', () => {
116 | expect(() => inflate(Person, { age: new Date() as any })).to.throw('Unable to deserialize property "age": Not a number');
117 | });
118 |
119 | });
120 |
121 | });
122 |
123 | describe('for string properties', () => {
124 |
125 | class Greeter extends Serializable {
126 | @Serialize() public message: string;
127 | }
128 |
129 | describe('when the value is a string', () => {
130 |
131 | describe('of primitive type', () => {
132 |
133 | it('serializes to a string literal', () => {
134 | const greeter = Greeter.create({ message: 'hello' });
135 | const serialized = deflate(greeter);
136 | expect(serialized).to.deep.equal({ message: 'hello' });
137 | });
138 |
139 | it('deserializes to a string literal', () => {
140 | const deserialized = inflate(Greeter, { message: 'hi' });
141 | expect(deserialized instanceof Greeter).to.equal(true);
142 | expect(deserialized).to.deep.equal({ message: 'hi' });
143 | });
144 |
145 | });
146 |
147 | describe('of object type', () => {
148 |
149 | it('serializes to a string literal', () => {
150 | const greeter = Greeter.create({ message: new String('hello') });
151 | const serialized = deflate(greeter);
152 | expect(serialized).to.deep.equal({ message: 'hello' });
153 | });
154 |
155 | it('deserializes to a string literal', () => {
156 | const deserialized = inflate(Greeter, { message: new String('hello') as string });
157 | expect(deserialized instanceof Greeter).to.equal(true);
158 | expect(deserialized).to.deep.equal({ message: 'hello' });
159 | });
160 |
161 | });
162 |
163 | });
164 |
165 | describe('when the value is a non-string', () => {
166 |
167 | it('should fail to serialize', () => {
168 | const greeter = Greeter.create({ message: new Date() as any });
169 | expect(() => deflate(greeter)).to.throw('Unable to serialize property "message": Not a string');
170 | });
171 |
172 | it('should fail to deserialize', () => {
173 | expect(() => inflate(Greeter, { message: new Date() as any })).to.throw('Unable to deserialize property "message": Not a string');
174 | });
175 |
176 | });
177 |
178 | });
179 |
180 | describe('for non-primitive properties', () => {
181 |
182 | const bookObj = {
183 | title: 'The Story of the Sealed Room',
184 | author: { name: 'Arthur Conan Doyle' }
185 | };
186 |
187 | describe('when a property is serializable', () => {
188 |
189 | class Author extends Serializable {
190 | @Serialize() public name: string;
191 | }
192 |
193 | class Book extends Serializable {
194 | @Serialize() public title: string;
195 | @Serialize() public author: Author;
196 | }
197 |
198 | const book = Book.create({
199 | title: 'The Story of the Sealed Room',
200 | author: Author.create({ name: 'Arthur Conan Doyle' })
201 | });
202 |
203 | it('serializes to JSON-compatible object', () => {
204 | const serialized = deflate(book);
205 | expect(serialized).to.deep.equal(bookObj);
206 | });
207 |
208 | it('deserializes from JSON-compatible object', () => {
209 | const deserialized = inflate(Book, bookObj);
210 | expect(deserialized instanceof Book).to.equal(true);
211 | expect(deserialized).to.deep.equal(book);
212 | });
213 |
214 | });
215 |
216 | describe('when a property is a non-serializable', () => {
217 |
218 | class Author extends Serializable {
219 | public name: string;
220 | }
221 |
222 | class Book extends Serializable {
223 | @Serialize() public title: string;
224 | @Serialize() public author: Author;
225 | }
226 |
227 | const book = Book.create({
228 | title: 'The Story of the Sealed Room',
229 | author: Author.create({ name: 'Arthur Conan Doyle' })
230 | });
231 |
232 | it('should fail to serialize', () => {
233 | expect(() => deflate(book)).to.throw('Serializer function ("down") for type "Author" is not defined.');
234 | });
235 |
236 | it('should fail to deserialize', () => {
237 | expect(() => inflate(Book, bookObj)).to.throw('Deserializer function ("up") for type "Author" is not defined.');
238 | });
239 |
240 | });
241 |
242 | });
243 |
244 | });
245 |
--------------------------------------------------------------------------------
/docs/_next/data/7of8QfVFcgerx6lX1Jut2/async.json:
--------------------------------------------------------------------------------
1 | {"pageProps":{"slug":"async","frontmatter":{"title":"Async Serialization"},"githubLink":"https://github.com/teq/serialazy/tree/main/website/content/async.page.md","markdown":"Async Serialization
\nIf one or more type serializer or deserializer (down or up functions) return a Promise value,\nit is possible to await until they are resolved with deflate.resolve and inflate.resolve.
\nUnlike deflate and inflate, these functions return a Promise to serialized / deserialized value.
\nFollowing example serializes User to its id and deserializes using async getUserFieldsById function.
\nimport { deflate, inflate, Serialize } from 'serialazy';\nimport { getUserFieldsById } from './db';\n\n@Serialize({\n down: (user: User) => user.id,\n up: async (id: string) => Object.assign(new User(), await getUserFieldsById(id))\n})\nclass User {\n public id: string;\n public email: string;\n public isAdmin: boolean;\n}\n\nconst user = Object.assign(new User(), {\n id: '<unique_id>',\n email: 'john.doe@example.com',\n isAdmin: true\n});\n\nconst serialized = deflate(user);\nexpect(serialized).to.equal('<unique_id>');\n\nconst deserialized = await inflate.resolve(User, serialized);\nexpect(deserialized).to.deep.equal({\n id: '<unique_id>',\n email: 'john.doe@example.com',\n isAdmin: true\n});\n
\n\nNote: All properties of given instance are serialized / deserialized in parallel with Promise.all().
\n
"},"__N_SSG":true}
--------------------------------------------------------------------------------
/spec/src/projections.spec.ts:
--------------------------------------------------------------------------------
1 | import chai = require('chai');
2 |
3 | import { deflate, inflate, JsonType, Serializable, Serialize } from 'serialazy';
4 |
5 | const { expect } = chai;
6 |
7 | type Constructor = new () => T;
8 |
9 | describe('projection options', () => {
10 |
11 | const TEST_PROJECTION = 'test';
12 |
13 | describe('when applied to decorator', () => {
14 |
15 | describe('on a type', () => {
16 |
17 | interface Named {
18 | name: string;
19 | }
20 |
21 | function itAppliesInDefaultProjection(ctor: Constructor) {
22 |
23 | it('applies decorator in default projection', () => {
24 | const serializable = Object.assign(new ctor(), { name: 'joe' });
25 | expect(() => deflate(serializable, {
26 | projection: TEST_PROJECTION,
27 | fallbackToDefaultProjection: false
28 | })).to.throw();
29 | const serialized = deflate(serializable);
30 | expect(serialized).to.equal('joe');
31 | });
32 |
33 | }
34 |
35 | describe('when projection is undefined', () => {
36 |
37 | @Serialize({ down: (named: Named) => named.name })
38 | class Person implements Named {
39 | public name: string;
40 | }
41 |
42 | itAppliesInDefaultProjection(Person);
43 |
44 | });
45 |
46 | describe('when projection is set to undefined', () => {
47 |
48 | @Serialize({ projection: undefined, down: (named: Named) => named.name })
49 | class Person implements Named {
50 | public name: string;
51 | }
52 |
53 | itAppliesInDefaultProjection(Person);
54 |
55 | });
56 |
57 | describe('when projection is set to null', () => {
58 |
59 | @Serialize({ projection: null, down: (named: Named) => named.name })
60 | class Person implements Named {
61 | public name: string;
62 | }
63 |
64 | itAppliesInDefaultProjection(Person);
65 |
66 | });
67 |
68 | describe('when projection is set to empty string', () => {
69 |
70 | @Serialize({ projection: '', down: (named: Named) => named.name })
71 | class Person implements Named {
72 | public name: string;
73 | }
74 |
75 | itAppliesInDefaultProjection(Person);
76 |
77 | });
78 |
79 | describe('when projection is a non-empty string', () => {
80 |
81 | @Serialize({ projection: 'test', down: (named: Named) => named.name })
82 | class Person implements Named {
83 | public name: string;
84 | }
85 |
86 | it('applies decorator in given projection', () => {
87 | const serializable = Object.assign(new Person(), { name: 'joe' });
88 | expect(() => deflate(serializable)).to.throw();
89 | const serialized = deflate(serializable, { projection: TEST_PROJECTION });
90 | expect(serialized).to.equal('joe');
91 | });
92 |
93 | });
94 |
95 | });
96 |
97 | describe('on a property', () => {
98 |
99 | describe('when projection is undefined/null or empty string', () => {
100 |
101 | class Person extends Serializable {
102 |
103 | @Serialize()
104 | public id: number;
105 |
106 | @Serialize({ projection: undefined })
107 | public name: string;
108 |
109 | @Serialize({ projection: null })
110 | public address: string;
111 |
112 | @Serialize({ projection: '' })
113 | public email: string;
114 |
115 | }
116 |
117 | it('applies decorator in default projection', () => {
118 | const person = Person.create({
119 | id: 1, name: 'joe', address: 'unknown', email: 'joe@example.com'
120 | });
121 | expect(() => deflate(person, {
122 | projection: TEST_PROJECTION,
123 | fallbackToDefaultProjection: false
124 | })).to.throw();
125 | const serialized = deflate(person);
126 | expect(serialized).to.deep.equal({
127 | id: 1, name: 'joe', address: 'unknown', email: 'joe@example.com'
128 | });
129 | });
130 |
131 | });
132 |
133 | describe('when projection is a non-empty string', () => {
134 |
135 | class Person extends Serializable {
136 |
137 | @Serialize({ projection: TEST_PROJECTION })
138 | public id: number;
139 |
140 | @Serialize({ projection: TEST_PROJECTION })
141 | public name: string;
142 |
143 | }
144 |
145 | it('applies decorator in given projection', () => {
146 | const person = Person.create({ id: 1, name: 'joe' });
147 | expect(() => deflate(person)).to.throw();
148 | const serialized = deflate(person, { projection: TEST_PROJECTION });
149 | expect(serialized).to.deep.equal({ id: 1, name: 'joe' });
150 | });
151 |
152 | });
153 |
154 | });
155 |
156 | });
157 |
158 | describe('when applied to serialization functions', () => {
159 |
160 | @Serialize({
161 | down: (ts: Timestamp) => ts.date.toISOString(),
162 | up: (isoString: string) => new Timestamp(new Date(isoString))
163 | })
164 | @Serialize({
165 | projection: 'compact',
166 | down: (ts: Timestamp) => ts.date.getTime(),
167 | up: (unixTimeMs: number) => new Timestamp(new Date(unixTimeMs))
168 | })
169 | class Timestamp {
170 | public constructor(
171 | public date: Date
172 | ) {}
173 | }
174 |
175 | class JWT extends Serializable {
176 |
177 | @Serialize({ name: 'sub' })
178 | public subject: string;
179 |
180 | @Serialize({ name: 'iat' })
181 | public issuedAt: Timestamp;
182 |
183 | }
184 |
185 | class Person extends Serializable {
186 |
187 | @Serialize()
188 | @Serialize({ projection: 'compact', name: 'id' })
189 | public identifier: number;
190 |
191 | @Serialize()
192 | public name: string;
193 |
194 | }
195 |
196 | class User extends Person {
197 |
198 | @Serialize()
199 | public jwt: JWT;
200 |
201 | @Serialize()
202 | @Serialize({ projection: 'compact', name: 'lv' })
203 | public lastVisit: Timestamp;
204 |
205 | }
206 |
207 | const timestamp = new Timestamp(new Date());
208 |
209 | const user = User.create({
210 | identifier: 1,
211 | name: 'John Doe',
212 | jwt: JWT.create({
213 | subject: 'api',
214 | issuedAt: timestamp
215 | }),
216 | lastVisit: timestamp
217 | });
218 |
219 | const userDefaultProjection = {
220 | identifier: 1,
221 | name: 'John Doe',
222 | jwt: {
223 | sub: 'api',
224 | iat: timestamp.date.toISOString()
225 | },
226 | lastVisit: timestamp.date.toISOString()
227 | };
228 |
229 | const userCompactProjection = {
230 | id: 1,
231 | name: 'John Doe',
232 | jwt: {
233 | sub: 'api',
234 | iat: timestamp.date.getTime()
235 | },
236 | lv: timestamp.date.getTime()
237 | };
238 |
239 | describe('deflate', () => {
240 |
241 | function itSerializesInDefaultProjection(obj: JsonType) {
242 | it('performs serialization in default projection', () => {
243 | expect(obj).to.deep.equal(userDefaultProjection);
244 | });
245 | }
246 |
247 | describe('when projection is undefined', () => {
248 | const obj = deflate(user);
249 | itSerializesInDefaultProjection(obj);
250 | });
251 |
252 | describe('when projection is set to undefined', () => {
253 | const obj = deflate(user, { projection: undefined });
254 | itSerializesInDefaultProjection(obj);
255 | });
256 |
257 | describe('when projection is null', () => {
258 | const obj = deflate(user, { projection: null });
259 | itSerializesInDefaultProjection(obj);
260 | });
261 |
262 | describe('when projection is set to empty string', () => {
263 | const obj = deflate(user, { projection: '' });
264 | itSerializesInDefaultProjection(obj);
265 | });
266 |
267 | describe('when projection is a non-empty string', () => {
268 |
269 | const projection = 'compact';
270 |
271 | it('performs serialization in given projection', () => {
272 | const obj = deflate(user, { projection });
273 | expect(obj).to.deep.equal(userCompactProjection);
274 | });
275 |
276 | describe('when fallback to default projection is disabled', () => {
277 |
278 | it('doesn\'t fall back to default projection', () => {
279 | const obj = deflate(user, { projection, fallbackToDefaultProjection: false });
280 | expect(obj).to.deep.equal({
281 | id: 1,
282 | lv: timestamp.date.getTime()
283 | });
284 | });
285 |
286 | });
287 |
288 | });
289 |
290 | });
291 |
292 | describe('inflate', () => {
293 |
294 | function itDeserializesInDefaultProjection(instance: User) {
295 | it('performs deserialization in default projection', () => {
296 | expect(instance).to.deep.equal(user);
297 | });
298 | }
299 |
300 | describe('when projection is undefined', () => {
301 | const instance = inflate(User, userDefaultProjection);
302 | itDeserializesInDefaultProjection(instance);
303 | });
304 |
305 | describe('when projection is set to undefined', () => {
306 | const instance = inflate(User, userDefaultProjection, { projection: undefined });
307 | itDeserializesInDefaultProjection(instance);
308 | });
309 |
310 | describe('when projection is null', () => {
311 | const instance = inflate(User, userDefaultProjection, { projection: null });
312 | itDeserializesInDefaultProjection(instance);
313 | });
314 |
315 | describe('when projection is set to empty string', () => {
316 | const instance = inflate(User, userDefaultProjection, { projection: '' });
317 | itDeserializesInDefaultProjection(instance);
318 | });
319 |
320 | describe('when projection is a non-empty string', () => {
321 |
322 | const projection = 'compact';
323 |
324 | it('performs deserialization in given projection', () => {
325 | const instance = inflate(User, userCompactProjection, { projection });
326 | expect(instance).to.deep.equal(user);
327 | });
328 |
329 | describe('when fallback to default projection is disabled', () => {
330 |
331 | it('doesn\'t fallback to default projection', () => {
332 | const instance = inflate(User, userCompactProjection, { projection, fallbackToDefaultProjection: false });
333 | expect(instance).to.deep.equal({
334 | identifier: 1,
335 | lastVisit: timestamp
336 | });
337 | });
338 |
339 | });
340 |
341 | });
342 |
343 | });
344 |
345 | });
346 |
347 | });
348 |
--------------------------------------------------------------------------------