Skip to content

Commit 3046214

Browse files
committed
ADD(RxSchema) default values
1 parent 45e8544 commit 3046214

13 files changed

+248
-83
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
Features:
66
- Added [RxCollection.atomicUpsert](https://pubkey.github.io/rxdb/RxCollection.html#atomicUpsert)
7+
- Added [defaul values](https://pubkey.github.io/rxdb/RxSchema.html#default)
78

89
Other:
910
- Split out test-util into its own npm-module [async-test-util](https://github.com/pubkey/async-test-util)
10-
- Upgrade to pouchdb version [6.3.2](https://github.com/pouchdb/pouchdb/releases/tag/6.3.2)
11+
- Upgrade to pouchdb version [6.3.4](https://github.com/pouchdb/pouchdb/releases/tag/6.3.4)
1112

1213
Bugfixes:
1314
- Settings values to `null` did not work on temporaryDocuments [#215](https://github.com/pubkey/rxdb/issues/215)

docs-src/RxSchema.md

+24
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,30 @@ const schemaWithIndexes = {
129129
```
130130

131131

132+
## default
133+
Default values can only be defined for first-level fields.
134+
Whenever you insert a document or create a temporary-document, unset fields will be filled with default-values.
135+
136+
```js
137+
const schemaWithDefaultAge = {
138+
version: 0,
139+
type: 'object',
140+
properties: {
141+
firstName: {
142+
type: 'string'
143+
},
144+
lastName: {
145+
type: 'string'
146+
},
147+
age: {
148+
type: 'integer',
149+
default: 20 // <- default will be used
150+
}
151+
},
152+
};
153+
```
154+
155+
132156
## NOTICE: Not everything within the jsonschema-spec is allowed
133157
The schema is not only used to validate objects before they are written into the database, but also used to map getters to observe and populate single fieldnames, keycompression and other things. Therefore you can not use every schema which would be valid for the spec of [json-schema.org](http://json-schema.org/).
134158
For example, fieldnames must match the regex `^[a-zA-Z][[a-zA-Z0-9_]*]?[a-zA-Z0-9]$` and `additionalProperties` is always set to `false`. But don't worry, RxDB will instantly throw an error when you pass a invalid schema into it.

docs-src/SUMMARY.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
* [Create a collection with the schema](./RxSchema.md#create-a-collection-with-the-schema)
2525
* [version](./RxSchema.md#version)
2626
* [disableKeyCompression](./RxSchema.md#disableKeyCompression)
27-
* [Indexes](./RxSchema.md#indexes)
27+
* [indexes](./RxSchema.md#indexes)
28+
* [default](./RxSchema.md#default)
29+
2830

2931
* [RxCollection](./RxCollection.md)
3032
* [Creation](./RxCollection.md#creating-a-collection)

examples/angular2/app/src/components/hero-insert/hero-insert.component.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ export class HeroInsertComponent implements OnInit {
2525
async reset() {
2626
const db = await this.databaseService.get();
2727
this.tempDoc = db['hero'].newDocument({
28-
name: '',
29-
color: '',
30-
maxHP: randomInt(100, 1000),
31-
hp: 100
28+
maxHP: randomInt(100, 1000)
3229
});
3330
}
3431

examples/angular2/app/src/schemas/hero.schema.json

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
"properties": {
77
"name": {
88
"type": "string",
9-
"primary": true
9+
"primary": true,
10+
"default": ""
1011
},
1112
"color": {
12-
"type": "string"
13+
"type": "string",
14+
"default": ""
1315
},
1416
"maxHP": {
1517
"type": "number",
@@ -19,7 +21,8 @@
1921
"hp": {
2022
"type": "number",
2123
"min": 0,
22-
"max": 100
24+
"max": 100,
25+
"default": 100
2326
},
2427
"team": {
2528
"description": "color of the team this hero belongs to",

examples/angular2/package.json

+42-42
Original file line numberDiff line numberDiff line change
@@ -19,65 +19,65 @@
1919
"author": "pubkey",
2020
"license": "MIT",
2121
"dependencies": {
22-
"@angular/common": "^4.2.6",
23-
"@angular/compiler": "^4.2.6",
24-
"@angular/compiler-cli": "^4.2.6",
25-
"@angular/core": "^4.2.6",
26-
"@angular/forms": "^4.2.6",
27-
"@angular/http": "^4.2.6",
22+
"@angular/common": "4.3.0",
23+
"@angular/compiler": "4.3.0",
24+
"@angular/compiler-cli": "4.3.0",
25+
"@angular/core": "4.3.0",
26+
"@angular/forms": "4.3.0",
27+
"@angular/http": "4.3.0",
2828
"@angular/material": "2.0.0-beta.2",
29-
"@angular/platform-browser": "^4.2.6",
30-
"@angular/platform-browser-dynamic": "^4.2.6",
31-
"@angular/platform-server": "^4.2.6",
32-
"@angular/router": "^4.2.6",
29+
"@angular/platform-browser": "4.3.0",
30+
"@angular/platform-browser-dynamic": "4.3.0",
31+
"@angular/platform-server": "4.3.0",
32+
"@angular/router": "4.3.0",
3333
"babel-polyfill": "6.23.0",
34-
"concurrently": "^3.5.0",
34+
"concurrently": "3.5.0",
3535
"core-js": "2.4.1",
36-
"font-awesome": "^4.7.0",
36+
"font-awesome": "4.7.0",
3737
"hammerjs": "2.0.8",
3838
"json-loader": "0.5.4",
39-
"node-gyp": "^3.6.0",
40-
"normalize.css": "^7.0.0",
41-
"pouchdb-adapter-http": "^6.2.0",
42-
"pouchdb-adapter-idb": "^6.2.0",
43-
"pouchdb-adapter-localstorage": "^6.2.0",
44-
"pouchdb-replication": "^6.2.0",
45-
"pouchdb-server": "^2.3.7",
39+
"node-gyp": "3.6.2",
40+
"normalize.css": "7.0.0",
41+
"pouchdb-adapter-http": "6.3.4",
42+
"pouchdb-adapter-idb": "6.3.4",
43+
"pouchdb-adapter-localstorage": "6.3.4",
44+
"pouchdb-replication": "6.3.4",
45+
"pouchdb-server": "2.3.7",
4646
"random-int": "1.0.0",
4747
"regenerator": "0.9.7",
4848
"roboto-npm-webfont": "0.0.4",
49-
"rxjs": "^5.4.2",
50-
"zone.js": "^0.8.12"
49+
"rxjs": "5.4.2",
50+
"zone.js": "0.8.13"
5151
},
5252
"devDependencies": {
53-
"@types/chai": "^4.0.1",
54-
"@types/core-js": "^0.9.42",
53+
"@types/chai": "4.0.1",
54+
"@types/core-js": "0.9.42",
5555
"@types/hammerjs": "2.0.34",
56-
"@types/requirejs": "^2.1.29",
56+
"@types/requirejs": "2.1.29",
5757
"angular2-template-loader": "0.6.2",
5858
"appcache-webpack-plugin": "1.3.0",
59-
"awesome-typescript-loader": "^3.2.1",
60-
"babel-core": "^6.25.0",
61-
"babel-loader": "^7.1.1",
62-
"babel-preset-env": "^1.6.0",
59+
"awesome-typescript-loader": "3.2.1",
60+
"babel-core": "6.25.0",
61+
"babel-loader": "7.1.1",
62+
"babel-preset-env": "1.6.0",
6363
"copy-webpack-plugin": "4.0.1",
64-
"css-loader": "^0.28.0",
65-
"extract-text-webpack-plugin": "^3.0.0",
66-
"file-loader": "^0.11.1",
64+
"css-loader": "0.28.4",
65+
"extract-text-webpack-plugin": "3.0.0",
66+
"file-loader": "0.11.2",
6767
"fsmonitor": "0.2.4",
68-
"html-webpack-plugin": "^2.29.0",
68+
"html-webpack-plugin": "2.29.0",
6969
"less": "2.7.2",
70-
"less-loader": "^4.0.5",
70+
"less-loader": "4.0.5",
7171
"npm-run-all": "4.0.2",
72-
"postcss-cli": "^4.1.0",
72+
"postcss-cli": "4.1.0",
7373
"raw-loader": "0.5.1",
74-
"rimraf": "^2.6.1",
75-
"style-loader": "^0.18.2",
76-
"tslint": "^5.5.0",
77-
"typescript": "^2.4.1",
78-
"url-loader": "^0.5.9",
79-
"webpack": "^3.2.0",
80-
"webpack-dev-server": "^2.5.1",
81-
"webpack-merge": "^4.1.0"
74+
"rimraf": "2.6.1",
75+
"style-loader": "0.18.2",
76+
"tslint": "5.5.0",
77+
"typescript": "2.4.1",
78+
"url-loader": "0.5.9",
79+
"webpack": "3.3.0",
80+
"webpack-dev-server": "2.5.1",
81+
"webpack-merge": "4.1.0"
8282
}
8383
}

src/RxCollection.js

+2
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ class RxCollection {
242242
}
243243

244244
json = clone(json);
245+
json = this.schema.fillObjectWithDefaults(json);
245246

246247
if (json._id)
247248
throw new Error('do not provide ._id, it will be generated');
@@ -589,6 +590,7 @@ class RxCollection {
589590
* @return {RxDocument}
590591
*/
591592
newDocument(docData = {}) {
593+
docData = this.schema.fillObjectWithDefaults(docData);
592594
const doc = RxDocument.create(this, docData);
593595
doc._isTemporary = true;
594596
this._assignMethodsToDocument(doc);

src/RxSchema.js

+34-3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ export class RxSchema {
7878
return Object.keys(this.normalized.properties);
7979
}
8080

81+
get defaultValues() {
82+
if (!this._defaultValues) {
83+
this._defaultValues = {};
84+
Object.entries(this.normalized.properties)
85+
.filter(entry => entry[1].default)
86+
.forEach(entry => this._defaultValues[entry[0]] = entry[1].default);
87+
}
88+
return this._defaultValues;
89+
}
90+
8191
/**
8292
* get all encrypted paths
8393
*/
@@ -130,6 +140,24 @@ export class RxSchema {
130140
return this._hash;
131141
}
132142

143+
/**
144+
* fills all unset fields with default-values if set
145+
* @param {object} obj
146+
* @return {object}
147+
*/
148+
fillObjectWithDefaults(obj) {
149+
obj = clone(obj);
150+
Object
151+
.entries(this.defaultValues)
152+
.filter(entry => !obj.hasOwnProperty(entry[0]))
153+
.forEach(entry => {
154+
const fieldName = entry[0];
155+
const value = entry[0];
156+
obj[entry[0]] = entry[1];
157+
});
158+
return obj;
159+
}
160+
133161
swapIdToPrimary(obj) {
134162
if (this.primaryPath == '_id' || obj[this.primaryPath]) return obj;
135163
obj[this.primaryPath] = obj._id;
@@ -301,6 +329,9 @@ export function validateFieldsDeep(jsonSchema) {
301329
if (isNested) {
302330
if (schemaObj.primary)
303331
throw new Error('primary can only be defined at top-level');
332+
333+
if (schemaObj.default)
334+
throw new Error('default-values can only be defined at top-level');
304335
}
305336

306337
// first level
@@ -435,11 +466,11 @@ export function normalize(jsonSchema) {
435466
}
436467

437468
/**
438-
* fills the schema-json with default-values
469+
* fills the schema-json with default-settings
439470
* @param {Object} schemaObj
440471
* @return {Object} cloned schemaObj
441472
*/
442-
const fillWithDefaults = function(schemaObj) {
473+
const fillWithDefaultSettings = function(schemaObj) {
443474
schemaObj = clone(schemaObj);
444475

445476
// additionalProperties is always false
@@ -470,7 +501,7 @@ const fillWithDefaults = function(schemaObj) {
470501

471502
export function create(jsonID, doCheck = true) {
472503
if (doCheck) checkSchema(jsonID);
473-
return new RxSchema(fillWithDefaults(jsonID));
504+
return new RxSchema(fillWithDefaultSettings(jsonID));
474505
}
475506

476507
export function isInstanceOf(obj) {

src/index.d.ts

+17-16
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,38 @@ declare class RxSchema {
1515
*/
1616
type JsonSchemaTypes = "array" | "boolean" | "integer" | "number" | "null" | "object" | "string";
1717
interface JsonSchema {
18+
allOf?: JsonSchema[];
19+
anyOf?: JsonSchema[];
20+
oneOf?: JsonSchema[];
21+
additionalItems?: boolean | JsonSchema;
1822
type?: JsonSchemaTypes | JsonSchemaTypes[];
23+
default?: any;
1924
description?: string;
25+
dependencies?: {
26+
[key: string]: JsonSchema | string[];
27+
};
28+
exclusiveMinimum?: boolean;
29+
exclusiveMaximum?: boolean;
30+
items?: JsonSchema | JsonSchema[];
2031
multipleOf?: number;
32+
maxProperties?: number;
2133
maximum?: number;
22-
exclusiveMaximum?: boolean;
2334
minimum?: number;
24-
exclusiveMinimum?: boolean;
2535
maxLength?: number;
2636
minLength?: number;
27-
pattern?: string;
28-
additionalItems?: boolean | JsonSchema;
29-
items?: JsonSchema | JsonSchema[];
3037
maxItems?: number;
3138
minItems?: number;
32-
uniqueItems?: boolean;
33-
maxProperties?: number;
3439
minProperties?: number;
35-
required?: string[] | boolean;
36-
properties?: {
37-
[key: string]: JsonSchema;
38-
};
40+
pattern?: string;
3941
patternProperties?: {
4042
[key: string]: JsonSchema;
4143
};
42-
dependencies?: {
43-
[key: string]: JsonSchema | string[];
44+
properties?: {
45+
[key: string]: JsonSchema;
4446
};
47+
required?: string[] | boolean;
48+
uniqueItems?: boolean;
4549
enum?: any[];
46-
allOf?: JsonSchema[];
47-
anyOf?: JsonSchema[];
48-
oneOf?: JsonSchema[];
4950
not?: JsonSchema;
5051
definitions?: {
5152
[key: string]: JsonSchema;

test/helper/schemas.js

+26
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,32 @@ export const human = {
2424
required: ['firstName', 'lastName']
2525
};
2626

27+
export const humanDefault = {
28+
title: 'human schema',
29+
version: 0,
30+
description: 'describes a human being',
31+
type: 'object',
32+
properties: {
33+
passportId: {
34+
type: 'string',
35+
index: true
36+
},
37+
firstName: {
38+
type: 'string'
39+
},
40+
lastName: {
41+
type: 'string'
42+
},
43+
age: {
44+
description: 'age in years',
45+
type: 'integer',
46+
minimum: 0,
47+
maximum: 150,
48+
default: 20
49+
}
50+
},
51+
required: ['passportId']
52+
};
2753

2854
export const simpleHuman = {
2955
title: 'human schema',

0 commit comments

Comments
 (0)