1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 | 1x
1x
1x
1x
1x
12x
12x
12x
78x
78x
45x
45x
12x
40x
40x
40x
300x
300x
296x
296x
296x
40x
1x
| const _ = require('lodash');
const db = require('../db');
const inflection = require('inflection');
const proto = db.bookshelf.Model.prototype;
/**
* Abstract database model.
*
* @class
* @extends bookshelf.Model
*/
const Abstract = db.bookshelf.Model.extend({
/**
* Parses data from the specified source into this record's columns.
*
* // The following code:
* record.parseFrom(data, [ 'name', 'siteUrl' ]);
*
* // Is equivalent to:
* if (data.hasOwnProperty('name')) {
* record.set('name', data.name);
* }
* if (data.hasOwnProperty('siteUrl')) {
* record.set('site_url', data.siteUrl);
* }
*
* // The following code:
* record.parseFrom(data, [ 'street', 'zipCode' ], { columnPrefix: 'address_', sourcePrefix: 'address.' });
*
* // Is equivalent to:
* if (data.hasOwnProperty('address') && data.address.hasOwnProperty('street')) {
* record.set('address_street', data.address.street);
* }
* if (data.hasOwnProperty('address') && data.address.hasOwnProperty('zipCode')) {
* record.set('address_zip_code', data.address.zipCode);
* }
*
* @method
* @memberof Abstract
* @instance
* @param {object} source - Source object (typically the parsed JSON request body).
* @param {string[]} properties - Camel-cased properties of the source object to parse.
* The column names will correspond to the underscored names of the properties (e.g. `zipCode` => `zip_code`).
* @param {object} [options] - Deserialization options.
* @param {string} [options.columnPrefix] - Prefix to prepend to column names.
* For example, if the prefix is `address_` and one of the properties to parse is `zipCode`, the column
* in which the value is stored will be `address_zip_code`.
* @param {string} [options.sourcePrefix] - Prefix to prepend to property names before extracting them from the
* source object. For example, if the prefix is `address.` and one of the properties to parse is `zipCode`, the
* `zipCode` property of the source's object `address` sub-object will be extracted.
* @returns {Model} This record.
*/
parseFrom: function(source, properties, options = {}) {
const columnPrefix = options.columnPrefix || '';
const sourcePrefix = options.sourcePrefix || '';
for (let property of properties) {
// Determine the complete source property name, e.g. `zipCode` or `address.zipCode` (with the "sourcePrefix" option).
const sourceProperty = `${sourcePrefix}${property}`;
// Only parse the property if it's in the source object.
if (_.has(source, sourceProperty)) {
// Determine the column name by underscoring the property name and prepending the column prefix (if any).
const column = `${columnPrefix}${inflection.underscore(property)}`;
this.set(column, _.get(source, sourceProperty));
}
}
return this;
},
/**
* Serializes columns of this record into the specified target object.
*
* // The following code:
* record.serializeTo(target, [ 'name', 'site_url' ]);
*
* // Is equivalent to:
* if (record.has('name')) {
* target.name = record.get('name');
* }
* if (record.has('site_url')) {
* target.siteUrl = record.get('site_url');
* }
*
* // The following code:
* record.serializeTo(target, [ 'street', 'zip_code' ], { columnPrefix: 'address_', targetPrefix: 'address.' });
*
* // Is equivalent to:
* if (!target.hasOwnProperty('address')) {
* target.address = {};
* }
* if (record.has('address_street')) {
* target.address.street = record.get('address_street');
* }
* if (record.has('address_zip_code')) {
* target.address.zipCode = record.get('address_zip_code');
* }
*
* @method
* @memberOf Abstract
* @instance
* @param {object} target - Target object to attach serialized properties to.
* @param {string[]} properties - Underscored column names of the record to serialize.
* The target property names will correspond to the camelized names of the columns (e.g. `zip_code` => `zipCode`).
* @param {object} [options] - Serialization options.
* @param {string} [options.columnPrefix] - Prefix to prepend to the column names to serialize. For example, if the
* prefix is `address` and one of the columns to serialize is `zip_code`, the column from which the value is
* extracted will be `address_zip_code`.
* @param {string} [options.targetPrefix] - Prefix to prepend to the property names of the target object. For
* example, if the target prefix is `address.` and one of the columns to serialize is `zip_code`, the `zipCode`
* property of the target object's `address` sub-object will be set to the value of the column.
* @returns {object} The target object.
*/
serializeTo: function(target, properties, options = {}) {
const columnPrefix = options.columnPrefix || '';
const targetPrefix = options.targetPrefix || '';
for (let property of properties) {
const column = `${columnPrefix}${property}`;
if (this.has(column)) {
const columnWithoutPrefix = column.slice(columnPrefix.length);
const targetProperty = `${targetPrefix}${inflection.camelize(columnWithoutPrefix, true)}`;
_.set(target, targetProperty, this.get(column));
}
}
return target;
}
});
module.exports = Abstract;
|