├── .editorconfig ├── .gitignore ├── .jscsrc ├── .jshintrc ├── LICENSE ├── README.md ├── build ├── back4app-entity.js ├── config.json └── text.js ├── dist └── browser │ ├── back4app-entity-bundle.js │ ├── back4app-entity.js │ └── text.js ├── docs └── guide │ ├── back4app.entity.guide.js │ ├── back4app.entity.guide.json │ └── getting-started.md ├── gulp.config.json ├── gulpfile.js ├── index.js ├── package.json ├── src └── back │ ├── adapters │ ├── Adapter.js │ ├── MemoryAdapter.js │ └── index.js │ ├── index.js │ ├── models │ ├── Entity.js │ ├── EntitySpecification.js │ ├── User.js │ ├── attributes │ │ ├── Attribute.js │ │ ├── AttributeDictionary.js │ │ ├── index.js │ │ └── types │ │ │ ├── AssociationAttribute.js │ │ │ ├── BooleanAttribute.js │ │ │ ├── DateAttribute.js │ │ │ ├── NumberAttribute.js │ │ │ ├── ObjectAttribute.js │ │ │ ├── StringAttribute.js │ │ │ └── index.js │ ├── errors.js │ ├── index.js │ └── methods.js │ ├── settings.js │ └── utils │ ├── classes.js │ ├── index.js │ └── objects.js └── tests ├── unit ├── back │ ├── adapters │ │ ├── MockAdapter.js │ │ ├── adapter.test.js │ │ └── index.test.js │ ├── index.test.js │ ├── models │ │ ├── C1.js │ │ ├── C11.js │ │ ├── C2.js │ │ ├── C3.js │ │ ├── EntityProxy.js │ │ ├── attributes │ │ │ ├── attribute.test.js │ │ │ ├── attributeDictionary.test.js │ │ │ ├── index.test.js │ │ │ └── types │ │ │ │ ├── associationAttribute.test.js │ │ │ │ ├── booleanAttribute.test.js │ │ │ │ ├── dateAttribute.test.js │ │ │ │ ├── index.test.js │ │ │ │ ├── numberAttribute.test.js │ │ │ │ ├── objectAttribute.test.js │ │ │ │ └── stringAttribute.test.js │ │ ├── entity.test.js │ │ ├── entitySpecification.test.js │ │ ├── errors.test.js │ │ ├── index.test.js │ │ ├── methods.test.js │ │ └── user.test.js │ ├── settings.test.js │ └── utils │ │ ├── classes.test.js │ │ ├── index.test.js │ │ └── objects.test.js ├── index.test.js └── settings.js └── visual ├── editor-multi ├── index.html ├── main.js └── style.css ├── editor-single ├── index.html ├── main.js └── style.css └── requirejs ├── index.html └── main.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | end_of_line = lf 11 | 12 | [{*.js,*.yaml,*.yml,*.json,.jshintrc,.jscsrc,*.html}] 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 | node_modules 29 | 30 | # Always-ignore extensions 31 | *.~ 32 | *.swp 33 | 34 | # Folders to ignore 35 | .idea/ 36 | dist/docs/ 37 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "excludeFiles": ["node_modules/**", "src/front/lib/**"], 3 | "disallowKeywords": ["with"], 4 | "disallowKeywordsOnNewLine": ["else"], 5 | "disallowMixedSpacesAndTabs": true, 6 | "disallowMultipleLineStrings": true, 7 | "disallowNewlineBeforeBlockStatements": true, 8 | "disallowSpaceAfterObjectKeys": true, 9 | "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], 10 | "disallowSpaceBeforeBinaryOperators": [","], 11 | "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], 12 | "disallowSpacesInCallExpression": true, 13 | "disallowSpacesInFunctionDeclaration": { 14 | "beforeOpeningRoundBrace": true 15 | }, 16 | "disallowSpacesInNamedFunctionExpression": { 17 | "beforeOpeningRoundBrace": true 18 | }, 19 | "disallowSpacesInsideArrayBrackets": true, 20 | "requireSpaceBeforeKeywords": [ 21 | "else", 22 | "while", 23 | "catch" 24 | ], 25 | "disallowSpacesInsideParentheses": true, 26 | "disallowTrailingComma": true, 27 | "disallowTrailingWhitespace": true, 28 | "requireCommaBeforeLineBreak": true, 29 | "requireLineFeedAtFileEnd": true, 30 | "requireSpaceAfterBinaryOperators": [ 31 | "?", 32 | ":", 33 | "+", 34 | "-", 35 | "/", 36 | "*", 37 | "%", 38 | "==", 39 | "===", 40 | "!=", 41 | "!==", 42 | ">", 43 | ">=", 44 | "<", 45 | "<=", 46 | "&&", 47 | "||" 48 | ], 49 | "requireSpaceBeforeBinaryOperators": [ 50 | "?", 51 | ":", 52 | "+", 53 | "-", 54 | "/", 55 | "*", 56 | "%", 57 | "==", 58 | "===", 59 | "!=", 60 | "!==", 61 | ">", 62 | ">=", 63 | "<", 64 | "<=", 65 | "&&", 66 | "||" 67 | ], 68 | "requireSpaceAfterKeywords": [ 69 | "function", 70 | "if", 71 | "else", 72 | "for", 73 | "while", 74 | "do", 75 | "switch", 76 | "return", 77 | "try", 78 | "catch" 79 | ], 80 | "requireSpaceBeforeBlockStatements": true, 81 | "requireSpacesInConditionalExpression": { 82 | "afterTest": true, 83 | "beforeConsequent": true, 84 | "afterConsequent": true, 85 | "beforeAlternate": true 86 | }, 87 | "requireSpacesInForStatement": true, 88 | "requireSpacesInFunction": { 89 | "beforeOpeningCurlyBrace": true 90 | }, 91 | "validateLineBreaks": "LF", 92 | "validateIndentation": 2, 93 | "validateQuoteMarks": "'", 94 | "maximumLineLength": 80 95 | } 96 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "latedef": false, 7 | "noarg": true, 8 | "nocomma": true, 9 | "nonbsp": true, 10 | "node": true, 11 | "nonew": true, 12 | "strict": true, 13 | "undef": true, 14 | "unused": true, 15 | "validthis": true, 16 | 17 | "globals": { 18 | "$": false, 19 | "angular": false, 20 | "joint": false, 21 | "window": false, 22 | "document": false, 23 | "global": false, 24 | "alert": false, 25 | "requirejs": false, 26 | "define": false, 27 | "ace": false, 28 | 29 | // global for tests 30 | "it": false, 31 | "beforeEach": false, 32 | "describe": false, 33 | "before": false, 34 | "context": false 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 BACK4APP SERVICOS DIGITAIS LTDA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | back4app entity layer implementations 2 | ===================================== 3 | 4 | [![Build Status]( 5 | http://jenkins.back4app.com:8080/buildStatus/icon?job=back4app-entity%20-%20master)]( 6 | http://jenkins.back4app.com:8080/job/back4app-entity%20-%20master/) 7 | 8 | ## Table of contents 9 | 10 | * [Getting Started] (#getting-started) 11 | * [Dependencies] (#dependencies) 12 | * [Gulp] (#gulp) 13 | * [Building Files] (#building-files) 14 | * [Best Practices] (#best-practices) 15 | * [Publishing] (#publishing) 16 | 17 | ### Getting Started 18 | 19 | First of all, you need to install Node.js. To help you to manage different 20 | version of Node.js in your system is recommended that you use nvm. nvm is a 21 | Node.js version manager. Using it you will be able to have how many Node.js 22 | versions you want. To install it run this command: 23 | 24 | ``` 25 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash 26 | ``` 27 | 28 | or 29 | 30 | ``` 31 | wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash 32 | ``` 33 | 34 | To enable the nvm, close and reopen the terminal. 35 | Now you can install the most recent stable version of Node.js. To do this just 36 | run this command: 37 | 38 | ``` 39 | nvm install stable 40 | ``` 41 | 42 | For further information about nvm check its [repository]( 43 | https://github.com/creationix/nvm). 44 | 45 | ### Dependencies 46 | 47 | To install all dependencies you should run this command: 48 | 49 | ``` 50 | npm install 51 | ``` 52 | 53 | ### Gulp 54 | 55 | Gulp is included on Development Dependencies. Running the previous command might install it. 56 | To install gulp you should run this command: 57 | 58 | ``` 59 | npm install gulp --global 60 | ``` 61 | 62 | #### Gulp Tasks 63 | 64 | ##### lint 65 | 66 | This task is used to maintain the established standards on code style and avoid syntax errors. 67 | 68 | It uses `gulp-jshint` and `gulp-jscs`. 69 | 70 | ### Best Practices 71 | 72 | * You should follow the configuration files, using it on your IDE. 73 | They're `.editorconfig`, `.jscsrc` and `.jshintrc`. 74 | 75 | * Try to always remember to run lint: 76 | ``` 77 | gulp lint 78 | ``` 79 | * Create tests to any new major interactions, or changed ones. 80 | 81 | * Follow the code comment standards for documentations. 82 | 83 | ### Publishing 84 | 85 | To publish a new *patch* version, checkout the `master` branch, pull the latest changes and run the following commands: 86 | 87 | ``` 88 | $ gulp dist 89 | $ git add . && git commit -m 'Update version' 90 | $ npm version patch 91 | $ git push && git push --tags 92 | $ npm publish 93 | ``` 94 | 95 | The new version should be accessible on npm. 96 | -------------------------------------------------------------------------------- /build/back4app-entity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Configure `back4app-entity` path, if possible */ 4 | 5 | (function () { 6 | var isBrowser = !!( 7 | typeof window !== 'undefined' && 8 | typeof navigator !== 'undefined' && 9 | window.document 10 | ); 11 | 12 | function configPath() { 13 | if (isBrowser) { 14 | eachReverse(scripts(), function (script) { 15 | var src = script.getAttribute('src'); 16 | if (src) { 17 | var path = extractPath(src); 18 | requirejs.config({ 19 | baseUrl: path, 20 | paths: { 21 | 'back4app-entity': 'back4app-entity-bundle' 22 | } 23 | }); 24 | return true; 25 | } 26 | }); 27 | } 28 | } 29 | 30 | function eachReverse(ary, func) { 31 | if (ary) { 32 | var i; 33 | for (i = ary.length - 1; i > -1; i -= 1) { 34 | if (ary[i] && func(ary[i], i, ary)) { 35 | break; 36 | } 37 | } 38 | } 39 | } 40 | 41 | function scripts() { 42 | return document.getElementsByTagName('script'); 43 | } 44 | 45 | function extractPath(src) { 46 | var parts = src.split('/'); 47 | parts.pop(); 48 | return parts.length ? parts.join('/') : '.'; 49 | } 50 | 51 | configPath(); 52 | })(); 53 | -------------------------------------------------------------------------------- /build/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "../tmp-build/lib/", 3 | 4 | "packages": [ 5 | {"name": "back4app-entity", "main": "index"}, 6 | {"name": "back4app-entity/adapters", "main": "index"}, 7 | {"name": "back4app-entity/models", "main": "index"}, 8 | {"name": "back4app-entity/models/attributes", "main": "index"}, 9 | {"name": "back4app-entity/models/attributes/types", "main": "index"}, 10 | {"name": "back4app-entity/utils", "main": "index"} 11 | ], 12 | 13 | "paths": { 14 | "bcryptjs": "vendor/bcrypt", 15 | "bluebird": "vendor/bluebird", 16 | "chai": "vendor/chai", 17 | "node-uuid": "vendor/uuid", 18 | "path": "vendor/path", 19 | "util": "vendor/util" 20 | }, 21 | 22 | "name": "back4app-entity", 23 | 24 | "out": "../tmp-build/back4app-entity-bundle.js" 25 | } 26 | -------------------------------------------------------------------------------- /dist/browser/back4app-entity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Configure `back4app-entity` path, if possible */ 4 | 5 | (function () { 6 | var isBrowser = !!( 7 | typeof window !== 'undefined' && 8 | typeof navigator !== 'undefined' && 9 | window.document 10 | ); 11 | 12 | function configPath() { 13 | if (isBrowser) { 14 | eachReverse(scripts(), function (script) { 15 | var src = script.getAttribute('src'); 16 | if (src) { 17 | var path = extractPath(src); 18 | requirejs.config({ 19 | baseUrl: path, 20 | paths: { 21 | 'back4app-entity': 'back4app-entity-bundle' 22 | } 23 | }); 24 | return true; 25 | } 26 | }); 27 | } 28 | } 29 | 30 | function eachReverse(ary, func) { 31 | if (ary) { 32 | var i; 33 | for (i = ary.length - 1; i > -1; i -= 1) { 34 | if (ary[i] && func(ary[i], i, ary)) { 35 | break; 36 | } 37 | } 38 | } 39 | } 40 | 41 | function scripts() { 42 | return document.getElementsByTagName('script'); 43 | } 44 | 45 | function extractPath(src) { 46 | var parts = src.split('/'); 47 | parts.pop(); 48 | return parts.length ? parts.join('/') : '.'; 49 | } 50 | 51 | configPath(); 52 | })(); 53 | -------------------------------------------------------------------------------- /docs/guide/back4app.entity.guide.js: -------------------------------------------------------------------------------- 1 | /* This file must be kept in order for JSDoc to process the guides */ 2 | -------------------------------------------------------------------------------- /docs/guide/back4app.entity.guide.json: -------------------------------------------------------------------------------- 1 | { 2 | "getting-started": { 3 | "title": "Getting Started" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | Getting started here. 4 | -------------------------------------------------------------------------------- /gulp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": { 3 | 4 | "core": { 5 | "src": "src/back/", 6 | "dest": "tmp-build/lib/back4app-entity/" 7 | }, 8 | 9 | "vendor": { 10 | "libs": { 11 | "bcrypt": "node_modules/bcryptjs/dist/bcrypt.js", 12 | "bluebird": "node_modules/bluebird/js/browser/bluebird.js", 13 | "chai": "node_modules/chai/chai.js", 14 | "uuid": "node_modules/node-uuid/uuid.js", 15 | "util": "node_modules/util-browser/index.js", 16 | "path": "node_modules/path-browserify/" 17 | }, 18 | "dest": "tmp-build/lib/vendor/" 19 | }, 20 | 21 | "build": { 22 | "src": "build/", 23 | "dest": "dist/browser/", 24 | "tmp": "tmp-build/" 25 | }, 26 | 27 | "tools": { 28 | "rjs": "node_modules/.bin/r.js" 29 | }, 30 | 31 | "lintCheckFiles": [ 32 | "src/**/*.js", 33 | "!src/front/lib/**", 34 | "tests/**/*.js", 35 | "dist/back4app-entity.js", 36 | "!node_modules/", 37 | "!coverage/" 38 | ], 39 | "mochaSrc": [ 40 | "./tests/unit/**/*.test.js", 41 | "!./tests/unit/front" 42 | ], 43 | "backDocsSrc": "./src/back", 44 | "backDocsDist": "./dist/docs/back", 45 | "guideDocsSrc": "./docs/guide", 46 | "guideDocsDist": "./dist/docs/guide" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var gulpConfig = require('./gulp.config.json'); 5 | var paths = gulpConfig.paths; 6 | var jshint = require('gulp-jshint'); 7 | var jscs = require('gulp-jscs'); 8 | var stylish = require('gulp-jscs-stylish'); 9 | var mocha = require('gulp-mocha'); 10 | var shell = require('gulp-shell'); 11 | var rename = require('gulp-rename'); 12 | var path = require('path'); 13 | var del = require('del'); 14 | var exec = require('child_process').exec; 15 | 16 | /** 17 | * The default task (called when you run `gulp` from cli) 18 | */ 19 | gulp.task('default', ['test']); 20 | 21 | /** 22 | * Task to run complete test for deployment 23 | */ 24 | gulp.task('test', ['dist', 'test-js', 'docs']); 25 | 26 | /** 27 | * Task to generate dist build 28 | */ 29 | gulp.task('dist', ['clean:dist'], function () { 30 | 31 | start(); 32 | 33 | function start() { 34 | // wrap core source code in AMD-friendly format 35 | gulp.src('') 36 | .pipe(shell([ 37 | '<%= rjs %> -convert <%= src %> <%= dest %>' 38 | ], { 39 | templateData: { 40 | rjs: paths.tools.rjs, 41 | src: paths.core.src, 42 | dest: paths.core.dest 43 | } 44 | })) 45 | .on('end', convertLibBcrypt); 46 | } 47 | 48 | function convertLibBcrypt() { 49 | // copy vendor lib, wrapping in AMD format if necessary 50 | gulp.src(paths.vendor.libs.bcrypt) 51 | .pipe(gulp.dest(paths.vendor.dest)) 52 | .on('end', convertLibBluebird); 53 | } 54 | 55 | function convertLibBluebird() { 56 | // copy vendor lib, wrapping in AMD format if necessary 57 | gulp.src(paths.vendor.libs.bluebird) 58 | .pipe(gulp.dest(paths.vendor.dest)) 59 | .on('end', convertLibChai); 60 | } 61 | 62 | function convertLibChai() { 63 | // copy vendor lib, wrapping in AMD format if necessary 64 | gulp.src(paths.vendor.libs.chai) 65 | .pipe(gulp.dest(paths.vendor.dest)) 66 | .on('end', convertLibUuid); 67 | } 68 | 69 | function convertLibUuid() { 70 | // copy vendor lib, wrapping in AMD format if necessary 71 | gulp.src(paths.vendor.libs.uuid) 72 | .pipe(gulp.dest(paths.vendor.dest)) 73 | .on('end', convertLibUtil); 74 | } 75 | 76 | function convertLibUtil() { 77 | // copy vendor lib, wrapping in AMD format if necessary 78 | gulp.src(paths.vendor.libs.util) 79 | .pipe(rename('util.js')) 80 | .pipe(gulp.dest(paths.vendor.dest)) 81 | .on('end', convertLibPath); 82 | } 83 | 84 | function convertLibPath() { 85 | // copy vendor lib, wrapping in AMD format if necessary 86 | var tmpConvertDir = path.join(paths.build.tmp, 'tmpConvert'); 87 | gulp.src('') 88 | .pipe(shell([ 89 | '<%= rjs %> -convert <%= src %> <%= dest %>' 90 | ], { 91 | templateData: { 92 | rjs: paths.tools.rjs, 93 | src: paths.vendor.libs.path, 94 | dest: tmpConvertDir 95 | } 96 | })) 97 | .on('end', function () { 98 | gulp.src(path.join(tmpConvertDir, 'index.js')) 99 | .pipe(rename('path.js')) 100 | .pipe(gulp.dest(paths.vendor.dest)) 101 | .on('end', buildMainBundle); 102 | }); 103 | } 104 | 105 | function buildMainBundle() { 106 | // bundle all files and minify 107 | gulp.src('') 108 | .pipe(shell([ 109 | '<%= rjs %> -o build/config.json' 110 | ], { 111 | templateData: { 112 | rjs: paths.tools.rjs 113 | } 114 | })) 115 | .on('end', copyFilesToDist); 116 | } 117 | 118 | function copyFilesToDist() { 119 | // copy bundle and index files to dist folder 120 | var bundle = path.join(paths.build.tmp, 'back4app-entity-bundle.js'); 121 | gulp.src(bundle) 122 | .pipe(gulp.dest(paths.build.dest)) 123 | .on('end', function () { 124 | var mainJS = path.join(paths.build.src, 'back4app-entity.js'); 125 | gulp.src(mainJS) 126 | .pipe(gulp.dest(paths.build.dest)) 127 | .on('end', function () { 128 | var textJS = path.join(paths.build.src, 'text.js'); 129 | gulp.src(textJS) 130 | .pipe(gulp.dest(paths.build.dest)) 131 | .on('end', removeTempBuildFiles); 132 | }); 133 | }); 134 | } 135 | 136 | function removeTempBuildFiles() { 137 | // remove temporary build folder 138 | del([paths.build.tmp]); 139 | } 140 | }); 141 | 142 | /** 143 | * Task to clean dist folder 144 | */ 145 | gulp.task('clean:dist', function () { 146 | return del(['dist/**/*']); 147 | }); 148 | 149 | /** 150 | * Task to run all linters and tests 151 | */ 152 | gulp.task('test-js', ['lint', 'mocha']); 153 | 154 | /** 155 | * Task to run link checks 156 | */ 157 | gulp.task('lint', function () { 158 | var noop = function () {}; 159 | 160 | return gulp.src(paths.lintCheckFiles) 161 | .pipe(jshint()) 162 | .pipe(jscs()) 163 | .on('error', noop) 164 | .pipe(stylish.combineWithHintResults()) 165 | .pipe(jshint.reporter('jshint-stylish')) 166 | .pipe(jshint.reporter('fail')); 167 | }); 168 | 169 | /** 170 | * Task to run mocha tests 171 | */ 172 | gulp.task('mocha', function () { 173 | return gulp.src(paths.mochaSrc, {read: false}) 174 | .pipe(mocha({ 175 | reporter: 'spec' 176 | })); 177 | }); 178 | 179 | /** 180 | * Task to create docs 181 | */ 182 | gulp.task('docs', ['docs:back', 'docs:guide']); 183 | 184 | /** 185 | * Task to create back docs 186 | */ 187 | gulp.task('docs:back', function () { 188 | exec( 189 | './node_modules/jsdoc/jsdoc.js ' + 190 | '-d ' + paths.backDocsDist + ' ' + 191 | '-r ' + paths.backDocsSrc + ' ' + 192 | '--private', 193 | function (err, stdout, stderr) { 194 | console.log(stdout); 195 | console.log(stderr); 196 | } 197 | ); 198 | }); 199 | 200 | /** 201 | * Task to create guide docs 202 | */ 203 | gulp.task('docs:guide', function () { 204 | exec( 205 | './node_modules/jsdoc/jsdoc.js ' + 206 | '-u ' + paths.guideDocsSrc + ' ' + 207 | '-d ' + paths.guideDocsDist + ' ' + 208 | '-r ' + paths.guideDocsSrc, 209 | function (err, stdout, stderr) { 210 | console.log(stdout); 211 | console.log(stderr); 212 | } 213 | ); 214 | }); 215 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var entityBack = require('./src/back'); 2 | 3 | module.exports = entityBack; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@back4app/back4app-entity", 3 | "version": "1.0.17", 4 | "description": "back{4}app implementations for the plataform's entity layer", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "gulp test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/back4app/back4app-entity.git" 12 | }, 13 | "keywords": [ 14 | "back{4}app", 15 | "entity", 16 | "persistence", 17 | "backend", 18 | "data", 19 | "database", 20 | "orm" 21 | ], 22 | "author": "BACK4APP SERVICOS DIGITAIS LTDA", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/back4app/back4app-entity/issues" 26 | }, 27 | "homepage": "https://github.com/back4app/back4app-entity#readme", 28 | "devDependencies": { 29 | "ace-builds": "^1.2.2", 30 | "del": "^2.1.0", 31 | "gulp": "^3.9.0", 32 | "gulp-jscs": "^3.0.2", 33 | "gulp-jscs-stylish": "^1.2.1", 34 | "gulp-jshint": "^1.11.2", 35 | "gulp-mocha": "^2.2.0", 36 | "gulp-rename": "^1.2.2", 37 | "gulp-shell": "^0.5.0", 38 | "jsdoc": "^3.4.0", 39 | "jshint-stylish": "^2.1.0", 40 | "mocha": "^2.3.4", 41 | "mockery": "^1.4.0", 42 | "path-browserify": "0.0.0", 43 | "requirejs": "^2.1.20", 44 | "sinon": "^1.17.2", 45 | "text": "github:requirejs/text#2.0.14", 46 | "util-browser": "0.0.2" 47 | }, 48 | "dependencies": { 49 | "bcryptjs": "^2.3.0", 50 | "bluebird": "^3.0.5", 51 | "chai": "3.4.1", 52 | "node-uuid": "^1.4.7" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/back/adapters/Adapter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('chai').expect; 4 | var Promise = require('bluebird'); 5 | 6 | module.exports = Adapter; 7 | 8 | /** 9 | * Base class for database adapters. It cannot be directly initialized. 10 | * @constructor 11 | * @memberof module:back4app-entity/adapters 12 | * @example 13 | * var myAdapter = new MyAdapter(myConfig); 14 | */ 15 | function Adapter() { 16 | expect(this).to.be.an( 17 | 'object', 18 | 'The Adapter\'s constructor can be only invoked from specialized' + 19 | 'classes\' constructors' 20 | ); 21 | 22 | expect(this.constructor).to.be.a( 23 | 'function', 24 | 'The Adapter\'s constructor can be only invoked from specialized' + 25 | 'classes\' constructors' 26 | ); 27 | 28 | expect(this.constructor).to.not.equal( 29 | Adapter, 30 | 'The Adapter is an abstract class and cannot be directly initialized' 31 | ); 32 | 33 | expect(this).to.be.instanceof( 34 | Adapter, 35 | 'The Adapter\'s constructor can be only invoked from specialized' + 36 | 'classes\' constructors' 37 | ); 38 | } 39 | 40 | Adapter.prototype.loadEntity = loadEntity; 41 | Adapter.prototype.loadEntityAttribute = loadEntityAttribute; 42 | Adapter.prototype.insertObject = insertObject; 43 | Adapter.prototype.updateObject = updateObject; 44 | 45 | /** 46 | * This method is called always that an Entity is specified. The adapter has to 47 | * load the new specified Entity. It has to be implemented in the concrete 48 | * adapters. Otherwise, it will throw Error. 49 | * @name module:back4app-entity/adapters.Adapter#loadEntity 50 | * @function 51 | * @param {!Class} Entity The Entity class to be loaded. 52 | * @example 53 | * myAdapter.loadEntity(MyEntity); 54 | */ 55 | function loadEntity() { 56 | throw new Error('Function "loadEntity" has to be implemented in the ' + 57 | 'Adapter specialization'); 58 | } 59 | 60 | /** 61 | * This method is called always that an Entity's attribute is loaded in an 62 | * EntitySpecification. The adapter has to load the new specified Attribute. It 63 | * has to be implemented in the concrete adapters. Otherwise, it will throw 64 | * Error. 65 | * @name module:back4app-entity/adapters.Adapter#loadEntityAttribute 66 | * @function 67 | * @param {!Class} Entity The Entity class whose Attribute has to be loaded. 68 | * @param {!module:back4app-entity/models/attributes.Attribute} attribute The 69 | * attribute to be loaded. 70 | * @example 71 | * myAdapter.loadEntityAttribute(MyEntity, myEntityAttribute); 72 | */ 73 | function loadEntityAttribute() { 74 | throw new Error('Function "loadAttribute" has to be implemented in the ' + 75 | 'Adapter specialization'); 76 | } 77 | 78 | /** 79 | * This method is called always that an Entity object has to be inserted in the 80 | * storage. The adapter has to insert the new Entity object. It has to be 81 | * implemented in the concrete adapters. Otherwise, it will throw Error. 82 | * @name module:back4app-entity/adapters.Adapter#insertObject 83 | * @function 84 | * @param {!module:back4app-entity/models.Entity} entityObject The Entity object 85 | * to be inserted. 86 | * @returns {Promise.} Promise that returns nothing if succeed 87 | * and the Error if failed. 88 | * @example 89 | * myAdapter.insertObject(new MyEntity()); 90 | */ 91 | function insertObject() { 92 | return new Promise(function () { 93 | throw new Error('Function "insertObject" has to be implemented in the ' + 94 | 'Adapter specialization'); 95 | }); 96 | } 97 | 98 | /** 99 | * This method is called always that an Entity object has to be updated in the 100 | * storage. The adapter has to update the Entity object. It has to be 101 | * implemented in the concrete adapters. Otherwise, it will throw Error. 102 | * @name module:back4app-entity/adapters.Adapter#updateObject 103 | * @function 104 | * @param {!module:back4app-entity/models.Entity} entityObject The Entity object 105 | * to be updated. 106 | * @returns {Promise.} Promise that returns nothing if succeed 107 | * and the Error if failed. 108 | * @example 109 | * myAdapter.updateObject(myEntity); 110 | */ 111 | function updateObject() { 112 | return new Promise(function () { 113 | throw new Error('Function "updateObject" has to be implemented in the ' + 114 | 'Adapter specialization'); 115 | }); 116 | } 117 | -------------------------------------------------------------------------------- /src/back/adapters/MemoryAdapter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var Promise = require('bluebird'); 5 | var Adapter = require('./Adapter'); 6 | 7 | module.exports = MemoryAdapter; 8 | 9 | /* Adapter Constructor */ 10 | 11 | function MemoryAdapter() { 12 | this.store = {}; 13 | } 14 | 15 | util.inherits(MemoryAdapter, Adapter); 16 | 17 | /* Public API */ 18 | 19 | MemoryAdapter.prototype.loadEntity = loadEntity; 20 | MemoryAdapter.prototype.loadEntityAttribute = loadEntityAttribute; 21 | MemoryAdapter.prototype.insertObject = insertObject; 22 | MemoryAdapter.prototype.updateObject = updateObject; 23 | MemoryAdapter.prototype.deleteObject = deleteObject; 24 | MemoryAdapter.prototype.getObject = getObject; 25 | MemoryAdapter.prototype.findObjects = findObjects; 26 | 27 | function loadEntity() { 28 | // noop 29 | } 30 | 31 | function loadEntityAttribute() { 32 | // noop 33 | } 34 | 35 | function insertObject(entity) { 36 | var self = this; 37 | return Promise.try(function () { 38 | // find collection name 39 | var collection = _collectionName(entity.Entity); 40 | // initialize possible empty collection 41 | self.store[collection] = self.store[collection] || {}; 42 | // insert object into collection 43 | self.store[collection][entity.id] = entity; 44 | }); 45 | } 46 | 47 | function updateObject(entity) { 48 | // same as insert 49 | return this.insertObject(entity); 50 | } 51 | 52 | function deleteObject(entity) { 53 | var self = this; 54 | return Promise.try(function () { 55 | // find collection name 56 | var collection = _collectionName(entity.Entity); 57 | // initialize possible empty collection 58 | self.store[collection] = self.store[collection] || {}; 59 | // remove object from collection 60 | delete self.store[collection][entity.id]; 61 | }); 62 | } 63 | 64 | function getObject(EntityClass, query) { 65 | return this.findObjects(EntityClass, query) 66 | .then(function (objects) { 67 | // check for number of results 68 | if (!objects || objects.length !== 1) { 69 | throw new Error('Query does not match exactly one object'); 70 | } 71 | // return found object 72 | return objects[0]; 73 | }); 74 | } 75 | 76 | function findObjects(EntityClass, query) { 77 | var self = this; 78 | return Promise.try(function () { 79 | // find collection name 80 | var collection = _collectionName(EntityClass); 81 | // initialize possible empty collection 82 | self.store[collection] = self.store[collection] || {}; 83 | // list all entities in collection 84 | var entities = _values(self.store[collection]); 85 | // filter entities matching query 86 | var filter = _buildFilter(query); 87 | return entities.filter(filter); 88 | }); 89 | } 90 | 91 | /* Private util functions */ 92 | 93 | function _collectionName(EntityClass) { 94 | var Entity = EntityClass; 95 | while (Entity.General !== null && !Entity.General.specification.isAbstract) { 96 | Entity = Entity.General; 97 | } 98 | return Entity.dataName; 99 | } 100 | 101 | function _values(object) { 102 | return Object.keys(object).map(function (key) { 103 | return object[key]; 104 | }); 105 | } 106 | 107 | function _buildFilter(query) { 108 | var attrs = Object.keys(query); 109 | return function (entity) { 110 | try { 111 | attrs.forEach(function (attr) { 112 | if (entity[attr] !== query[attr]) { 113 | throw new Error('Object does not match query'); 114 | } 115 | }); 116 | } catch (e) { 117 | return false; 118 | } 119 | return true; 120 | }; 121 | } 122 | -------------------------------------------------------------------------------- /src/back/adapters/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Adapter = require('./Adapter'); 4 | var MemoryAdapter = require('./MemoryAdapter'); 5 | 6 | /** 7 | * Contains base classes for entities adapters. 8 | * @module back4app-entity/adapters 9 | */ 10 | module.exports = {}; 11 | 12 | module.exports.Adapter = Adapter; 13 | module.exports.MemoryAdapter = MemoryAdapter; 14 | -------------------------------------------------------------------------------- /src/back/index.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils'); 2 | var settings = require('./settings'); 3 | var models = require('./models'); 4 | var adapters = require('./adapters'); 5 | 6 | /** 7 | * Contains all back{4}app's entity implementations. 8 | * @module back4app-entity 9 | */ 10 | module.exports = {}; 11 | 12 | module.exports.utils = utils; 13 | module.exports.settings = settings; 14 | module.exports.models = models; 15 | module.exports.adapters = adapters; 16 | -------------------------------------------------------------------------------- /src/back/models/User.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Entity = require('./Entity'); 4 | var Promise = require('bluebird'); 5 | var bcrypt = require('bcryptjs'); 6 | 7 | module.exports = Entity.specify({ 8 | name: 'User', 9 | 10 | attributes: { 11 | 'username': { 12 | type: 'String', 13 | multiplicity: '1', 14 | default: '' 15 | }, 16 | 'email': { 17 | type: 'String', 18 | multiplicity: '1', 19 | default: '' 20 | }, 21 | 'password': { 22 | type: 'String', 23 | multiplicity: '1', 24 | default: '' 25 | } 26 | }, 27 | 28 | methods: { 29 | 'authenticate': authenticate 30 | }, 31 | 32 | nameValidation: false 33 | 34 | }); 35 | 36 | function authenticate(password) { 37 | var user = this; 38 | return new Promise(function (resolve) { 39 | bcrypt.compare(password, user.password, function (err, res) { 40 | resolve(res); 41 | }); 42 | }); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/back/models/attributes/AttributeDictionary.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var Attribute = require('./Attribute'); 9 | 10 | module.exports = AttributeDictionary; 11 | 12 | /** 13 | * Dictionary of Entity Attributes. 14 | * @constructor 15 | * @memberof module:back4app-entity/models/attributes 16 | * @param {?(module:back4app-entity/models/attributes.Attribute[]| 17 | * Object.)} 19 | * [attributes] The attributes to be added in the dictionary. They can be given 20 | * as an Array or a Dictionary of 21 | * {@link module:back4app-entity/models/attributes.Attribute}. 22 | * @example 23 | * var attributeDictionary = new AttributeDictionary(); 24 | * @example 25 | * var attributeDictionary = new AttributeDictionary(null); 26 | * @example 27 | * var attributeDictionary = new AttributeDictionary({}); 28 | * @example 29 | * var attributeDictionary = new AttributeDictionary({ 30 | * attribute1: new StringAttribute('attribute1'), 31 | * attribute2: new StringAttribute('attribute2') 32 | * }); 33 | */ 34 | function AttributeDictionary(attributes) { 35 | expect(arguments).to.have.length.below( 36 | 2, 37 | 'Invalid arguments length when creating an AttributeDictionary (it has ' + 38 | 'to be passed less than 2 arguments)' 39 | ); 40 | 41 | if (attributes) { 42 | expect(typeof attributes).to.equal( 43 | 'object', 44 | 'Invalid argument type when creating an AttributeDictionary (it has to ' + 45 | 'be an object)' 46 | ); 47 | 48 | if (attributes instanceof Array) { 49 | for (var i = 0; i < attributes.length; i++) { 50 | _addAttribute(this, attributes[i]); 51 | } 52 | } else { 53 | for (var attribute in attributes) { 54 | _addAttribute(this, attributes[attribute], attribute); 55 | } 56 | } 57 | } 58 | 59 | Object.preventExtensions(this); 60 | Object.seal(this); 61 | } 62 | 63 | AttributeDictionary.concat = concat; 64 | 65 | /** 66 | * Adds a new attribute to the dictionary. 67 | * @name 68 | * module:back4app-entity/models/attributes.AttributeDictionary~_addAttribute 69 | * @function 70 | * @param {!module:back4app-entity/models/attributes.AttributeDictionary} 71 | * attributeDictionary It is the attribute dictionary to which the attribute 72 | * will be added. 73 | * @param {!module:back4app-entity/models/attributes.Attribute} attribute This 74 | * is the attribute to be added. It can be passed as a 75 | * {@link module:back4app-entity/models/attributes.Attribute} instance. 76 | * @param {?string} [name] This is the name of the attribute. 77 | * @private 78 | * @example 79 | * var attributeDictionary = new AttributeDictionary(); 80 | * _addAttribute( 81 | * attributeDictionary, 82 | * new StringAttribute('attribute'), 83 | * 'attribute' 84 | * ); 85 | */ 86 | /** 87 | * Adds a new attribute to the dictionary. 88 | * @name 89 | * module:back4app-entity/models/attributes.AttributeDictionary~_addAttribute 90 | * @function 91 | * @param {!module:back4app-entity/models/attributes.AttributeDictionary} 92 | * attributeDictionary It is the attribute dictionary to which the attribute 93 | * will be added. 94 | * @param {!Object} attribute This is the attribute to be added. It can be 95 | * passed as an Object, as specified in 96 | * {@link module:back4app-entity/models/attributes.Attribute}. 97 | * @param {!string} [attribute.name] It is the name of the attribute. It is 98 | * optional if it is passed as an argument in the function. 99 | * @param {!string} [attribute.type='Object'] It is the type of the attribute. 100 | * It is optional and if not passed it will assume 'Object' as the default 101 | * value. 102 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 103 | * attribute. It is optional and if not passed it will assume '1' as the default 104 | * value. 105 | * @param {?(boolean|number|string|Object|function)} [attribute.default] It is 106 | * the default expression of the attribute. 107 | * @param {?string} [name] This is the name of the attribute. 108 | * @private 109 | * @example 110 | * var attributeDictionary = new AttributeDictionary(); 111 | * _addAttribute(attributeDictionary, {}, 'attribute'); 112 | */ 113 | function _addAttribute() { 114 | var attributeDictionary = arguments[0]; 115 | 116 | var attribute = null; 117 | var name = null; 118 | 119 | if (arguments.length === 2) { 120 | attribute = arguments[1]; 121 | } else { 122 | attribute = arguments[1]; 123 | name = arguments[2]; 124 | } 125 | 126 | expect(attribute).to.be.an( 127 | 'object', 128 | 'Invalid argument type when adding an attribute ' + (name ? 'called "' + 129 | name + '" ' : '') + 'in an AttributeDictionary (it has to be an object)' 130 | ); 131 | 132 | if (name) { 133 | if (attribute.name) { 134 | expect(attribute.name).to.equal( 135 | name, 136 | 'Invalid argument "name" when adding an attribute called "' + 137 | attribute.name + '" in an AttributeDictionary (the name given in ' + 138 | 'argument and the name given in the attribute object should be equal)' 139 | ); 140 | } else { 141 | attribute.name = name; 142 | } 143 | } 144 | 145 | if (!(attribute instanceof Attribute)) { 146 | attribute = Attribute.resolve(attribute); 147 | } 148 | 149 | expect(attribute.constructor).to.not.equal( 150 | Attribute, 151 | 'Invalid attribute "' + attribute.name + '". Attribute is an abstract ' + 152 | 'class and cannot be directly instantiated and added in an ' + 153 | 'AttributeDictionary' 154 | ); 155 | 156 | expect(attributeDictionary).to.not.have.ownProperty( 157 | attribute.name, 158 | 'Duplicated attribute name "' + attribute.name + '"' 159 | ); 160 | 161 | Object.defineProperty(attributeDictionary, attribute.name, { 162 | value: attribute, 163 | enumerable: true, 164 | writable: false, 165 | configurable: false 166 | }); 167 | } 168 | 169 | /** 170 | * Concatenates an AttributeDictionary instance with an Attribute instance and 171 | * returns a new AttributeDictionary. 172 | * @name module:back4app-entity/models/attributes.AttributeDictionary.concat 173 | * @function 174 | * @param {!module:back4app-entity/models/attributes.AttributeDictionary} 175 | * attributeDictionary The AttributeDictionary to be concatenated. 176 | * @param {!module:back4app-entity/models/attributes.Attribute} attribute 177 | * The Attribute to be concatenated. 178 | * @returns {module:back4app-entity/models/attributes.AttributeDictionary} The 179 | * new concatenated AttributeDictionary. 180 | * @example 181 | * var concatenatedAttributeDictionary = AttributeDictionary.concat( 182 | * attributeDictionary, 183 | * attribute 184 | * ); 185 | */ 186 | function concat(attributeDictionary, attribute) { 187 | expect(arguments).to.have.length( 188 | 2, 189 | 'Invalid arguments length when concatenating an AttributeDictionary (it ' + 190 | 'has to be passed 2 arguments)' 191 | ); 192 | 193 | expect(attributeDictionary).to.be.instanceof( 194 | AttributeDictionary, 195 | 'Invalid argument "attributeDictionary" when concatenating an ' + 196 | 'AttributeDictionary (it has to be an AttributeDictionary)' 197 | ); 198 | 199 | expect(attribute).to.be.instanceof( 200 | Attribute, 201 | 'Invalid argument "attribute" when concatenating an AttributeDictionary ' + 202 | '(it has to be an Attribute)' 203 | ); 204 | 205 | var currentAttributes = []; 206 | 207 | for (var currentAttribute in attributeDictionary) { 208 | currentAttributes.push(attributeDictionary[currentAttribute]); 209 | } 210 | 211 | currentAttributes.push(attribute); 212 | 213 | return new AttributeDictionary(currentAttributes); 214 | } 215 | -------------------------------------------------------------------------------- /src/back/models/attributes/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 30/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var Attribute = require('./Attribute'); 8 | var AttributeDictionary = require('./AttributeDictionary'); 9 | var types = require('./types'); 10 | 11 | /** 12 | * Contains base classes for entity attributes modelling. 13 | * @module back4app-entity/models/attributes 14 | */ 15 | module.exports = {}; 16 | 17 | module.exports.Attribute = Attribute; 18 | module.exports.AttributeDictionary = AttributeDictionary; 19 | module.exports.types = types; 20 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/AssociationAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 10/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var classes = require('../../../utils/classes'); 9 | var objects = require('../../../utils/objects'); 10 | var models = require('../../index'); 11 | var ValidationError = require('../../errors').ValidationError; 12 | var Attribute = require('../Attribute'); 13 | 14 | module.exports = AssociationAttribute; 15 | 16 | /** 17 | * Implementation of an Entity Attribute to store association data. 18 | * @memberof module:back4app-entity/models/attributes/types 19 | * @name AssociationAttribute 20 | * @constructor 21 | * @extends module:back4app-entity/models/attributes.Attribute 22 | * @param {!Object} attribute This is the attribute to be added. It can be 23 | * passed as an Object. 24 | * @param {!string} attribute.name It is the name of the attribute. 25 | * @param {!(string|Class)} attribute.entity It is the 26 | * Entity that is associated with the current AssociationAttribute. 27 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 28 | * attribute. It is optional and if not passed it will assume '1' as the default 29 | * value. 30 | * @param {?Object} [attribute.default] It is 31 | * the default expression of the attribute. 32 | * @param {?(string|Object.)} [attribute.dataName] It is the 33 | * name to be used to stored the attribute data in the repository. It can be 34 | * given as a string that will be used by all adapters or as a dictionary 35 | * specifying the data name for each adapter. If dataName is not given, the 36 | * attribute's name will be used instead. 37 | * @example 38 | * var associationAttribute = new AssociationAttribute({ 39 | * name: 'associationAttribute', 40 | * entity: 'MyEntity', 41 | * multiplicity: '0..1', 42 | * default: null, 43 | * dataName: { 44 | * mongodb: 'mongodbAttribute' 45 | * } 46 | * }); 47 | */ 48 | /** 49 | * Implementation of an Entity Attribute to store association data. 50 | * @memberof module:back4app-entity/models/attributes/types 51 | * @name AssociationAttribute 52 | * @constructor 53 | * @extends module:back4app-entity/models/attributes.Attribute 54 | * @param {!string} name It is the name of the attribute. 55 | * @param {!(string|Class)} entity It is the Entity that 56 | * is associated with the current AssociationAttribute. 57 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 58 | * It is optional and if not passed it will assume '1' as the default value. 59 | * @param {?Object} [default] It is the default 60 | * expression of the attribute. 61 | * @param {?(string|Object.)} [dataName] It is the name to be 62 | * used to stored the attribute data in the repository. It can be given as a 63 | * string that will be used by all adapters or as a dictionary specifying the 64 | * data name for each adapter. If dataName is not given, the attribute's name 65 | * will be used instead. 66 | * @example 67 | * var associationAttribute = new AssociationAttribute( 68 | * 'associationAttribute', 69 | * 'MyEntity', 70 | * '0..1', 71 | * null, 72 | * { 73 | * mongodb: 'mongodbAttribute' 74 | * } 75 | * ); 76 | */ 77 | function AssociationAttribute() { 78 | /** 79 | * It is a readonly property with the Entity that is associated with the 80 | * current AssociationAttribute. 81 | * @name 82 | * module:back4app-entity/models/attributes/types.AssociationAttribute#Entity 83 | * @type {!Class} 84 | * @readonly 85 | * @throws {module:back4app-entity/models/errors.EntityNotFoundError} 86 | * @example 87 | * var associationAttribute = new AssociationAttribute( 88 | * 'associationAttribute', 89 | * MyEntity 90 | * ); 91 | * console.log(associationAttribute.Entity == MyEntity) // Logs "true" 92 | */ 93 | this.Entity = null; 94 | 95 | var _Entity = null; 96 | Object.defineProperty(this, 'Entity', { 97 | get: function () { 98 | if (typeof _Entity === 'string') { 99 | _Entity = models.Entity.getSpecialization(_Entity); 100 | } 101 | 102 | return _Entity; 103 | }, 104 | set: function () { 105 | throw new Error( 106 | 'Entity property of an AssociationAttribute instance cannot be changed' 107 | ); 108 | }, 109 | enumerable: true, 110 | configurable: false 111 | }); 112 | 113 | var argumentsArray = Array.prototype.slice.call(arguments); 114 | 115 | expect(argumentsArray).to.have.length.within( 116 | 1, 117 | 5, 118 | 'Invalid arguments length when creating an AssociationAttribute (it has ' + 119 | 'to be passed from 1 to 5 arguments)' 120 | ); 121 | 122 | if (argumentsArray.length === 1) { 123 | var associationAttribute = argumentsArray[0]; 124 | 125 | expect(associationAttribute).to.be.an( 126 | 'object', 127 | 'Invalid argument type when creating an Attribute (it has to be an ' + 128 | 'object)' 129 | ); 130 | 131 | associationAttribute = objects.copy(associationAttribute); 132 | 133 | _Entity = associationAttribute.entity; 134 | if (_Entity) { 135 | delete associationAttribute.entity; 136 | } else { 137 | expect(associationAttribute).to.have.ownProperty( 138 | 'Entity', 139 | 'Property "entity" or "Entity" is required when creating an ' + 140 | 'AssociationAttribute' 141 | ); 142 | 143 | _Entity = associationAttribute.Entity; 144 | delete associationAttribute.Entity; 145 | } 146 | 147 | argumentsArray[0] = associationAttribute; 148 | } else { 149 | _Entity = argumentsArray.splice(1, 1)[0]; 150 | } 151 | 152 | if (typeof _Entity !== 'string') { 153 | expect(_Entity).to.be.a( 154 | 'function', 155 | 'Invalid argument "entity" when creating an AssociationAttribute (it ' + 156 | 'has to be a Class)' 157 | ); 158 | 159 | expect(classes.isGeneral(models.Entity, _Entity)).to.equal( 160 | true, 161 | 'Invalid argument "entity" when creating an AssociationAttribute (it ' + 162 | 'has to be a subclass of Entity)' 163 | ); 164 | } 165 | 166 | Attribute.apply(this, argumentsArray); 167 | } 168 | 169 | classes.generalize(Attribute, AssociationAttribute); 170 | 171 | AssociationAttribute.typeName = 'Association'; 172 | 173 | AssociationAttribute.prototype.validateValue = validateValue; 174 | AssociationAttribute.prototype.getDataValue = getDataValue; 175 | AssociationAttribute.prototype.parseDataValue = parseDataValue; 176 | 177 | function validateValue(value) { 178 | if (value instanceof this.Entity) { 179 | value.validate(); 180 | } else { 181 | throw new ValidationError( 182 | 'this attribute\'s value should be a "' + 183 | this.Entity.specification.name + 184 | '"' 185 | ); 186 | } 187 | } 188 | 189 | function getDataValue(attributeValue) { 190 | expect(arguments).to.have.length( 191 | 1, 192 | 'Invalid arguments length when getting the data value of an Attribute ' + 193 | '(it has to be passed 1 argument)'); 194 | 195 | var dataValue = attributeValue; 196 | 197 | if (attributeValue instanceof models.Entity) { 198 | dataValue = { 199 | Entity: attributeValue.Entity.specification.name, 200 | id: attributeValue.id 201 | }; 202 | } else if (attributeValue instanceof Array) { 203 | dataValue = []; 204 | 205 | for (var i = 0; i < attributeValue.length; i++) { 206 | if (attributeValue[i] instanceof models.Entity) { 207 | dataValue.push({ 208 | Entity: attributeValue[i].Entity.specification.name, 209 | id: attributeValue[i].id 210 | }); 211 | } else { 212 | dataValue.push(attributeValue[i]); 213 | } 214 | } 215 | } 216 | 217 | return dataValue; 218 | } 219 | 220 | function parseDataValue(dataValue) { 221 | expect(arguments).to.have.length( 222 | 1, 223 | 'Invalid arguments length when parsing the data value of an Attribute ' + 224 | '(it has to be passed 1 argument)'); 225 | 226 | var attributeValue = dataValue; 227 | 228 | if (dataValue instanceof Array) { 229 | attributeValue = []; 230 | for (var i = 0; i < dataValue.length; i++) { 231 | attributeValue.push(_parseDataValueItem(dataValue[i])); 232 | } 233 | } else { 234 | attributeValue = _parseDataValueItem(dataValue); 235 | } 236 | 237 | return attributeValue; 238 | 239 | function _parseDataValueItem(dataValueItem) { 240 | if (typeof dataValueItem === 'object' && dataValueItem !== null) { 241 | try { 242 | var dataValueItemCopy = objects.copy(dataValueItem); 243 | var newFunction = models.Entity.new(dataValueItemCopy.Entity); 244 | delete dataValueItemCopy.Entity; 245 | return newFunction(dataValueItemCopy); 246 | } catch (error) { 247 | return dataValueItem; 248 | } 249 | } else { 250 | return dataValueItem; 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/BooleanAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var classes = require('../../../utils/classes'); 8 | var ValidationError = require('../../errors').ValidationError; 9 | var Attribute = require('../Attribute'); 10 | 11 | module.exports = BooleanAttribute; 12 | 13 | /** 14 | * Implementation of an Entity Attribute to store boolean data. 15 | * @memberof module:back4app-entity/models/attributes/types 16 | * @name BooleanAttribute 17 | * @constructor 18 | * @extends module:back4app-entity/models/attributes.Attribute 19 | * @param {!Object} attribute This is the attribute to be added. It can be 20 | * passed as an Object. 21 | * @param {!string} attribute.name It is the name of the attribute. 22 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 23 | * attribute. It is optional and if not passed it will assume '1' as the default 24 | * value. 25 | * @param {?boolean} [attribute.default] It is 26 | * the default expression of the attribute. 27 | * @param {?(string|Object.)} [attribute.dataName] It is the 28 | * name to be used to stored the attribute data in the repository. It can be 29 | * given as a string that will be used by all adapters or as a dictionary 30 | * specifying the data name for each adapter. If dataName is not given, the 31 | * attribute's name will be used instead. 32 | * @example 33 | * var booleanAttribute = new BooleanAttribute({ 34 | * name: 'booleanAttribute', 35 | * multiplicity: '0..1', 36 | * default: null, 37 | * dataName: { 38 | * mongodb: 'mongodbAttribute' 39 | * } 40 | * }); 41 | */ 42 | /** 43 | * Implementation of an Entity Attribute to store boolean data. 44 | * @memberof module:back4app-entity/models/attributes/types 45 | * @name BooleanAttribute 46 | * @constructor 47 | * @extends module:back4app-entity/models/attributes.Attribute 48 | * @param {!string} name It is the name of the attribute. 49 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 50 | * It is optional and if not passed it will assume '1' as the default value. 51 | * @param {?boolean} [default] It is the default 52 | * expression of the attribute. 53 | * @param {?(string|Object.)} [dataName] It is the name to be 54 | * used to stored the attribute data in the repository. It can be given as a 55 | * string that will be used by all adapters or as a dictionary specifying the 56 | * data name for each adapter. If dataName is not given, the attribute's name 57 | * will be used instead. 58 | * @example 59 | * var booleanAttribute = new BooleanAttribute( 60 | * 'booleanAttribute', 61 | * '0..1', 62 | * null, 63 | * { 64 | * mongodb: 'mongodbAttribute' 65 | * } 66 | * ); 67 | */ 68 | function BooleanAttribute() { 69 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 70 | } 71 | 72 | classes.generalize(Attribute, BooleanAttribute); 73 | 74 | BooleanAttribute.typeName = 'Boolean'; 75 | 76 | BooleanAttribute.prototype.validateValue = validateValue; 77 | 78 | function validateValue(value) { 79 | if (typeof value !== 'boolean') { 80 | throw new ValidationError( 81 | 'this attribute\'s value should be a boolean' 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/DateAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var classes = require('../../../utils/classes'); 9 | var ValidationError = require('../../errors').ValidationError; 10 | var Attribute = require('../Attribute'); 11 | 12 | module.exports = DateAttribute; 13 | 14 | /** 15 | * Implementation of an Entity Attribute to store Date data. 16 | * @memberof module:back4app-entity/models/attributes/types 17 | * @name DateAttribute 18 | * @constructor 19 | * @extends module:back4app-entity/models/attributes.Attribute 20 | * @param {!Object} attribute This is the attribute to be added. It can be 21 | * passed as an Object. 22 | * @param {!string} attribute.name It is the name of the attribute. 23 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 24 | * attribute. It is optional and if not passed it will assume '1' as the default 25 | * value. 26 | * @param {?Date} [attribute.default] It is 27 | * the default expression of the attribute. 28 | * @param {?(string|Object.)} [attribute.dataName] It is the 29 | * name to be used to stored the attribute data in the repository. It can be 30 | * given as a string that will be used by all adapters or as a dictionary 31 | * specifying the data name for each adapter. If dataName is not given, the 32 | * attribute's name will be used instead. 33 | * @example 34 | * var dateAttribute = new DateAttribute({ 35 | * name: 'dateAttribute', 36 | * multiplicity: '0..1', 37 | * default: null, 38 | * dataName: { 39 | * mongodb: 'mongodbAttribute' 40 | * } 41 | * }); 42 | */ 43 | /** 44 | * Implementation of an Entity Attribute to store Date data. 45 | * @memberof module:back4app-entity/models/attributes/types 46 | * @name DateAttribute 47 | * @constructor 48 | * @extends module:back4app-entity/models/attributes.Attribute 49 | * @param {!string} name It is the name of the attribute. 50 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 51 | * It is optional and if not passed it will assume '1' as the default value. 52 | * @param {?Date} [default] It is the default 53 | * expression of the attribute. 54 | * @param {?(string|Object.)} [dataName] It is the name to be 55 | * used to stored the attribute data in the repository. It can be given as a 56 | * string that will be used by all adapters or as a dictionary specifying the 57 | * data name for each adapter. If dataName is not given, the attribute's name 58 | * will be used instead. 59 | * @example 60 | * var dateAttribute = new DateAttribute( 61 | * 'dateAttribute', 62 | * '0..1', 63 | * null, 64 | * { 65 | * mongodb: 'mongodbAttribute' 66 | * } 67 | * ); 68 | */ 69 | function DateAttribute() { 70 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 71 | } 72 | 73 | classes.generalize(Attribute, DateAttribute); 74 | 75 | DateAttribute.typeName = 'Date'; 76 | 77 | DateAttribute.prototype.validateValue = validateValue; 78 | DateAttribute.prototype.parseDataValue = parseDataValue; 79 | 80 | function validateValue(value) { 81 | if (!(value instanceof Date) || isNaN(value.getTime())) { 82 | throw new ValidationError( 83 | 'this attribute\'s value should be a Date' 84 | ); 85 | } 86 | } 87 | 88 | function parseDataValue(dataValue) { 89 | expect(arguments).to.have.length( 90 | 1, 91 | 'Invalid arguments length when parsing the data value of an Attribute ' + 92 | '(it has to be passed 1 argument)'); 93 | 94 | var attributeValue = dataValue; 95 | if (dataValue instanceof Array) { 96 | attributeValue = []; 97 | for (var i = 0; i < dataValue.length; i++) { 98 | attributeValue.push(_parseDataValueItem(dataValue[i])); 99 | } 100 | } else { 101 | attributeValue = _parseDataValueItem(dataValue); 102 | } 103 | return attributeValue; 104 | 105 | function _parseDataValueItem(dataValueItem) { 106 | if (typeof dataValueItem === 'string' && dataValueItem !== null) { 107 | try { 108 | var date = new Date(dataValueItem); 109 | if (isNaN(date.getTime())) { 110 | return dataValueItem; 111 | } else { 112 | return date; 113 | } 114 | } catch (error) { 115 | return dataValueItem; 116 | } 117 | } else { 118 | return dataValueItem; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/NumberAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var classes = require('../../../utils/classes'); 8 | var ValidationError = require('../../errors').ValidationError; 9 | var Attribute = require('../Attribute'); 10 | 11 | module.exports = NumberAttribute; 12 | 13 | /** 14 | * Implementation of an Entity Attribute to store number data. 15 | * @memberof module:back4app-entity/models/attributes/types 16 | * @name NumberAttribute 17 | * @constructor 18 | * @extends module:back4app-entity/models/attributes.Attribute 19 | * @param {!Object} attribute This is the attribute to be added. It can be 20 | * passed as an Object. 21 | * @param {!string} attribute.name It is the name of the attribute. 22 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 23 | * attribute. It is optional and if not passed it will assume '1' as the default 24 | * value. 25 | * @param {?number} [attribute.default] It is 26 | * the default expression of the attribute. 27 | * @param {?(string|Object.)} [attribute.dataName] It is the 28 | * name to be used to stored the attribute data in the repository. It can be 29 | * given as a string that will be used by all adapters or as a dictionary 30 | * specifying the data name for each adapter. If dataName is not given, the 31 | * attribute's name will be used instead. 32 | * @example 33 | * var numberAttribute = new NumberAttribute({ 34 | * name: 'numberAttribute', 35 | * multiplicity: '0..1', 36 | * default: null, 37 | * dataName: { 38 | * mongodb: 'mongodbAttribute' 39 | * } 40 | * }); 41 | */ 42 | /** 43 | * Implementation of an Entity Attribute to store number data. 44 | * @memberof module:back4app-entity/models/attributes/types 45 | * @name NumberAttribute 46 | * @constructor 47 | * @extends module:back4app-entity/models/attributes.Attribute 48 | * @param {!string} name It is the name of the attribute. 49 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 50 | * It is optional and if not passed it will assume '1' as the default value. 51 | * @param {?number} [default] It is the default 52 | * expression of the attribute. 53 | * @param {?(string|Object.)} [dataName] It is the name to be 54 | * used to stored the attribute data in the repository. It can be given as a 55 | * string that will be used by all adapters or as a dictionary specifying the 56 | * data name for each adapter. If dataName is not given, the attribute's name 57 | * will be used instead. 58 | * @example 59 | * var numberAttribute = new NumberAttribute( 60 | * 'numberAttribute', 61 | * '0..1', 62 | * null, 63 | * { 64 | * mongodb: 'mongodbAttribute' 65 | * } 66 | * ); 67 | */ 68 | function NumberAttribute() { 69 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 70 | } 71 | 72 | classes.generalize(Attribute, NumberAttribute); 73 | 74 | NumberAttribute.typeName = 'Number'; 75 | 76 | NumberAttribute.prototype.validateValue = validateValue; 77 | 78 | function validateValue(value) { 79 | if (typeof value !== 'number' && !(value instanceof Number)) { 80 | throw new ValidationError( 81 | 'this attribute\'s value should be a number' 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/ObjectAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var classes = require('../../../utils/classes'); 8 | var ValidationError = require('../../errors').ValidationError; 9 | var Attribute = require('../Attribute'); 10 | 11 | module.exports = ObjectAttribute; 12 | 13 | /** 14 | * Implementation of an Entity Attribute to store Object data. 15 | * @memberof module:back4app-entity/models/attributes/types 16 | * @name ObjectAttribute 17 | * @constructor 18 | * @extends module:back4app-entity/models/attributes.Attribute 19 | * @param {!Object} attribute This is the attribute to be added. It can be 20 | * passed as an Object. 21 | * @param {!string} attribute.name It is the name of the attribute. 22 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 23 | * attribute. It is optional and if not passed it will assume '1' as the default 24 | * value. 25 | * @param {?Object} [attribute.default] It is 26 | * the default expression of the attribute. 27 | * @param {?(string|Object.)} [attribute.dataName] It is the 28 | * name to be used to stored the attribute data in the repository. It can be 29 | * given as a string that will be used by all adapters or as a dictionary 30 | * specifying the data name for each adapter. If dataName is not given, the 31 | * attribute's name will be used instead. 32 | * @example 33 | * var objectAttribute = new ObjectAttribute({ 34 | * name: 'objectAttribute', 35 | * multiplicity: '0..1', 36 | * default: null, 37 | * dataName: { 38 | * mongodb: 'mongodbAttribute' 39 | * } 40 | * }); 41 | */ 42 | /** 43 | * Implementation of an Entity Attribute to store Object data. 44 | * @memberof module:back4app-entity/models/attributes/types 45 | * @name ObjectAttribute 46 | * @constructor 47 | * @extends module:back4app-entity/models/attributes.Attribute 48 | * @param {!string} name It is the name of the attribute. 49 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 50 | * It is optional and if not passed it will assume '1' as the default value. 51 | * @param {?Object} [default] It is the default 52 | * expression of the attribute. 53 | * @param {?(string|Object.)} [dataName] It is the name to be 54 | * used to stored the attribute data in the repository. It can be given as a 55 | * string that will be used by all adapters or as a dictionary specifying the 56 | * data name for each adapter. If dataName is not given, the attribute's name 57 | * will be used instead. 58 | * @example 59 | * var objectAttribute = new ObjectAttribute( 60 | * 'objectAttribute', 61 | * '0..1', 62 | * null, 63 | * { 64 | * mongodb: 'mongodbAttribute' 65 | * } 66 | * ); 67 | */ 68 | function ObjectAttribute() { 69 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 70 | } 71 | 72 | classes.generalize(Attribute, ObjectAttribute); 73 | 74 | ObjectAttribute.typeName = 'Object'; 75 | 76 | ObjectAttribute.prototype.validateValue = validateValue; 77 | 78 | function validateValue(value) { 79 | if (value === null || typeof value !== 'object') { 80 | throw new ValidationError( 81 | 'this attribute\'s value should be an object' 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/StringAttribute.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var classes = require('../../../utils/classes'); 8 | var ValidationError = require('../../errors').ValidationError; 9 | var Attribute = require('../Attribute'); 10 | 11 | module.exports = StringAttribute; 12 | 13 | /** 14 | * Implementation of an Entity Attribute to store string data. 15 | * @memberof module:back4app-entity/models/attributes/types 16 | * @name StringAttribute 17 | * @constructor 18 | * @extends module:back4app-entity/models/attributes.Attribute 19 | * @param {!Object} attribute This is the attribute to be added. It can be 20 | * passed as an Object. 21 | * @param {!string} attribute.name It is the name of the attribute. 22 | * @param {!string} [attribute.multiplicity='1'] It is the multiplicity of the 23 | * attribute. It is optional and if not passed it will assume '1' as the default 24 | * value. 25 | * @param {?string} [attribute.default] It is 26 | * the default expression of the attribute. 27 | * @param {?(string|Object.)} [attribute.dataName] It is the 28 | * name to be used to stored the attribute data in the repository. It can be 29 | * given as a string that will be used by all adapters or as a dictionary 30 | * specifying the data name for each adapter. If dataName is not given, the 31 | * attribute's name will be used instead. 32 | * @example 33 | * var stringAttribute = new StringAttribute({ 34 | * name: 'stringAttribute', 35 | * multiplicity: '0..1', 36 | * default: null, 37 | * dataName: { 38 | * mongodb: 'mongodbAttribute' 39 | * } 40 | * }); 41 | */ 42 | /** 43 | * Implementation of an Entity Attribute to store string data. 44 | * @memberof module:back4app-entity/models/attributes/types 45 | * @name StringAttribute 46 | * @constructor 47 | * @extends module:back4app-entity/models/attributes.Attribute 48 | * @param {!string} name It is the name of the attribute. 49 | * @param {!string} [multiplicity='1'] It is the multiplicity of the attribute. 50 | * It is optional and if not passed it will assume '1' as the default value. 51 | * @param {?string} [default] It is the default 52 | * expression of the attribute. 53 | * @param {?(string|Object.)} [dataName] It is the name to be 54 | * used to stored the attribute data in the repository. It can be given as a 55 | * string that will be used by all adapters or as a dictionary specifying the 56 | * data name for each adapter. If dataName is not given, the attribute's name 57 | * will be used instead. 58 | * @example 59 | * var stringAttribute = new StringAttribute( 60 | * 'stringAttribute', 61 | * '0..1', 62 | * null, 63 | * { 64 | * mongodb: 'mongodbAttribute' 65 | * } 66 | * ); 67 | */ 68 | function StringAttribute() { 69 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 70 | } 71 | 72 | classes.generalize(Attribute, StringAttribute); 73 | 74 | StringAttribute.typeName = 'String'; 75 | 76 | StringAttribute.prototype.validateValue = validateValue; 77 | 78 | function validateValue(value) { 79 | if (typeof value !== 'string' && !(value instanceof String)) { 80 | throw new ValidationError( 81 | 'this attribute\'s value should be a string' 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/back/models/attributes/types/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var AttributeTypeNotFoundError = require('../../errors') 9 | .AttributeTypeNotFoundError; 10 | var AssociationAttribute = require('./AssociationAttribute'); 11 | var BooleanAttribute = require('./BooleanAttribute'); 12 | var DateAttribute = require('./DateAttribute'); 13 | var NumberAttribute = require('./NumberAttribute'); 14 | var ObjectAttribute = require('./ObjectAttribute'); 15 | var StringAttribute = require('./StringAttribute'); 16 | 17 | /** 18 | * Contains specializations of the Attribute class to be used as types of 19 | * attributes. 20 | * @module back4app-entity/models/attributes/types 21 | */ 22 | module.exports = {}; 23 | 24 | module.exports.AssociationAttribute = AssociationAttribute; 25 | module.exports.BooleanAttribute = BooleanAttribute; 26 | module.exports.DateAttribute = DateAttribute; 27 | module.exports.NumberAttribute = NumberAttribute; 28 | module.exports.ObjectAttribute = ObjectAttribute; 29 | module.exports.StringAttribute = StringAttribute; 30 | 31 | module.exports.get = null; 32 | 33 | require('../index').types = module.exports; 34 | 35 | Object.defineProperty(module.exports, 'get', { 36 | value: get, 37 | enumerable: false, 38 | writable: false, 39 | configurable: true 40 | }); 41 | 42 | /** 43 | * Gets an Attribute type by a given string representing the type. First, it 44 | * tries to find the exactly name. If not find, it tries concatenates the given 45 | * string with "Attribute" in the end and tries again. If it still cannot find, 46 | * it throws an 47 | * {@link module:back4app-entity/models/errors.AttributeTypeNotFoundError}. 48 | * @name module:back4app-entity/models/attributes/types~get 49 | * @function 50 | * @param {!string} type The name of type to be get. 51 | * @returns {Class} The Attribute type class. 52 | * @throws {module:back4app-entity/models/errors.AttributeTypeNotFoundError} 53 | * @example 54 | * var ObjectAttribute = types.get('ObjectAttribute); 55 | */ 56 | function get(type) { 57 | expect(arguments).to.have.length( 58 | 1, 59 | 'Invalid arguments length when getting an Attribute type (it has to be ' + 60 | 'passed 1 argument)' 61 | ); 62 | 63 | expect(type).to.be.a( 64 | 'string', 65 | 'Invalid argument "type" when getting an Attribute type (it has to be a ' + 66 | 'string' 67 | ); 68 | 69 | if (module.exports.hasOwnProperty(type)) { 70 | return module.exports[type]; 71 | } else if (module.exports.hasOwnProperty(type + 'Attribute')) { 72 | return module.exports[type + 'Attribute']; 73 | } else { 74 | throw new AttributeTypeNotFoundError(type); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/back/models/errors.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 30/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var util = require('util'); 8 | var expect = require('chai').expect; 9 | 10 | /** 11 | * Contains Error Classes used to be thrown when the models API is not used 12 | * correctly. 13 | * @module back4app-entity/models/errors 14 | */ 15 | module.exports = {}; 16 | 17 | module.exports.EntityNotFoundError = EntityNotFoundError; 18 | module.exports.AttributeTypeNotFoundError = AttributeTypeNotFoundError; 19 | module.exports.ValidationError = ValidationError; 20 | module.exports.AdapterNotFoundError = AdapterNotFoundError; 21 | module.exports.NotFetchedError = NotFetchedError; 22 | 23 | /** 24 | * Error class to be used when an Entity was referenced and the platform was not 25 | * able to find it. 26 | * @constructor 27 | * @extends Error 28 | * @param {?string} [entity] The entity name to be displayed. 29 | * @param {?Error} [innerError] The inner error. 30 | * @memberof module:back4app-entity/models/errors 31 | * @example 32 | * try { 33 | * var myEntity = require('./MyEntity'); 34 | * } 35 | * catch (e) { 36 | * throw new EntityNotFoundError('MyEntity', e); 37 | * } 38 | */ 39 | function EntityNotFoundError(entity, innerError) { 40 | /** 41 | * The name of the entity that was not found. 42 | * @type {?string} 43 | */ 44 | this.entity = entity; 45 | /** 46 | * The inner error that generated the current error. 47 | * @type {?Error} 48 | */ 49 | this.innerError = innerError; 50 | 51 | expect(arguments).to.have.length.below( 52 | 3, 53 | 'Invalid arguments length when creating a new EntityNotFoundError (it ' + 54 | 'has to be passed less than 3 arguments)' 55 | ); 56 | 57 | this.name = 'EntityNotFoundError'; 58 | 59 | this.message = 'Cannot find Entity'; 60 | if (entity) { 61 | expect(entity).to.be.a( 62 | 'string', 63 | 'Invalid argument "entity" when creating a new EntityNotFoundError ' + 64 | '(it has to be a string)' 65 | ); 66 | this.message += ' "' + entity + '"'; 67 | } 68 | 69 | this.stack = (new Error(this.message)).stack; 70 | if (innerError) { 71 | expect(innerError).to.be.an.instanceof( 72 | Error, 73 | 'Invalid argument "innerError" when creating a new EntityNotFoundError ' + 74 | '(it has to be an Error)' 75 | ); 76 | this.stack += '\n\n' + innerError.stack; 77 | } 78 | } 79 | 80 | util.inherits(EntityNotFoundError, Error); 81 | 82 | /** 83 | * Error class to be used when an Attribute type was referenced and the platform 84 | * was not able to find it. 85 | * @constructor 86 | * @extends Error 87 | * @param {?string} [type] The attribute type name to be displayed. 88 | * @param {?Error} [innerError] The inner error. 89 | * @memberof module:back4app-entity/models/errors 90 | * @example 91 | * try { 92 | * var TypedAttribute = types.get('MyCustomAttribute'); 93 | * } 94 | * catch (e) { 95 | * throw new AttributeTypeNotFoundError('MyCustomAttribute', e); 96 | * } 97 | */ 98 | function AttributeTypeNotFoundError(type, innerError) { 99 | /** 100 | * The attribute type that was not found. 101 | * @type {?string} 102 | */ 103 | this.type = type; 104 | /** 105 | * The inner error that generated the current error. 106 | * @type {?Error} 107 | */ 108 | this.innerError = innerError; 109 | 110 | expect(arguments).to.have.length.below( 111 | 3, 112 | 'Invalid arguments length when creating a new ' + 113 | 'AttributeTypeNotFoundError (it has to be passed less than 3 arguments)' 114 | ); 115 | 116 | this.name = 'AttributeTypeNotFoundError'; 117 | 118 | this.message = 'Cannot find Attribute type'; 119 | if (type) { 120 | expect(type).to.be.a( 121 | 'string', 122 | 'Invalid argument "type" when creating a new ' + 123 | 'AttributeTypeNotFoundError (it has to be a string)' 124 | ); 125 | this.message += ' "' + type + '"'; 126 | } 127 | 128 | this.stack = (new Error(this.message)).stack; 129 | if (innerError) { 130 | expect(innerError).to.be.an.instanceof( 131 | Error, 132 | 'Invalid argument "innerError" when creating a new ' + 133 | 'AttributeTypeNotFoundError (it has to be an Error)' 134 | ); 135 | this.stack += '\n\n' + innerError.stack; 136 | } 137 | } 138 | 139 | util.inherits(AttributeTypeNotFoundError, Error); 140 | 141 | /** 142 | * Error class to be used when an attribute value was not fetched yet and it 143 | * was required. 144 | * @constructor 145 | * @extends Error 146 | * @param {?string} [entity] The entity whose attribute is not fetched. 147 | * @param {?string} [attribute] The attribute that is not fetched. 148 | * @param {?Error} [innerError] The inner error. 149 | * @memberof module:back4app-entity/models/errors 150 | * @example 151 | * try 152 | * { 153 | * throw new NotFetchedError( 154 | * 'MyEntity', 155 | * 'myAttribute', 156 | * null 157 | * ); 158 | * } catch(e) { 159 | * console.log(e.message); // Logs "Error when getting an attribute called 160 | * // "myAttribute" of an entity called "MyEntity": 161 | * // this attribute was not fetched yet" 162 | * } 163 | */ 164 | function NotFetchedError( 165 | entity, 166 | attribute, 167 | innerError 168 | ) { 169 | /** 170 | * The name of the entity whose attribute is not fetched. 171 | * @type {?string} 172 | */ 173 | this.entity = entity; 174 | /** 175 | * The name of the attribute that was not fetched. 176 | * @type {?string} 177 | */ 178 | this.attribute = attribute; 179 | /** 180 | * The inner error that generated the current error. 181 | * @type {?Error} 182 | */ 183 | this.innerError = innerError; 184 | 185 | expect(arguments).to.have.length.below( 186 | 4, 187 | 'Invalid arguments length when creating a new ' + 188 | 'NotFetchedError (it has to be passed less than 4 arguments)' 189 | ); 190 | 191 | this.name = 'NotFetchedError'; 192 | 193 | this.message = 'Error when getting an attribute'; 194 | if (attribute) { 195 | expect(attribute).to.be.a( 196 | 'string', 197 | 'Invalid argument "attribute" when creating a new ValidationError (it ' + 198 | 'has to be a string)' 199 | ); 200 | this.message += ' called "' + attribute + '"'; 201 | } 202 | 203 | this.message += ' of an entity'; 204 | if (entity) { 205 | expect(entity).to.be.a( 206 | 'string', 207 | 'Invalid argument "entity" when creating a new ValidationError (it has ' + 208 | 'to be a string)' 209 | ); 210 | this.message += ' called "' + entity + '"'; 211 | } 212 | 213 | this.message += ': this attribute was not fetched yet'; 214 | 215 | this.stack = (new Error(this.message)).stack; 216 | if (innerError) { 217 | expect(innerError).to.be.an.instanceof( 218 | Error, 219 | 'Invalid argument "innerError" when creating a new ' + 220 | 'ValidationError (it has to be an Error)' 221 | ); 222 | this.stack += '\n\n' + innerError.stack; 223 | } 224 | } 225 | 226 | util.inherits(NotFetchedError, Error); 227 | 228 | /** 229 | * Error class to be used when an attribute value is not valid for the attribute 230 | * specification. 231 | * @constructor 232 | * @extends Error 233 | * @param {?string} [validationMessage] The message explaining the validation 234 | * error. 235 | * @param {?string} [entity] The entity whose attribute is not valid. 236 | * @param {?string} [attribute] The attribute that is not valid. 237 | * @param {?(string|number)} [position] The position in the attribute that is 238 | * not valid. 239 | * @param {?Error} [innerError] The inner error. 240 | * @memberof module:back4app-entity/models/errors 241 | * @example 242 | * try 243 | * { 244 | * throw new ValidationError( 245 | * 'this attribute is required', 246 | * 'MyEntity', 247 | * 'myAttribute', 248 | * 1, 249 | * null 250 | * ); 251 | * } catch(e) { 252 | * console.log(e.message); // Logs "Error when validating an attribute called 253 | * // "myAttribute" of an entity called "MyEntity" in 254 | * // position 1: this attribute is required" 255 | * } 256 | */ 257 | function ValidationError( 258 | validationMessage, 259 | entity, 260 | attribute, 261 | position, 262 | innerError 263 | ) { 264 | /** 265 | * The validation message to be included in the error. 266 | * @type {?string} 267 | */ 268 | this.validationMessage = validationMessage; 269 | /** 270 | * The name of the entity that was not validated. 271 | * @type {?string} 272 | */ 273 | this.entity = entity; 274 | /** 275 | * The name of the attribute that was not validated. 276 | * @type {?string} 277 | */ 278 | this.attribute = attribute; 279 | /** 280 | * The position of the item in the attribute that was not validated. 281 | * @type {?(string|number)} 282 | */ 283 | this.position = position; 284 | /** 285 | * The inner error that generated the current error. 286 | * @type {?Error} 287 | */ 288 | this.innerError = innerError; 289 | 290 | expect(arguments).to.have.length.below( 291 | 6, 292 | 'Invalid arguments length when creating a new ' + 293 | 'AttributeTypeNotFoundError (it has to be passed less than 6 arguments)' 294 | ); 295 | 296 | this.name = 'ValidationError'; 297 | 298 | this.message = 'Error when validating an attribute'; 299 | if (attribute) { 300 | expect(attribute).to.be.a( 301 | 'string', 302 | 'Invalid argument "attribute" when creating a new ValidationError (it ' + 303 | 'has to be a string)' 304 | ); 305 | this.message += ' called "' + attribute + '"'; 306 | } 307 | 308 | this.message += ' of an entity'; 309 | if (entity) { 310 | expect(entity).to.be.a( 311 | 'string', 312 | 'Invalid argument "entity" when creating a new ValidationError (it has ' + 313 | 'to be a string)' 314 | ); 315 | this.message += ' called "' + entity + '"'; 316 | } 317 | 318 | if (position) { 319 | expect(['string', 'number']).to.include( 320 | typeof position, 321 | 'Invalid argument "position" when creating a new ValidationError (it ' + 322 | 'has to be a string or a number)' 323 | ); 324 | this.message += ' in position ' + position; 325 | } 326 | 327 | if (validationMessage) { 328 | expect(validationMessage).to.be.a( 329 | 'string', 330 | 'Invalid argument "validationMessage" when creating a new ' + 331 | 'ValidationError (it has to be a string)' 332 | ); 333 | this.message += ': ' + validationMessage; 334 | } 335 | 336 | this.stack = (new Error(this.message)).stack; 337 | if (innerError) { 338 | expect(innerError).to.be.an.instanceof( 339 | Error, 340 | 'Invalid argument "innerError" when creating a new ' + 341 | 'ValidationError (it has to be an Error)' 342 | ); 343 | this.stack += '\n\n' + innerError.stack; 344 | } 345 | } 346 | 347 | util.inherits(ValidationError, Error); 348 | 349 | /** 350 | * Error class to be used when an Adapter was referenced and the platform 351 | * was not able to find it. 352 | * @constructor 353 | * @extends Error 354 | * @param {?string} [adapterName] The adapter name to be displayed. 355 | * @param {?Error} [innerError] The inner error. 356 | * @memberof module:back4app-entity/models/errors 357 | * @example 358 | * if (settings.ADAPTERS.default) { 359 | * return settings.ADAPTERS.default; 360 | * } else { 361 | * throw new errors.AdapterNotFoundError('default'); 362 | * } 363 | */ 364 | function AdapterNotFoundError(adapterName, innerError) { 365 | /** 366 | * The name of the adapter that was not found. 367 | * @type {?string} 368 | */ 369 | this.adapterName = adapterName; 370 | /** 371 | * The inner error that generated the current error. 372 | * @type {?Error} 373 | */ 374 | this.innerError = innerError; 375 | 376 | expect(arguments).to.have.length.below( 377 | 3, 378 | 'Invalid arguments length when creating a new ' + 379 | 'EntityNotFoundError (it has to be passed less than 3 arguments)' 380 | ); 381 | 382 | this.name = 'AdapterNotFoundError'; 383 | 384 | this.message = 'Cannot find Adapter'; 385 | if (adapterName) { 386 | expect(adapterName).to.be.a( 387 | 'string', 388 | 'Invalid argument "adapterName" when creating a new ' + 389 | 'AdapterNotFoundError (it has to be a string)' 390 | ); 391 | this.message += ' "' + adapterName + '"'; 392 | } 393 | 394 | this.stack = (new Error(this.message)).stack; 395 | if (innerError) { 396 | expect(innerError).to.be.an.instanceof( 397 | Error, 398 | 'Invalid argument "innerError" when creating a new ' + 399 | 'AdapterNotFoundError (it has to be an Error)' 400 | ); 401 | this.stack += '\n\n' + innerError.stack; 402 | } 403 | } 404 | 405 | util.inherits(AdapterNotFoundError, Error); 406 | -------------------------------------------------------------------------------- /src/back/models/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | var Entity = require('./Entity'); 6 | var EntitySpecification = require('./EntitySpecification'); 7 | var attributes = require('./attributes'); 8 | var methods = require('./methods'); 9 | var errors = require('./errors'); 10 | var User = require('./User'); 11 | 12 | /** 13 | * Contains base classes for entities modelling. 14 | * @module back4app-entity/models 15 | */ 16 | module.exports = {}; 17 | 18 | module.exports.Entity = Entity; 19 | module.exports.EntitySpecification = EntitySpecification; 20 | module.exports.attributes = attributes; 21 | module.exports.methods = methods; 22 | module.exports.errors = errors; 23 | module.exports.User = User; 24 | -------------------------------------------------------------------------------- /src/back/models/methods.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 30/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | 9 | /** 10 | * Contains base classes for entity methods modelling. 11 | * @module back4app-entity/models/methods 12 | */ 13 | module.exports = {}; 14 | 15 | module.exports.MethodDictionary = MethodDictionary; 16 | 17 | /** 18 | * Dictionary of Entity Methods. An instance of MethodDictionary is not 19 | * extensible. 20 | * @constructor 21 | * @memberof module:back4app-entity/models/methods 22 | * @param {?Object.} [methods] The methods to be added in 23 | * the dictionary. They have to be given as a dictionary of functions. 24 | * @example 25 | * var methodDictionary = new MethodDictionary(); 26 | * @example 27 | * var methodDictionary = new MethodDictionary(null); 28 | * @example 29 | * var methodDictionary = new MethodDictionary({}); 30 | * @example 31 | * var methodDictionary = new MethodDictionary({ 32 | * method1: function () { return 'method1'; }, 33 | * method2: function () { return 'method2'; } 34 | * }); 35 | */ 36 | function MethodDictionary(methods) { 37 | expect(arguments).to.have.length.below( 38 | 2, 39 | 'Invalid arguments length when creating a new MethodDictionary (it has ' + 40 | 'to be passed less than 2 arguments)' 41 | ); 42 | 43 | if (methods) { 44 | expect(methods).to.be.an( 45 | 'object', 46 | 'Invalid argument type when creating a new MethodDictionary (it has to ' + 47 | 'be an object)' 48 | ); 49 | 50 | for (var method in methods) { 51 | _addMethod(this, methods[method], method); 52 | } 53 | } 54 | 55 | Object.preventExtensions(this); 56 | Object.seal(this); 57 | } 58 | 59 | MethodDictionary.concat = concat; 60 | 61 | /** 62 | * Adds a new method to the dictionary. 63 | * @name module:back4app-entity/models/methods~_addMethod 64 | * @function 65 | * @param {!module:back4app-entity/models/methods.MethodDictionary} 66 | * methodDictionary This is the MethodDictionary instance to which the method 67 | * will be added. 68 | * @param {!function} func This is the method's function to be added. 69 | * @param {!string} name This is the name of the method. 70 | * @private 71 | * @example 72 | * MethodDictionary.add( 73 | * methodDictionary, 74 | * function () { return 'method3'; }, 75 | * 'method3' 76 | * ); 77 | */ 78 | function _addMethod(methodDictionary, func, name) { 79 | expect(func).to.be.a( 80 | 'function', 81 | 'Invalid argument "func" when adding a method called "' + name + '" in a ' + 82 | 'MethodDictionary (it has to be a function)' 83 | ); 84 | 85 | Object.defineProperty(methodDictionary, name, { 86 | value: func, 87 | enumerable: true, 88 | writable: false, 89 | configurable: false 90 | }); 91 | } 92 | 93 | /** 94 | * Concatenates a MethodDictionary instance with a new method and returns a new 95 | * MethodDictionary. 96 | * @name module:back4app-entity/models/methods.MethodDictionary.concat 97 | * @function 98 | * @param {!module:back4app-entity/models/methods.MethodDictionary} 99 | * methodDictionary The MethodDictionary to be concatenated. 100 | * @param {!function} func The method's function to be concatenated. 101 | * @param {!string} name The method's name to be concatenated. 102 | * @returns {module:back4app-entity/models/methods.MethodDictionary} The 103 | * new concatenated MethodDictionary. 104 | * @example 105 | * var concatenatedMethodDictionary = MethodDictionary.concat( 106 | * methodDictionary, 107 | * function () { return 'newMethod'; }, 108 | * 'newMethod' 109 | * ); 110 | */ 111 | function concat(methodDictionary, func, name) { 112 | expect(arguments).to.have.length( 113 | 3, 114 | 'Invalid arguments length when concatenating a MethodDictionary (it has ' + 115 | 'to be passed 3 arguments)' 116 | ); 117 | 118 | expect(methodDictionary).to.be.instanceof( 119 | MethodDictionary, 120 | 'Invalid argument "methodDictionary" when concatenating a ' + 121 | 'MethodDictionary (it has to be a MethodDictionary)' 122 | ); 123 | 124 | expect(func).to.be.a( 125 | 'function', 126 | 'Invalid argument "func" when concatenating a MethodDictionary ' + 127 | '(it has to be a function)' 128 | ); 129 | 130 | expect(name).to.be.a( 131 | 'string', 132 | 'Invalid argument "name" when concatenating a MethodDictionary ' + 133 | '(it has to be a string)' 134 | ); 135 | 136 | expect(methodDictionary).to.not.have.ownProperty( 137 | name, 138 | 'Duplicated method name "' + name + '"' 139 | ); 140 | 141 | var currentMethods = {}; 142 | 143 | for (var currentMethod in methodDictionary) { 144 | currentMethods[currentMethod] = methodDictionary[currentMethod]; 145 | } 146 | 147 | currentMethods[name] = func; 148 | 149 | return new MethodDictionary(currentMethods); 150 | } 151 | -------------------------------------------------------------------------------- /src/back/settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains all settings needed by the {@link module:back4app-entity} module. 3 | * @module back4app-entity/settings 4 | */ 5 | module.exports = {}; 6 | 7 | /** 8 | * Constant with the path to the adapters dictionary. It will be 9 | * used to find the adapters always that one of them is referenced in the code. 10 | * @type {!Object.} 11 | * @example 12 | * settings.ADAPTERS = { 13 | * default: new MyAdapter(myConfig) 14 | * }; 15 | */ 16 | module.exports.ADAPTERS = {}; 17 | -------------------------------------------------------------------------------- /src/back/utils/classes.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var util = require('util'); 8 | var expect = require('chai').expect; 9 | 10 | /** 11 | * Contains utilities functions to be used with classes around the project. 12 | * @module back4app-entity/utils/classes 13 | */ 14 | module.exports = {}; 15 | 16 | module.exports.generalize = generalize; 17 | module.exports.isGeneral = isGeneral; 18 | 19 | /** 20 | * Makes the GeneralClass to generalize the SpecificClass. 21 | * @param {!Class} GeneralClass The general class to generalize the 22 | * SpecificClass. 23 | * @param {!Class} SpecificClass The specific class to be generalized by the 24 | * GeneralClass. 25 | * @example 26 | * function GeneralClass() {} 27 | * 28 | * function SpecificClass() { 29 | * GeneralClass.call(this); 30 | * } 31 | * 32 | * classes.generalize(GeneralClass, SpecificClass); 33 | */ 34 | function generalize(GeneralClass, SpecificClass) { 35 | expect(arguments).to.have.length( 36 | 2, 37 | 'Invalid argument length when generalizing classes (it has to be passed ' + 38 | '2 arguments)' 39 | ); 40 | expect(GeneralClass).to.be.a( 41 | 'function', 42 | 'Invalid argument "GeneralClass" when generalizing classes (it has to be ' + 43 | 'a function)' 44 | ); 45 | expect(SpecificClass).to.be.a( 46 | 'function', 47 | 'Invalid argument "SpecificClass" when generalizing classes (ut has to ' + 48 | 'be a function)' 49 | ); 50 | 51 | util.inherits(SpecificClass, GeneralClass); 52 | 53 | for (var property in GeneralClass) { 54 | if (SpecificClass.hasOwnProperty(property) === false) { 55 | var descriptor = Object.getOwnPropertyDescriptor(GeneralClass, property); 56 | if (descriptor) { 57 | descriptor.configurable = true; 58 | Object.defineProperty(SpecificClass, property, descriptor); 59 | } 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * Checks if the GeneralClass generalizes the SpecificClass. 66 | * @param {!Class} GeneralClass The general class to check. 67 | * @param {!Class} SpecificClass The specific class to check. 68 | * @example 69 | * function GeneralClass() {} 70 | * 71 | * function SpecificClass() { 72 | * GeneralClass.call(this); 73 | * } 74 | * 75 | * classes.generalize(GeneralClass, SpecificClass); 76 | * 77 | * console.log(classes.isGeneral(GeneralClass, SpecificClass)); // Logs "true" 78 | * 79 | * console.log(classes.isGeneral(GeneralClass, GeneralClass)); // Logs "true" 80 | * 81 | * console.log(classes.isGeneral(SpecificClass, SpecificClass)); // Logs "true" 82 | * 83 | * console.log(classes.isGeneral(SpecificClass, GeneralClass)); // Logs "false" 84 | */ 85 | function isGeneral(GeneralClass, SpecificClass) { 86 | expect(arguments).to.have.length( 87 | 2, 88 | 'Invalid argument length when checking if a class is general of another ' + 89 | '(it has to be passed 2 arguments)' 90 | ); 91 | expect(GeneralClass).to.be.a( 92 | 'function', 93 | 'Invalid argument "GeneralClass" when checking if a class is general of ' + 94 | 'another (it has to be a function)' 95 | ); 96 | expect(SpecificClass).to.be.a( 97 | 'function', 98 | 'Invalid argument "SpecificClass" when checking if a class is general ' + 99 | 'of another (it has to be a function)' 100 | ); 101 | 102 | var visitedClasses = []; 103 | var CurrentClass = SpecificClass; 104 | 105 | while (CurrentClass && visitedClasses.indexOf(CurrentClass) === -1) { 106 | if (CurrentClass === GeneralClass) { 107 | return true; 108 | } 109 | 110 | visitedClasses.push(CurrentClass); 111 | CurrentClass = CurrentClass.super_; 112 | } 113 | 114 | return false; 115 | } 116 | -------------------------------------------------------------------------------- /src/back/utils/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | var classes = require('./classes'); 6 | var objects = require('./objects'); 7 | 8 | /** 9 | * Contains utilities functions to be used around the project. 10 | * @module back4app-entity/utils 11 | */ 12 | module.exports = {}; 13 | 14 | module.exports.classes = classes; 15 | module.exports.objects = objects; 16 | -------------------------------------------------------------------------------- /src/back/utils/objects.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | 9 | /** 10 | * Contains utilities functions to be used with objects around the project. 11 | * @module back4app-entity/utils/objects 12 | */ 13 | module.exports = {}; 14 | 15 | module.exports.copy = copy; 16 | 17 | /** 18 | * Makes a copy of a given object. 19 | * @param {!Object} o The object to be copied. 20 | * @returns {Object} The new copy of the given object. 21 | * @example 22 | * var copy = objects.copy(myObject); 23 | */ 24 | function copy(o) { 25 | expect(arguments).to.have.length( 26 | 1, 27 | 'Invalid argument length when copying an object (it has to be passed ' + 28 | '1 argument)' 29 | ); 30 | 31 | expect(o).to.be.an( 32 | 'object', 33 | 'Invalid argument "o" when copying an object (it has to be an object)' 34 | ); 35 | 36 | var oCopy = {}; 37 | 38 | for (var property in o) { 39 | oCopy[property] = o[property]; 40 | } 41 | 42 | return oCopy; 43 | } 44 | -------------------------------------------------------------------------------- /tests/unit/back/adapters/MockAdapter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Promise = require('bluebird'); 4 | var classes = require('../../../../src/back').utils.classes; 5 | var Adapter = require('../../../../src/back').adapters.Adapter; 6 | 7 | module.exports = MockAdapter; 8 | 9 | function MockAdapter() { 10 | Adapter.apply(this, Array.prototype.slice.call(arguments)); 11 | } 12 | 13 | classes.generalize(Adapter, MockAdapter); 14 | 15 | MockAdapter.prototype.loadEntity = loadEntity; 16 | MockAdapter.prototype.loadEntityAttribute = loadEntityAttribute; 17 | MockAdapter.prototype.insertObject = insertObject; 18 | MockAdapter.prototype.updateObject = updateObject; 19 | MockAdapter.prototype.deleteObject = deleteObject; 20 | MockAdapter.prototype.getObject = getObject; 21 | MockAdapter.prototype.findObjects = findObjects; 22 | 23 | function loadEntity() {} 24 | 25 | function loadEntityAttribute() {} 26 | 27 | function insertObject() { 28 | var promise = new Promise(function (resolve) { 29 | resolve(); 30 | }); 31 | 32 | return promise; 33 | } 34 | 35 | function updateObject() { 36 | var promise = new Promise(function (resolve) { 37 | resolve(); 38 | }); 39 | 40 | return promise; 41 | } 42 | 43 | function deleteObject() {} 44 | 45 | function getObject() {} 46 | 47 | function findObjects() {} 48 | -------------------------------------------------------------------------------- /tests/unit/back/adapters/adapter.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var entity = require('../../../../'); 11 | var classes = entity.utils.classes; 12 | var adapters = entity.adapters; 13 | var Adapter = adapters.Adapter; 14 | var Entity = entity.models.Entity; 15 | var ObjectAttribute = entity.models.attributes.types.ObjectAttribute; 16 | 17 | require('../../settings'); 18 | 19 | describe('Adapter', function () { 20 | var adapter; 21 | 22 | var myEntityAttribute = new ObjectAttribute('myAttribute'); 23 | var MyEntity = Entity.specify( 24 | 'MyNewEntity', 25 | [ 26 | myEntityAttribute 27 | ] 28 | ); 29 | 30 | function WrongAdapterProxy() { 31 | adapters.Adapter.apply(this, Array.prototype.slice.call(arguments)); 32 | } 33 | 34 | function AdapterProxy() { 35 | adapters.Adapter.apply(this, Array.prototype.slice.call(arguments)); 36 | } 37 | 38 | classes.generalize(adapters.Adapter, AdapterProxy); 39 | 40 | context('interface tests', function () { 41 | it('expect to not be able to instantiate directly', function () { 42 | expect(function () { 43 | adapter = new Adapter(); 44 | }).to.throw(AssertionError); 45 | }); 46 | 47 | it( 48 | 'expect to not be not able to instantiate from a non subclass', 49 | function () { 50 | expect(function () { 51 | adapter = new WrongAdapterProxy(); 52 | }).to.throw(AssertionError); 53 | } 54 | ); 55 | 56 | it('expect to work when initialized from subclasses', function () { 57 | adapter = new AdapterProxy(); 58 | }); 59 | }); 60 | 61 | describe('#loadEntity', function () { 62 | adapter = new AdapterProxy(); 63 | 64 | it('expect to exist as an instance member', function () { 65 | expect(adapter).to.respondTo('loadEntity'); 66 | }); 67 | 68 | it('expect to be implemented in concrete adapters', function () { 69 | expect(function () { 70 | adapters.Adapter.prototype.loadEntity(Entity); 71 | }).to.throw(Error); 72 | }); 73 | }); 74 | 75 | describe('#loadEntityAttribute', function () { 76 | adapter = new AdapterProxy(); 77 | 78 | it('expect to exist as an instance member', function () { 79 | expect(adapter).to.respondTo('loadEntityAttribute'); 80 | }); 81 | 82 | it('expect to be implemented in concrete adapters', function () { 83 | expect(function () { 84 | adapter.loadEntityAttribute( 85 | MyEntity, 86 | myEntityAttribute 87 | ); 88 | }).to.throw(Error); 89 | }); 90 | }); 91 | 92 | describe('#insertObject', function () { 93 | adapter = new AdapterProxy(); 94 | 95 | it('expect to exist as an instance member', function () { 96 | expect(adapter).to.respondTo('insertObject'); 97 | }); 98 | 99 | it('expect to be implemented in concrete adapters', function (done) { 100 | adapters.Adapter.prototype 101 | .insertObject(new MyEntity()) 102 | .catch(function (error) { 103 | expect(error).to.be.an.instanceOf(Error); 104 | done(); 105 | }); 106 | }); 107 | }); 108 | 109 | describe('#updateObject', function () { 110 | adapter = new AdapterProxy(); 111 | 112 | it('expect to exist as an instance member', function () { 113 | expect(adapter).to.respondTo('updateObject'); 114 | }); 115 | 116 | it('expect to be implemented in concrete adapters', function (done) { 117 | adapters.Adapter.prototype 118 | .updateObject(new MyEntity()) 119 | .catch(function (error) { 120 | expect(error).to.be.an.instanceOf(Error); 121 | done(); 122 | }); 123 | }); 124 | }); 125 | }); 126 | -------------------------------------------------------------------------------- /tests/unit/back/adapters/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('chai').expect; 4 | var adaptersIndex = require('../../../../src/back/adapters'); 5 | var Adapter = require('../../../../src/back/adapters/Adapter'); 6 | 7 | require('../../settings'); 8 | 9 | describe('adaptersIndex', function () { 10 | it('expect to export Adapter in the Adapter property', function () { 11 | expect(adaptersIndex).to.have.property('Adapter') 12 | .that.equals(Adapter); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /tests/unit/back/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('chai').expect; 4 | var backIndex = require('../../../src/back'); 5 | var utils = require('../../../src/back/utils'); 6 | var settings = require('../../../src/back/settings'); 7 | var adapters = require('../../../src/back/adapters'); 8 | var models = require('../../../src/back/models'); 9 | 10 | require('../settings'); 11 | 12 | describe('backIndex', function () { 13 | it('expect to export utils in the utils property', function () { 14 | expect(backIndex).to.have.property('utils') 15 | .that.equals(utils); 16 | }); 17 | 18 | it('expect to export settings in the settings property', function () { 19 | expect(backIndex).to.have.property('settings') 20 | .that.equals(settings); 21 | }); 22 | 23 | it('expect to export adapters in the adapters property', function () { 24 | expect(backIndex).to.have.property('adapters') 25 | .that.equals(adapters); 26 | }); 27 | 28 | it('expect to export models in the models property', function () { 29 | expect(backIndex).to.have.property('models') 30 | .that.equals(models); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /tests/unit/back/models/C1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Entity = require('../../../../').models.Entity; 4 | 5 | require('../../settings'); 6 | 7 | module.exports = Entity.specify({ 8 | name: 'C1', 9 | attributes: { 10 | c1A1: { 11 | type: 'Boolean', 12 | multiplicity: '1', 13 | default: false 14 | }, 15 | c1A2: { 16 | type: 'Date', 17 | multiplicity: '0..1', 18 | default: Date.now 19 | }, 20 | c1A3: { 21 | type: 'Number', 22 | multiplicity: '1..*', 23 | default: function () { return [0]; } 24 | }, 25 | c1A4: { 26 | type: 'Object', 27 | multiplicity: '*', 28 | default: null 29 | }, 30 | c1A5: { 31 | type: 'Number', 32 | multiplicity: '1', 33 | default: 0.0 34 | }, 35 | c1A6: { 36 | type: 'String', 37 | multiplicity: '0..1', 38 | default: '' 39 | }, 40 | c1A7: { 41 | type: 'C1', 42 | multiplicity: '1' 43 | }, 44 | c1A8: { 45 | type: 'C11', 46 | multiplicity: '0..1', 47 | default: null 48 | }, 49 | c1A9: { 50 | type: 'C2', 51 | multiplicity: '1..*', 52 | default: function () { return [new (Entity.getSpecialization('C2'))()]; } 53 | }, 54 | c1A10: { 55 | type: 'C2', 56 | multiplicity: '1', 57 | default: Entity.new('C2') 58 | } 59 | }, 60 | methods: { 61 | c1A6M: c1A6M, 62 | c1M1: c1M1, 63 | c1M2: c1M2 64 | }, 65 | isAbstract: false, 66 | dataName: { 67 | default: 'C1' 68 | } 69 | }); 70 | 71 | function c1A6M(c1A6) { 72 | if (arguments.length > 0) { 73 | this.c1A6 = c1A6; 74 | } 75 | return this.c1A6; 76 | } 77 | 78 | function c1M1(c1M1P1, c1M1P2) { 79 | return c1M1P1 + c1M1P2; 80 | } 81 | 82 | function c1M2(c1M2P1, c1M2P2) { 83 | return c1M2P1 + c1M2P2; 84 | } 85 | -------------------------------------------------------------------------------- /tests/unit/back/models/C11.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var C1 = require('./C1'); 8 | 9 | require('../../settings'); 10 | 11 | module.exports = C1.specify({ 12 | name: 'C11', 13 | attributes: { 14 | c11A1: { 15 | type: 'Object', 16 | multiplicity: '1' 17 | } 18 | }, 19 | methods: { 20 | c1M1: c1M1, 21 | c11M: c11M 22 | }, 23 | isAbstract: false, 24 | dataName: 'C11' 25 | }); 26 | 27 | function c1M1(c1M1P1, c1M1P2, c11M1P) { 28 | return this.General.methods.c1M1.call(this, c1M1P1, c1M1P2) + c11M1P; 29 | } 30 | 31 | function c11M() { 32 | var toReturn = ''; 33 | var attribute = null; 34 | 35 | for (attribute in this.General.attributes) { 36 | toReturn += attribute; 37 | } 38 | 39 | for (attribute in this.Entity.attributes) { 40 | toReturn += attribute; 41 | } 42 | 43 | return toReturn; 44 | } 45 | -------------------------------------------------------------------------------- /tests/unit/back/models/C2.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 24/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var Entity = require('../../../../').models.Entity; 8 | var ObjectAttribute = require('../../../../') 9 | .models.attributes.types.ObjectAttribute; 10 | 11 | require('../../settings'); 12 | 13 | module.exports = Entity.specify( 14 | 'C2', 15 | [ 16 | new ObjectAttribute( 17 | '_Entity', 18 | '1', 19 | function () { return {}; } 20 | ), 21 | new ObjectAttribute({ 22 | name: 'c2A2', 23 | multiplicity: '0..1', 24 | default: function () { return { default: 'thisIsMyDefault' }; } 25 | }) 26 | ], 27 | { 28 | constructor: function () { return 'constructor'; } 29 | }, 30 | { 31 | isAbstract: false, 32 | dataName: { 33 | notDefault: 'notDefault', 34 | default: 'C2' 35 | } 36 | } 37 | ); 38 | -------------------------------------------------------------------------------- /tests/unit/back/models/C3.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 31/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var entity = require('../../../../'); 8 | var Entity = entity.models.Entity; 9 | var types = entity.models.attributes.types; 10 | var ObjectAttribute = types.ObjectAttribute; 11 | var AssociationAttribute = types.AssociationAttribute; 12 | 13 | require('../../settings'); 14 | 15 | module.exports = Entity.specify( 16 | 'C3', 17 | [ 18 | new ObjectAttribute({ 19 | name: 'c3A1', 20 | multiplicity: '1', 21 | default: function () { return {}; } 22 | }), 23 | new AssociationAttribute({ 24 | name: 'c3A2', 25 | entity: 'C3', 26 | multiplicity: '0..1' 27 | }) 28 | ] 29 | ); 30 | -------------------------------------------------------------------------------- /tests/unit/back/models/EntityProxy.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 30/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var entity = require('../../../../'); 8 | var classes = entity.utils.classes; 9 | var Entity = entity.models.Entity; 10 | 11 | module.exports = EntityProxy; 12 | 13 | function EntityProxy() { 14 | Entity.apply(this, Array.prototype.slice.call(arguments)); 15 | } 16 | 17 | classes.generalize(Entity, EntityProxy); 18 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/attributeDictionary.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var attributes = require('../../../../../').models.attributes; 11 | 12 | require('../../../settings'); 13 | 14 | describe('AttributeDictionary', function () { 15 | var attributeDictionary; 16 | 17 | context('interface tests', function () { 18 | it('expect to work without arguments', function () { 19 | attributeDictionary = new attributes.AttributeDictionary(); 20 | }); 21 | 22 | it('expect to work with null argument', function () { 23 | attributeDictionary = new attributes.AttributeDictionary(null); 24 | }); 25 | 26 | it('expect to work with empty object', function () { 27 | attributeDictionary = new attributes.AttributeDictionary({}); 28 | }); 29 | 30 | it('expect to work with right arguments', function () { 31 | attributeDictionary = new attributes.AttributeDictionary({ 32 | attribute1: attributes.Attribute.resolve('attribute1'), 33 | attribute2: attributes.Attribute.resolve('attribute2') 34 | }); 35 | 36 | attributeDictionary = new attributes.AttributeDictionary({ 37 | attribute1: {}, 38 | attribute2: {} 39 | }); 40 | 41 | attributeDictionary = new attributes.AttributeDictionary([ 42 | attributes.Attribute.resolve('attribute1'), 43 | attributes.Attribute.resolve('attribute2') 44 | ]); 45 | 46 | attributeDictionary = new attributes.AttributeDictionary([ 47 | { name: 'attribute1' }, 48 | { name: 'attribute2' } 49 | ]); 50 | }); 51 | 52 | it('expect to not work with wrong arguments', function () { 53 | expect(function () { 54 | attributeDictionary = new attributes.AttributeDictionary({}, {}); 55 | }).to.throw(AssertionError); 56 | 57 | expect(function () { 58 | attributeDictionary = new attributes.AttributeDictionary( 59 | function () {} 60 | ); 61 | }).to.throw(AssertionError); 62 | 63 | expect(function () { 64 | attributeDictionary = new attributes.AttributeDictionary({ 65 | attribute1: null 66 | }); 67 | }).to.throw(AssertionError); 68 | 69 | expect(function () { 70 | attributeDictionary = new attributes.AttributeDictionary({ 71 | attribute1: { 72 | name: 'differentName' 73 | } 74 | }); 75 | }).to.throw(AssertionError); 76 | 77 | expect(function () { 78 | attributeDictionary = new attributes.AttributeDictionary([ 79 | null 80 | ]); 81 | }).to.throw(AssertionError); 82 | 83 | expect(function () { 84 | attributeDictionary = new attributes.AttributeDictionary([ 85 | { name: 'sameName' }, 86 | { name: 'sameName' } 87 | ]); 88 | }).to.throw(AssertionError); 89 | }); 90 | }); 91 | 92 | context('functional tests', function () { 93 | it('expect to allow get attributes correctly', function () { 94 | expect(attributeDictionary.attribute1.name).to.equal('attribute1'); 95 | expect(attributeDictionary.attribute2.name).to.equal('attribute2'); 96 | }); 97 | 98 | it('expect to allow to list attributes', function () { 99 | var attributes = []; 100 | 101 | for (var attribute in attributeDictionary) { 102 | attributes.push(attribute); 103 | } 104 | 105 | expect(attributes).to.be.deep.equal(['attribute1', 'attribute2']); 106 | }); 107 | 108 | it('expect to be not extensible', function () { 109 | expect(Object.isExtensible(attributeDictionary)).to.equal(false); 110 | 111 | expect(function () { 112 | attributeDictionary.attribute3 = attributes.Attribute.resolve( 113 | 'attribute3' 114 | ); 115 | }).to.throw(TypeError); 116 | 117 | expect(attributeDictionary).to.not.have.property('attribute3'); 118 | }); 119 | 120 | it('expect to not allow to delete attribute', function () { 121 | expect(function () { 122 | delete attributeDictionary.attribute1; 123 | }).to.throw(Error); 124 | 125 | expect(attributeDictionary).to.have.property('attribute1'); 126 | }); 127 | 128 | it('expect to not allow to change method', function () { 129 | expect(function () { 130 | attributeDictionary.attribute1 = attributes.Attribute.resolve( 131 | 'wontWork' 132 | ); 133 | }).to.throw(Error); 134 | 135 | expect(attributeDictionary.attribute1.name).to.equal('attribute1'); 136 | }); 137 | }); 138 | 139 | describe('.concat', function () { 140 | var attributeDictionary; 141 | var concatenatedAttributeDictionary; 142 | 143 | it( 144 | 'expect to work with right arguments and have specified behavior', 145 | function () { 146 | attributeDictionary = new attributes.AttributeDictionary([ 147 | attributes.Attribute.resolve('attribute1'), 148 | attributes.Attribute.resolve('attribute2') 149 | ]); 150 | 151 | concatenatedAttributeDictionary = 152 | attributes 153 | .AttributeDictionary 154 | .concat( 155 | attributeDictionary, 156 | attributes.Attribute.resolve('attribute3') 157 | ); 158 | 159 | expect(concatenatedAttributeDictionary) 160 | .to.not.deep.equal(attributeDictionary); 161 | 162 | expect(Object.keys(concatenatedAttributeDictionary)) 163 | .to.deep.equal(['attribute1', 'attribute2', 'attribute3']); 164 | 165 | expect(concatenatedAttributeDictionary.attribute1.name) 166 | .to.equal('attribute1'); 167 | expect(concatenatedAttributeDictionary.attribute2.name) 168 | .to.equal('attribute2'); 169 | expect(concatenatedAttributeDictionary.attribute3.name) 170 | .to.equal('attribute3'); 171 | } 172 | ); 173 | 174 | it('expect to not work with wrong arguments', function () { 175 | expect(function () { 176 | concatenatedAttributeDictionary = 177 | attributes 178 | .AttributeDictionary 179 | .concat( 180 | attributes.Attribute.resolve('attribute3') 181 | ); 182 | }).to.throw(AssertionError); 183 | 184 | expect(function () { 185 | concatenatedAttributeDictionary = 186 | attributes 187 | .AttributeDictionary 188 | .concat( 189 | attributeDictionary, 190 | attributes.Attribute.resolve('attribute3'), 191 | null 192 | ); 193 | }).to.throw(AssertionError); 194 | 195 | expect(function () { 196 | concatenatedAttributeDictionary = 197 | attributes 198 | .AttributeDictionary 199 | .concat( 200 | {}, 201 | attributes.Attribute.resolve('attribute3') 202 | ); 203 | }).to.throw(AssertionError); 204 | 205 | expect(function () { 206 | concatenatedAttributeDictionary = 207 | attributes 208 | .AttributeDictionary 209 | .concat( 210 | attributeDictionary, 211 | {} 212 | ); 213 | }).to.throw(AssertionError); 214 | }); 215 | 216 | it('expect to not work with duplicated', function () { 217 | expect(function () { 218 | concatenatedAttributeDictionary = 219 | attributes 220 | .AttributeDictionary 221 | .concat( 222 | concatenatedAttributeDictionary, 223 | attributes.Attribute.resolve('attribute3') 224 | ); 225 | }).to.throw(AssertionError); 226 | }); 227 | }); 228 | }); 229 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/index.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var attributesIndex = require('../../../../../src/back/models/attributes'); 9 | var Attribute = require('../../../../../src/back/models/attributes/Attribute'); 10 | var AttributeDictionary = require( 11 | '../../../../../src/back/models/attributes/AttributeDictionary' 12 | ); 13 | var types = require('../../../../../src/back/models/attributes/types'); 14 | 15 | require('../../../settings'); 16 | 17 | describe('attributesIndex', function () { 18 | it('expect to export Attribute in the Attribute property', function () { 19 | expect(attributesIndex).to.have.property('Attribute') 20 | .that.equals(Attribute); 21 | }); 22 | 23 | it( 24 | 'expect to export AttributeDictionary in the AttributeDictionary property', 25 | function () { 26 | expect(attributesIndex).to.have.property('AttributeDictionary') 27 | .that.equals(AttributeDictionary); 28 | } 29 | ); 30 | 31 | it('expect to export types in the types property', function () { 32 | expect(attributesIndex).to.have.property('types') 33 | .that.equals(types); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/booleanAttribute.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var ValidationError = models.errors.ValidationError; 13 | var attributes = models.attributes; 14 | var Attribute = attributes.Attribute; 15 | var BooleanAttribute = attributes.types.BooleanAttribute; 16 | 17 | require('../../../../settings'); 18 | 19 | describe('BooleanAttribute', function () { 20 | var booleanAttribute; 21 | 22 | context('interface tests', function () { 23 | it('expect to not work without arguments', function () { 24 | expect(function () { 25 | booleanAttribute = new BooleanAttribute(); 26 | }).to.throw(AssertionError); 27 | }); 28 | 29 | it('expect to not work with null argument', function () { 30 | expect(function () { 31 | booleanAttribute = new BooleanAttribute(null); 32 | }).to.throw(AssertionError); 33 | }); 34 | 35 | it('expect to not work with empty object', function () { 36 | expect(function () { 37 | booleanAttribute = new BooleanAttribute({}); 38 | }).to.throw(AssertionError); 39 | }); 40 | 41 | it('expect to work with right arguments passing as an object', 42 | function () { 43 | booleanAttribute = new BooleanAttribute({ 44 | name: 'attribute' 45 | }); 46 | 47 | booleanAttribute = new BooleanAttribute({ 48 | name: 'attribute', 49 | default: null 50 | }); 51 | 52 | booleanAttribute = new BooleanAttribute({ 53 | name: 'attribute', 54 | multiplicity: '0..1' 55 | }); 56 | 57 | 58 | booleanAttribute = new BooleanAttribute({ 59 | name: 'attribute', 60 | multiplicity: '0..1', 61 | default: null 62 | }); 63 | 64 | booleanAttribute = new BooleanAttribute({ 65 | name: 'attribute', 66 | multiplicity: '0..1', 67 | default: null, 68 | dataName: 'attributeDataName' 69 | }); 70 | 71 | booleanAttribute = new BooleanAttribute({ 72 | name: 'attribute', 73 | multiplicity: '0..1', 74 | default: null, 75 | dataName: { 76 | default: 'attributeDataName', 77 | default2: 'attributeDataName' 78 | } 79 | }); 80 | } 81 | ); 82 | 83 | it('expect to work with right arguments passing as arguments', 84 | function () { 85 | booleanAttribute = new BooleanAttribute( 86 | 'attribute' 87 | ); 88 | 89 | booleanAttribute = new BooleanAttribute( 90 | 'attribute', 91 | '0..1' 92 | ); 93 | 94 | booleanAttribute = new BooleanAttribute( 95 | 'attribute', 96 | '0..1', 97 | { propertyTest: 'justATest' } 98 | ); 99 | 100 | booleanAttribute = new BooleanAttribute( 101 | 'attribute', 102 | '0..1', 103 | { propertyTest: 'justATest' }, 104 | 'attributeDataName' 105 | ); 106 | 107 | booleanAttribute = new BooleanAttribute( 108 | 'attribute', 109 | '0..1', 110 | { propertyTest: 'justATest' }, 111 | { 112 | default: 'attributeDataName', 113 | default2: 'attributeDataName' 114 | } 115 | ); 116 | } 117 | ); 118 | 119 | it('expect to not work with wrong arguments', function () { 120 | expect(function () { 121 | booleanAttribute = new BooleanAttribute( 122 | 'attribute', 123 | '0..1', 124 | null, 125 | null, 126 | null 127 | ); 128 | }).to.throw(AssertionError); 129 | 130 | expect(function () { 131 | booleanAttribute = new BooleanAttribute(function () {}); 132 | }).to.throw(AssertionError); 133 | 134 | expect(function () { 135 | booleanAttribute = new BooleanAttribute({ 136 | multiplicity: '0..1', 137 | default: null, 138 | dataName: 'dataName' 139 | }); 140 | }).to.throw(AssertionError); 141 | 142 | expect(function () { 143 | booleanAttribute = new BooleanAttribute({ 144 | name: null, 145 | multiplicity: '0..1', 146 | default: null, 147 | dataName: 'dataName' 148 | }); 149 | }).to.throw(AssertionError); 150 | 151 | expect(function () { 152 | booleanAttribute = new BooleanAttribute({ 153 | name: 'attribute', 154 | multiplicity: '0..1', 155 | default: null, 156 | dataName: 'dataName', 157 | doesNotExist: null 158 | }); 159 | }).to.throw(AssertionError); 160 | 161 | expect(function () { 162 | booleanAttribute = new BooleanAttribute({ 163 | name: 'attribute', 164 | type: 'Boolean', 165 | multiplicity: '0..1', 166 | default: null, 167 | dataName: 'dataName' 168 | }); 169 | }).to.throw(AssertionError); 170 | 171 | expect(function () { 172 | booleanAttribute = new BooleanAttribute({ 173 | name: 'attribute', 174 | multiplicity: null, 175 | default: null, 176 | dataName: 'dataName' 177 | }); 178 | }).to.throw(AssertionError); 179 | 180 | expect(function () { 181 | booleanAttribute = new BooleanAttribute({ 182 | name: 'attribute', 183 | multiplicity: '1', 184 | default: null, 185 | dataName: function () {} 186 | }); 187 | }).to.throw(AssertionError); 188 | }); 189 | 190 | it('expect to find correct typeName', function () { 191 | expect(BooleanAttribute).to.have.property('typeName') 192 | .that.equals('Boolean'); 193 | }); 194 | }); 195 | 196 | context('functional tests', function () { 197 | it('expect to be a specialization of Attribute', function () { 198 | expect(classes.isGeneral(Attribute, BooleanAttribute)).to.equal(true); 199 | 200 | expect(new BooleanAttribute('myBooleanAttribute')) 201 | .to.be.an.instanceof(Attribute); 202 | }); 203 | 204 | it('expect to have all properties storing the right values', function () { 205 | expect(booleanAttribute).to.have.property('name') 206 | .that.equals('attribute'); 207 | 208 | expect(booleanAttribute).to.have.property('type') 209 | .that.equals(BooleanAttribute); 210 | 211 | expect(booleanAttribute).to.have.property('multiplicity') 212 | .that.equals('0..1'); 213 | 214 | expect(booleanAttribute).to.have.property('default') 215 | .that.deep.equals({ propertyTest: 'justATest'}); 216 | 217 | expect(booleanAttribute).to.have.property('dataName') 218 | .that.deep.equals( 219 | { 220 | default: 'attributeDataName', 221 | default2: 'attributeDataName' 222 | } 223 | ); 224 | }); 225 | 226 | it('expect to be not extensible', function () { 227 | expect(Object.isExtensible(booleanAttribute)).to.equal(false); 228 | 229 | expect(function () { 230 | booleanAttribute.doesNotExist = {}; 231 | }).to.throw(TypeError); 232 | 233 | expect(booleanAttribute).to.not.respondTo('doesNotExist'); 234 | }); 235 | 236 | it('expect to not allow to delete property', function () { 237 | expect(function () { 238 | delete booleanAttribute.name; 239 | }).to.throw(Error); 240 | 241 | expect(booleanAttribute).to.have.property('name') 242 | .that.equals('attribute'); 243 | 244 | expect(function () { 245 | delete booleanAttribute.type; 246 | }).to.throw(Error); 247 | 248 | expect(booleanAttribute).to.have.property('type') 249 | .that.equals(BooleanAttribute); 250 | 251 | expect(function () { 252 | delete booleanAttribute.multiplicity; 253 | }).to.throw(Error); 254 | 255 | expect(booleanAttribute).to.have.property('multiplicity') 256 | .that.equals('0..1'); 257 | 258 | expect(function () { 259 | delete booleanAttribute.default; 260 | }).to.throw(Error); 261 | 262 | expect(booleanAttribute).to.have.property('default') 263 | .that.deep.equals({ propertyTest: 'justATest' }); 264 | 265 | expect(function () { 266 | delete booleanAttribute.dataName; 267 | }).to.throw(Error); 268 | 269 | expect(booleanAttribute).to.have.property('dataName') 270 | .that.deep.equals({ 271 | default: 'attributeDataName', 272 | default2: 'attributeDataName' 273 | }); 274 | }); 275 | 276 | it('expect to not allow to change property', function () { 277 | expect(function () { 278 | booleanAttribute.name = 'will not change'; 279 | }).to.throw(Error); 280 | 281 | expect(booleanAttribute).to.have.property('name') 282 | .that.equals('attribute'); 283 | 284 | expect(function () { 285 | booleanAttribute.type = 'will not change'; 286 | }).to.throw(Error); 287 | 288 | expect(booleanAttribute).to.have.property('type') 289 | .that.equals(BooleanAttribute); 290 | 291 | expect(function () { 292 | booleanAttribute.multiplicity = 'will not change'; 293 | }).to.throw(Error); 294 | 295 | expect(booleanAttribute).to.have.property('multiplicity') 296 | .that.equals('0..1'); 297 | 298 | expect(function () { 299 | booleanAttribute.default = 'will not change'; 300 | }).to.throw(Error); 301 | 302 | expect(booleanAttribute).to.have.property('default') 303 | .that.deep.equals({ propertyTest: 'justATest' }); 304 | 305 | expect(function () { 306 | booleanAttribute.dataName = 'will not change'; 307 | }).to.throw(Error); 308 | 309 | expect(booleanAttribute).to.have.property('dataName') 310 | .that.deep.equals({ 311 | default: 'attributeDataName', 312 | default2: 'attributeDataName' 313 | }); 314 | }); 315 | 316 | it('expect to have the right default values', function () { 317 | booleanAttribute = new BooleanAttribute('attributeName'); 318 | 319 | expect(booleanAttribute.name).to.equal('attributeName'); 320 | expect(booleanAttribute.type).to.equal(BooleanAttribute); 321 | expect(booleanAttribute.multiplicity).to.equal('1'); 322 | expect(booleanAttribute.default).to.equal(null); 323 | expect(booleanAttribute.dataName).to.equal(null); 324 | }); 325 | }); 326 | 327 | describe('#validateValue', function () { 328 | it('expect to work correctly', function () { 329 | booleanAttribute.validateValue(true); 330 | booleanAttribute.validateValue(false); 331 | expect(function () { 332 | booleanAttribute.validateValue(null); 333 | }).to.throw(ValidationError); 334 | expect(function () { 335 | booleanAttribute.validateValue({}); 336 | }).to.throw(ValidationError); 337 | }); 338 | }); 339 | }); 340 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/dateAttribute.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var ValidationError = models.errors.ValidationError; 13 | var attributes = models.attributes; 14 | var Attribute = attributes.Attribute; 15 | var DateAttribute = attributes.types.DateAttribute; 16 | 17 | require('../../../../settings'); 18 | 19 | describe('DateAttribute', function () { 20 | var dateAttribute; 21 | 22 | context('interface tests', function () { 23 | it('expect to not work without arguments', function () { 24 | expect(function () { 25 | dateAttribute = new DateAttribute(); 26 | }).to.throw(AssertionError); 27 | }); 28 | 29 | it('expect to not work with null argument', function () { 30 | expect(function () { 31 | dateAttribute = new DateAttribute(null); 32 | }).to.throw(AssertionError); 33 | }); 34 | 35 | it('expect to not work with empty object', function () { 36 | expect(function () { 37 | dateAttribute = new DateAttribute({}); 38 | }).to.throw(AssertionError); 39 | }); 40 | 41 | it('expect to work with right arguments passing as an object', 42 | function () { 43 | dateAttribute = new DateAttribute({ 44 | name: 'attribute' 45 | }); 46 | 47 | dateAttribute = new DateAttribute({ 48 | name: 'attribute', 49 | default: null 50 | }); 51 | 52 | dateAttribute = new DateAttribute({ 53 | name: 'attribute', 54 | multiplicity: '0..1' 55 | }); 56 | 57 | 58 | dateAttribute = new DateAttribute({ 59 | name: 'attribute', 60 | multiplicity: '0..1', 61 | default: null 62 | }); 63 | 64 | dateAttribute = new DateAttribute({ 65 | name: 'attribute', 66 | multiplicity: '0..1', 67 | default: null, 68 | dataName: 'attributeDataName' 69 | }); 70 | 71 | dateAttribute = new DateAttribute({ 72 | name: 'attribute', 73 | multiplicity: '0..1', 74 | default: null, 75 | dataName: { 76 | default: 'attributeDataName', 77 | default2: 'attributeDataName' 78 | } 79 | }); 80 | } 81 | ); 82 | 83 | it('expect to work with right arguments passing as arguments', 84 | function () { 85 | dateAttribute = new DateAttribute( 86 | 'attribute' 87 | ); 88 | 89 | dateAttribute = new DateAttribute( 90 | 'attribute', 91 | '0..1' 92 | ); 93 | 94 | dateAttribute = new DateAttribute( 95 | 'attribute', 96 | '0..1', 97 | { propertyTest: 'justATest' } 98 | ); 99 | 100 | dateAttribute = new DateAttribute( 101 | 'attribute', 102 | '0..1', 103 | { propertyTest: 'justATest' }, 104 | 'attributeDataName' 105 | ); 106 | 107 | dateAttribute = new DateAttribute( 108 | 'attribute', 109 | '0..1', 110 | { propertyTest: 'justATest' }, 111 | { 112 | default: 'attributeDataName', 113 | default2: 'attributeDataName' 114 | } 115 | ); 116 | } 117 | ); 118 | 119 | it('expect to not work with wrong arguments', function () { 120 | expect(function () { 121 | dateAttribute = new DateAttribute( 122 | 'attribute', 123 | '0..1', 124 | null, 125 | null, 126 | null 127 | ); 128 | }).to.throw(AssertionError); 129 | 130 | expect(function () { 131 | dateAttribute = new DateAttribute(function () {}); 132 | }).to.throw(AssertionError); 133 | 134 | expect(function () { 135 | dateAttribute = new DateAttribute({ 136 | multiplicity: '0..1', 137 | default: null, 138 | dataName: 'dataName' 139 | }); 140 | }).to.throw(AssertionError); 141 | 142 | expect(function () { 143 | dateAttribute = new DateAttribute({ 144 | name: null, 145 | multiplicity: '0..1', 146 | default: null, 147 | dataName: 'dataName' 148 | }); 149 | }).to.throw(AssertionError); 150 | 151 | expect(function () { 152 | dateAttribute = new DateAttribute({ 153 | name: 'attribute', 154 | multiplicity: '0..1', 155 | default: null, 156 | dataName: 'dataName', 157 | doesNotExist: null 158 | }); 159 | }).to.throw(AssertionError); 160 | 161 | expect(function () { 162 | dateAttribute = new DateAttribute({ 163 | name: 'attribute', 164 | type: 'Date', 165 | multiplicity: '0..1', 166 | default: null, 167 | dataName: 'dataName' 168 | }); 169 | }).to.throw(AssertionError); 170 | 171 | expect(function () { 172 | dateAttribute = new DateAttribute({ 173 | name: 'attribute', 174 | multiplicity: null, 175 | default: null, 176 | dataName: 'dataName' 177 | }); 178 | }).to.throw(AssertionError); 179 | 180 | expect(function () { 181 | dateAttribute = new DateAttribute({ 182 | name: 'attribute', 183 | multiplicity: '1', 184 | default: null, 185 | dataName: function () {} 186 | }); 187 | }).to.throw(AssertionError); 188 | }); 189 | 190 | it('expect to find correct typeName', function () { 191 | expect(DateAttribute).to.have.property('typeName') 192 | .that.equals('Date'); 193 | }); 194 | }); 195 | 196 | context('functional tests', function () { 197 | it('expect to be a specialization of Attribute', function () { 198 | expect(classes.isGeneral(Attribute, DateAttribute)).to.equal(true); 199 | 200 | expect(new DateAttribute('myDateAttribute')) 201 | .to.be.an.instanceof(Attribute); 202 | }); 203 | 204 | it('expect to have all properties storing the right values', function () { 205 | expect(dateAttribute).to.have.property('name') 206 | .that.equals('attribute'); 207 | 208 | expect(dateAttribute).to.have.property('type') 209 | .that.equals(DateAttribute); 210 | 211 | expect(dateAttribute).to.have.property('multiplicity') 212 | .that.equals('0..1'); 213 | 214 | expect(dateAttribute).to.have.property('default') 215 | .that.deep.equals({ propertyTest: 'justATest'}); 216 | 217 | expect(dateAttribute).to.have.property('dataName') 218 | .that.deep.equals( 219 | { 220 | default: 'attributeDataName', 221 | default2: 'attributeDataName' 222 | } 223 | ); 224 | }); 225 | 226 | it('expect to be not extensible', function () { 227 | expect(Object.isExtensible(dateAttribute)).to.equal(false); 228 | 229 | expect(function () { 230 | dateAttribute.doesNotExist = {}; 231 | }).to.throw(TypeError); 232 | 233 | expect(dateAttribute).to.not.respondTo('doesNotExist'); 234 | }); 235 | 236 | it('expect to not allow to delete property', function () { 237 | expect(function () { 238 | delete dateAttribute.name; 239 | }).to.throw(Error); 240 | 241 | expect(dateAttribute).to.have.property('name') 242 | .that.equals('attribute'); 243 | 244 | expect(function () { 245 | delete dateAttribute.type; 246 | }).to.throw(Error); 247 | 248 | expect(dateAttribute).to.have.property('type') 249 | .that.equals(DateAttribute); 250 | 251 | expect(function () { 252 | delete dateAttribute.multiplicity; 253 | }).to.throw(Error); 254 | 255 | expect(dateAttribute).to.have.property('multiplicity') 256 | .that.equals('0..1'); 257 | 258 | expect(function () { 259 | delete dateAttribute.default; 260 | }).to.throw(Error); 261 | 262 | expect(dateAttribute).to.have.property('default') 263 | .that.deep.equals({ propertyTest: 'justATest' }); 264 | 265 | expect(function () { 266 | delete dateAttribute.dataName; 267 | }).to.throw(Error); 268 | 269 | expect(dateAttribute).to.have.property('dataName') 270 | .that.deep.equals({ 271 | default: 'attributeDataName', 272 | default2: 'attributeDataName' 273 | }); 274 | }); 275 | 276 | it('expect to not allow to change property', function () { 277 | expect(function () { 278 | dateAttribute.name = 'will not change'; 279 | }).to.throw(Error); 280 | 281 | expect(dateAttribute).to.have.property('name') 282 | .that.equals('attribute'); 283 | 284 | expect(function () { 285 | dateAttribute.type = 'will not change'; 286 | }).to.throw(Error); 287 | 288 | expect(dateAttribute).to.have.property('type') 289 | .that.equals(DateAttribute); 290 | 291 | expect(function () { 292 | dateAttribute.multiplicity = 'will not change'; 293 | }).to.throw(Error); 294 | 295 | expect(dateAttribute).to.have.property('multiplicity') 296 | .that.equals('0..1'); 297 | 298 | expect(function () { 299 | dateAttribute.default = 'will not change'; 300 | }).to.throw(Error); 301 | 302 | expect(dateAttribute).to.have.property('default') 303 | .that.deep.equals({ propertyTest: 'justATest' }); 304 | 305 | expect(function () { 306 | dateAttribute.dataName = 'will not change'; 307 | }).to.throw(Error); 308 | 309 | expect(dateAttribute).to.have.property('dataName') 310 | .that.deep.equals({ 311 | default: 'attributeDataName', 312 | default2: 'attributeDataName' 313 | }); 314 | }); 315 | 316 | it('expect to have the right default values', function () { 317 | dateAttribute = new DateAttribute('attributeName'); 318 | 319 | expect(dateAttribute.name).to.equal('attributeName'); 320 | expect(dateAttribute.type).to.equal(DateAttribute); 321 | expect(dateAttribute.multiplicity).to.equal('1'); 322 | expect(dateAttribute.default).to.equal(null); 323 | expect(dateAttribute.dataName).to.equal(null); 324 | }); 325 | }); 326 | 327 | describe('#validateValue', function () { 328 | it('expect to work correctly', function () { 329 | dateAttribute.validateValue(new Date()); 330 | expect(function () { 331 | dateAttribute.validateValue(null); 332 | }).to.throw(ValidationError); 333 | expect(function () { 334 | dateAttribute.validateValue({}); 335 | }).to.throw(ValidationError); 336 | expect(function () { 337 | dateAttribute.validateValue(false); 338 | }).to.throw(ValidationError); 339 | expect(function () { 340 | dateAttribute.validateValue(true); 341 | }).to.throw(ValidationError); 342 | }); 343 | }); 344 | }); 345 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/index.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var AssertionError = chai.AssertionError; 9 | var expect = chai.expect; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var AttributeTypeNotFoundError = models.errors.AttributeTypeNotFoundError; 13 | var Attribute = models.attributes.Attribute; 14 | var attributesTypesIndex = require( 15 | '../../../../../../src/back/models/attributes/types' 16 | ); 17 | var AssociationAttribute = require( 18 | '../../../../../../src/back/models/attributes/types/AssociationAttribute' 19 | ); 20 | var BooleanAttribute = require( 21 | '../../../../../../src/back/models/attributes/types/BooleanAttribute' 22 | ); 23 | var DateAttribute = require( 24 | '../../../../../../src/back/models/attributes/types/DateAttribute' 25 | ); 26 | var NumberAttribute = require( 27 | '../../../../../../src/back/models/attributes/types/NumberAttribute' 28 | ); 29 | var ObjectAttribute = require( 30 | '../../../../../../src/back/models/attributes/types/ObjectAttribute' 31 | ); 32 | var StringAttribute = require( 33 | '../../../../../../src/back/models/attributes/types/StringAttribute' 34 | ); 35 | 36 | require('../../../../settings'); 37 | 38 | describe('attributesTypesIndex', function () { 39 | it( 40 | 'expect to export AssociationAttribute in the AssociationAttribute ' + 41 | 'property', 42 | function () { 43 | expect(attributesTypesIndex).to.have.property('AssociationAttribute') 44 | .that.equals(AssociationAttribute); 45 | } 46 | ); 47 | 48 | it( 49 | 'expect to export BooleanAttribute in the BooleanAttribute property', 50 | function () { 51 | expect(attributesTypesIndex).to.have.property('BooleanAttribute') 52 | .that.equals(BooleanAttribute); 53 | } 54 | ); 55 | 56 | it( 57 | 'expect to export DateAttribute in the DateAttribute property', 58 | function () { 59 | expect(attributesTypesIndex).to.have.property('DateAttribute') 60 | .that.equals(DateAttribute); 61 | } 62 | ); 63 | 64 | it( 65 | 'expect to export NumberAttribute in the NumberAttribute property', 66 | function () { 67 | expect(attributesTypesIndex).to.have.property('NumberAttribute') 68 | .that.equals(NumberAttribute); 69 | } 70 | ); 71 | 72 | it( 73 | 'expect to export ObjectAttribute in the ObjectAttribute property', 74 | function () { 75 | expect(attributesTypesIndex).to.have.property('ObjectAttribute') 76 | .that.equals(ObjectAttribute); 77 | } 78 | ); 79 | 80 | it( 81 | 'expect to export StringAttribute in the StringAttribute property', 82 | function () { 83 | expect(attributesTypesIndex).to.have.property('StringAttribute') 84 | .that.equals(StringAttribute); 85 | } 86 | ); 87 | 88 | describe('~get', function () { 89 | it( 90 | 'expect to export get function in the get property', 91 | function () { 92 | expect(attributesTypesIndex).to.have.property('get'); 93 | 94 | expect(attributesTypesIndex.get).to.be.a('function'); 95 | } 96 | ); 97 | 98 | it( 99 | 'expect to work with right argument and get the right type', 100 | function () { 101 | expect(attributesTypesIndex.get('ObjectAttribute')) 102 | .to.equal(ObjectAttribute); 103 | 104 | expect(attributesTypesIndex.get('Object')).to.equal(ObjectAttribute); 105 | 106 | attributesTypesIndex.MyCustomAttribute = MyCustomAttribute; 107 | 108 | function MyCustomAttribute() { 109 | Attribute.apply(this, Array.prototype.slice.call(arguments)); 110 | } 111 | 112 | classes.generalize(Attribute, MyCustomAttribute); 113 | 114 | expect(attributesTypesIndex.get('MyCustomAttribute')) 115 | .to.equal(MyCustomAttribute); 116 | 117 | expect(attributesTypesIndex.get('MyCustom')) 118 | .to.equal(MyCustomAttribute); 119 | } 120 | ); 121 | 122 | it('expect to not work with wrong arguments', function () { 123 | expect(function () { 124 | attributesTypesIndex.get(); 125 | }).to.throw(AssertionError); 126 | 127 | expect(function () { 128 | attributesTypesIndex.get('ObjectAttribute', null); 129 | }).to.throw(AssertionError); 130 | 131 | expect(function () { 132 | attributesTypesIndex.get(null); 133 | }).to.throw(AssertionError); 134 | }); 135 | 136 | it('expect to throw AttributeTypeNotFoundError when the Attribute type' + 137 | ' cannot be found', function () { 138 | expect(function () { 139 | attributesTypesIndex.get('NotExistent'); 140 | 141 | attributesTypesIndex.get('NotExistentAttribute'); 142 | 143 | attributesTypesIndex.get('bject'); 144 | 145 | attributesTypesIndex.get('bjectAttribute'); 146 | 147 | attributesTypesIndex.get('ObjectAttribut'); 148 | }).to.throw(AttributeTypeNotFoundError); 149 | }); 150 | 151 | it('expect to not be set', function () { 152 | expect(function () { 153 | attributesTypesIndex.get = function () {}; 154 | }).to.throw(Error); 155 | }); 156 | }); 157 | }); 158 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/numberAttribute.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var ValidationError = models.errors.ValidationError; 13 | var attributes = models.attributes; 14 | var Attribute = attributes.Attribute; 15 | var NumberAttribute = attributes.types.NumberAttribute; 16 | 17 | require('../../../../settings'); 18 | 19 | describe('NumberAttribute', function () { 20 | var numberAttribute; 21 | 22 | context('interface tests', function () { 23 | it('expect to not work without arguments', function () { 24 | expect(function () { 25 | numberAttribute = new NumberAttribute(); 26 | }).to.throw(AssertionError); 27 | }); 28 | 29 | it('expect to not work with null argument', function () { 30 | expect(function () { 31 | numberAttribute = new NumberAttribute(null); 32 | }).to.throw(AssertionError); 33 | }); 34 | 35 | it('expect to not work with empty object', function () { 36 | expect(function () { 37 | numberAttribute = new NumberAttribute({}); 38 | }).to.throw(AssertionError); 39 | }); 40 | 41 | it('expect to work with right arguments passing as an object', 42 | function () { 43 | numberAttribute = new NumberAttribute({ 44 | name: 'attribute' 45 | }); 46 | 47 | numberAttribute = new NumberAttribute({ 48 | name: 'attribute', 49 | default: null 50 | }); 51 | 52 | numberAttribute = new NumberAttribute({ 53 | name: 'attribute', 54 | multiplicity: '0..1' 55 | }); 56 | 57 | 58 | numberAttribute = new NumberAttribute({ 59 | name: 'attribute', 60 | multiplicity: '0..1', 61 | default: null 62 | }); 63 | 64 | numberAttribute = new NumberAttribute({ 65 | name: 'attribute', 66 | multiplicity: '0..1', 67 | default: null, 68 | dataName: 'attributeDataName' 69 | }); 70 | 71 | numberAttribute = new NumberAttribute({ 72 | name: 'attribute', 73 | multiplicity: '0..1', 74 | default: null, 75 | dataName: { 76 | default: 'attributeDataName', 77 | default2: 'attributeDataName' 78 | } 79 | }); 80 | } 81 | ); 82 | 83 | it('expect to work with right arguments passing as arguments', 84 | function () { 85 | numberAttribute = new NumberAttribute( 86 | 'attribute' 87 | ); 88 | 89 | numberAttribute = new NumberAttribute( 90 | 'attribute', 91 | '0..1' 92 | ); 93 | 94 | numberAttribute = new NumberAttribute( 95 | 'attribute', 96 | '0..1', 97 | { propertyTest: 'justATest' } 98 | ); 99 | 100 | numberAttribute = new NumberAttribute( 101 | 'attribute', 102 | '0..1', 103 | { propertyTest: 'justATest' }, 104 | 'attributeDataName' 105 | ); 106 | 107 | numberAttribute = new NumberAttribute( 108 | 'attribute', 109 | '0..1', 110 | { propertyTest: 'justATest' }, 111 | { 112 | default: 'attributeDataName', 113 | default2: 'attributeDataName' 114 | } 115 | ); 116 | } 117 | ); 118 | 119 | it('expect to not work with wrong arguments', function () { 120 | expect(function () { 121 | numberAttribute = new NumberAttribute( 122 | 'attribute', 123 | '0..1', 124 | null, 125 | null, 126 | null 127 | ); 128 | }).to.throw(AssertionError); 129 | 130 | expect(function () { 131 | numberAttribute = new NumberAttribute(function () {}); 132 | }).to.throw(AssertionError); 133 | 134 | expect(function () { 135 | numberAttribute = new NumberAttribute({ 136 | multiplicity: '0..1', 137 | default: null, 138 | dataName: 'dataName' 139 | }); 140 | }).to.throw(AssertionError); 141 | 142 | expect(function () { 143 | numberAttribute = new NumberAttribute({ 144 | name: null, 145 | multiplicity: '0..1', 146 | default: null, 147 | dataName: 'dataName' 148 | }); 149 | }).to.throw(AssertionError); 150 | 151 | expect(function () { 152 | numberAttribute = new NumberAttribute({ 153 | name: 'attribute', 154 | multiplicity: '0..1', 155 | default: null, 156 | dataName: 'dataName', 157 | doesNotExist: null 158 | }); 159 | }).to.throw(AssertionError); 160 | 161 | expect(function () { 162 | numberAttribute = new NumberAttribute({ 163 | name: 'attribute', 164 | type: 'Number', 165 | multiplicity: '0..1', 166 | default: null, 167 | dataName: 'dataName' 168 | }); 169 | }).to.throw(AssertionError); 170 | 171 | expect(function () { 172 | numberAttribute = new NumberAttribute({ 173 | name: 'attribute', 174 | multiplicity: null, 175 | default: null, 176 | dataName: 'dataName' 177 | }); 178 | }).to.throw(AssertionError); 179 | 180 | expect(function () { 181 | numberAttribute = new NumberAttribute({ 182 | name: 'attribute', 183 | multiplicity: '1', 184 | default: null, 185 | dataName: function () {} 186 | }); 187 | }).to.throw(AssertionError); 188 | }); 189 | 190 | it('expect to find correct typeName', function () { 191 | expect(NumberAttribute).to.have.property('typeName') 192 | .that.equals('Number'); 193 | }); 194 | }); 195 | 196 | context('functional tests', function () { 197 | it('expect to be a specialization of Attribute', function () { 198 | expect(classes.isGeneral(Attribute, NumberAttribute)).to.equal(true); 199 | 200 | expect(new NumberAttribute('myNumberAttribute')) 201 | .to.be.an.instanceof(Attribute); 202 | }); 203 | 204 | it('expect to have all properties storing the right values', function () { 205 | expect(numberAttribute).to.have.property('name') 206 | .that.equals('attribute'); 207 | 208 | expect(numberAttribute).to.have.property('type') 209 | .that.equals(NumberAttribute); 210 | 211 | expect(numberAttribute).to.have.property('multiplicity') 212 | .that.equals('0..1'); 213 | 214 | expect(numberAttribute).to.have.property('default') 215 | .that.deep.equals({ propertyTest: 'justATest'}); 216 | 217 | expect(numberAttribute).to.have.property('dataName') 218 | .that.deep.equals( 219 | { 220 | default: 'attributeDataName', 221 | default2: 'attributeDataName' 222 | } 223 | ); 224 | }); 225 | 226 | it('expect to be not extensible', function () { 227 | expect(Object.isExtensible(numberAttribute)).to.equal(false); 228 | 229 | expect(function () { 230 | numberAttribute.doesNotExist = {}; 231 | }).to.throw(TypeError); 232 | 233 | expect(numberAttribute).to.not.respondTo('doesNotExist'); 234 | }); 235 | 236 | it('expect to not allow to delete property', function () { 237 | expect(function () { 238 | delete numberAttribute.name; 239 | }).to.throw(Error); 240 | 241 | expect(numberAttribute).to.have.property('name') 242 | .that.equals('attribute'); 243 | 244 | expect(function () { 245 | delete numberAttribute.type; 246 | }).to.throw(Error); 247 | 248 | expect(numberAttribute).to.have.property('type') 249 | .that.equals(NumberAttribute); 250 | 251 | expect(function () { 252 | delete numberAttribute.multiplicity; 253 | }).to.throw(Error); 254 | 255 | expect(numberAttribute).to.have.property('multiplicity') 256 | .that.equals('0..1'); 257 | 258 | expect(function () { 259 | delete numberAttribute.default; 260 | }).to.throw(Error); 261 | 262 | expect(numberAttribute).to.have.property('default') 263 | .that.deep.equals({ propertyTest: 'justATest' }); 264 | 265 | expect(function () { 266 | delete numberAttribute.dataName; 267 | }).to.throw(Error); 268 | 269 | expect(numberAttribute).to.have.property('dataName') 270 | .that.deep.equals({ 271 | default: 'attributeDataName', 272 | default2: 'attributeDataName' 273 | }); 274 | }); 275 | 276 | it('expect to not allow to change property', function () { 277 | expect(function () { 278 | numberAttribute.name = 'will not change'; 279 | }).to.throw(Error); 280 | 281 | expect(numberAttribute).to.have.property('name') 282 | .that.equals('attribute'); 283 | 284 | expect(function () { 285 | numberAttribute.type = 'will not change'; 286 | }).to.throw(Error); 287 | 288 | expect(numberAttribute).to.have.property('type') 289 | .that.equals(NumberAttribute); 290 | 291 | expect(function () { 292 | numberAttribute.multiplicity = 'will not change'; 293 | }).to.throw(Error); 294 | 295 | expect(numberAttribute).to.have.property('multiplicity') 296 | .that.equals('0..1'); 297 | 298 | expect(function () { 299 | numberAttribute.default = 'will not change'; 300 | }).to.throw(Error); 301 | 302 | expect(numberAttribute).to.have.property('default') 303 | .that.deep.equals({ propertyTest: 'justATest' }); 304 | 305 | expect(function () { 306 | numberAttribute.dataName = 'will not change'; 307 | }).to.throw(Error); 308 | 309 | expect(numberAttribute).to.have.property('dataName') 310 | .that.deep.equals({ 311 | default: 'attributeDataName', 312 | default2: 'attributeDataName' 313 | }); 314 | }); 315 | 316 | it('expect to have the right default values', function () { 317 | numberAttribute = new NumberAttribute('attributeName'); 318 | 319 | expect(numberAttribute.name).to.equal('attributeName'); 320 | expect(numberAttribute.type).to.equal(NumberAttribute); 321 | expect(numberAttribute.multiplicity).to.equal('1'); 322 | expect(numberAttribute.default).to.equal(null); 323 | expect(numberAttribute.dataName).to.equal(null); 324 | }); 325 | }); 326 | 327 | describe('#validateValue', function () { 328 | it('expect to work correctly', function () { 329 | numberAttribute.validateValue(1.5); 330 | numberAttribute.validateValue(1); 331 | numberAttribute.validateValue(0); 332 | /* jshint ignore:start */ 333 | numberAttribute.validateValue(new Number()); 334 | /* jshint ignore:end */ 335 | expect(function () { 336 | numberAttribute.validateValue(null); 337 | }).to.throw(ValidationError); 338 | expect(function () { 339 | numberAttribute.validateValue({}); 340 | }).to.throw(ValidationError); 341 | expect(function () { 342 | numberAttribute.validateValue(false); 343 | }).to.throw(ValidationError); 344 | expect(function () { 345 | numberAttribute.validateValue(true); 346 | }).to.throw(ValidationError); 347 | }); 348 | }); 349 | }); 350 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/objectAttribute.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 08/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var ValidationError = models.errors.ValidationError; 13 | var attributes = models.attributes; 14 | var Attribute = attributes.Attribute; 15 | var ObjectAttribute = attributes.types.ObjectAttribute; 16 | var EntityProxy = require('../../EntityProxy'); 17 | 18 | require('../../../../settings'); 19 | 20 | describe('ObjectAttribute', function () { 21 | var objectAttribute; 22 | 23 | context('interface tests', function () { 24 | it('expect to not work without arguments', function () { 25 | expect(function () { 26 | objectAttribute = new ObjectAttribute(); 27 | }).to.throw(AssertionError); 28 | }); 29 | 30 | it('expect to not work with null argument', function () { 31 | expect(function () { 32 | objectAttribute = new ObjectAttribute(null); 33 | }).to.throw(AssertionError); 34 | }); 35 | 36 | it('expect to not work with empty object', function () { 37 | expect(function () { 38 | objectAttribute = new ObjectAttribute({}); 39 | }).to.throw(AssertionError); 40 | }); 41 | 42 | it('expect to work with right arguments passing as an object', 43 | function () { 44 | objectAttribute = new ObjectAttribute({ 45 | name: 'attribute' 46 | }); 47 | 48 | objectAttribute = new ObjectAttribute({ 49 | name: 'attribute', 50 | default: null 51 | }); 52 | 53 | objectAttribute = new ObjectAttribute({ 54 | name: 'attribute', 55 | multiplicity: '0..1' 56 | }); 57 | 58 | 59 | objectAttribute = new ObjectAttribute({ 60 | name: 'attribute', 61 | multiplicity: '0..1', 62 | default: null 63 | }); 64 | 65 | objectAttribute = new ObjectAttribute({ 66 | name: 'attribute', 67 | multiplicity: '0..1', 68 | default: null, 69 | dataName: 'attributeDataName' 70 | }); 71 | 72 | objectAttribute = new ObjectAttribute({ 73 | name: 'attribute', 74 | multiplicity: '0..1', 75 | default: null, 76 | dataName: { 77 | default: 'attributeDataName', 78 | default2: 'attributeDataName' 79 | } 80 | }); 81 | } 82 | ); 83 | 84 | it('expect to work with right arguments passing as arguments', 85 | function () { 86 | objectAttribute = new ObjectAttribute( 87 | 'attribute' 88 | ); 89 | 90 | objectAttribute = new ObjectAttribute( 91 | 'attribute', 92 | '0..1' 93 | ); 94 | 95 | objectAttribute = new ObjectAttribute( 96 | 'attribute', 97 | '0..1', 98 | { propertyTest: 'justATest' } 99 | ); 100 | 101 | objectAttribute = new ObjectAttribute( 102 | 'attribute', 103 | '0..1', 104 | { propertyTest: 'justATest' }, 105 | 'attributeDataName' 106 | ); 107 | 108 | objectAttribute = new ObjectAttribute( 109 | 'attribute', 110 | '0..1', 111 | { propertyTest: 'justATest' }, 112 | { 113 | default: 'attributeDataName', 114 | default2: 'attributeDataName' 115 | } 116 | ); 117 | } 118 | ); 119 | 120 | it('expect to not work with wrong arguments', function () { 121 | expect(function () { 122 | objectAttribute = new ObjectAttribute( 123 | 'attribute', 124 | '0..1', 125 | null, 126 | null, 127 | null 128 | ); 129 | }).to.throw(AssertionError); 130 | 131 | expect(function () { 132 | objectAttribute = new ObjectAttribute(function () {}); 133 | }).to.throw(AssertionError); 134 | 135 | expect(function () { 136 | objectAttribute = new ObjectAttribute({ 137 | multiplicity: '0..1', 138 | default: null, 139 | dataName: 'dataName' 140 | }); 141 | }).to.throw(AssertionError); 142 | 143 | expect(function () { 144 | objectAttribute = new ObjectAttribute({ 145 | name: null, 146 | multiplicity: '0..1', 147 | default: null, 148 | dataName: 'dataName' 149 | }); 150 | }).to.throw(AssertionError); 151 | 152 | expect(function () { 153 | objectAttribute = new ObjectAttribute({ 154 | name: 'attribute', 155 | multiplicity: '0..1', 156 | default: null, 157 | dataName: 'dataName', 158 | doesNotExist: null 159 | }); 160 | }).to.throw(AssertionError); 161 | 162 | expect(function () { 163 | objectAttribute = new ObjectAttribute({ 164 | name: 'attribute', 165 | type: 'Object', 166 | multiplicity: '0..1', 167 | default: null, 168 | dataName: 'dataName' 169 | }); 170 | }).to.throw(AssertionError); 171 | 172 | expect(function () { 173 | objectAttribute = new ObjectAttribute({ 174 | name: 'attribute', 175 | multiplicity: null, 176 | default: null, 177 | dataName: 'dataName' 178 | }); 179 | }).to.throw(AssertionError); 180 | 181 | expect(function () { 182 | objectAttribute = new ObjectAttribute({ 183 | name: 'attribute', 184 | multiplicity: '1', 185 | default: null, 186 | dataName: function () {} 187 | }); 188 | }).to.throw(AssertionError); 189 | }); 190 | 191 | it('expect to find correct typeName', function () { 192 | expect(ObjectAttribute).to.have.property('typeName') 193 | .that.equals('Object'); 194 | }); 195 | }); 196 | 197 | context('functional tests', function () { 198 | it('expect to be a specialization of Attribute', function () { 199 | expect(classes.isGeneral(Attribute, ObjectAttribute)).to.equal(true); 200 | 201 | expect(new ObjectAttribute('myObjectAttribute')) 202 | .to.be.an.instanceof(Attribute); 203 | }); 204 | 205 | it('expect to have all properties storing the right values', function () { 206 | expect(objectAttribute).to.have.property('name') 207 | .that.equals('attribute'); 208 | 209 | expect(objectAttribute).to.have.property('type') 210 | .that.equals(ObjectAttribute); 211 | 212 | expect(objectAttribute).to.have.property('multiplicity') 213 | .that.equals('0..1'); 214 | 215 | expect(objectAttribute).to.have.property('default') 216 | .that.deep.equals({ propertyTest: 'justATest'}); 217 | 218 | expect(objectAttribute).to.have.property('dataName') 219 | .that.deep.equals( 220 | { 221 | default: 'attributeDataName', 222 | default2: 'attributeDataName' 223 | } 224 | ); 225 | }); 226 | 227 | it('expect to be not extensible', function () { 228 | expect(Object.isExtensible(objectAttribute)).to.equal(false); 229 | 230 | expect(function () { 231 | objectAttribute.doesNotExist = {}; 232 | }).to.throw(TypeError); 233 | 234 | expect(objectAttribute).to.not.respondTo('doesNotExist'); 235 | }); 236 | 237 | it('expect to not allow to delete property', function () { 238 | expect(function () { 239 | delete objectAttribute.name; 240 | }).to.throw(Error); 241 | 242 | expect(objectAttribute).to.have.property('name') 243 | .that.equals('attribute'); 244 | 245 | expect(function () { 246 | delete objectAttribute.type; 247 | }).to.throw(Error); 248 | 249 | expect(objectAttribute).to.have.property('type') 250 | .that.equals(ObjectAttribute); 251 | 252 | expect(function () { 253 | delete objectAttribute.multiplicity; 254 | }).to.throw(Error); 255 | 256 | expect(objectAttribute).to.have.property('multiplicity') 257 | .that.equals('0..1'); 258 | 259 | expect(function () { 260 | delete objectAttribute.default; 261 | }).to.throw(Error); 262 | 263 | expect(objectAttribute).to.have.property('default') 264 | .that.deep.equals({ propertyTest: 'justATest' }); 265 | 266 | expect(function () { 267 | delete objectAttribute.dataName; 268 | }).to.throw(Error); 269 | 270 | expect(objectAttribute).to.have.property('dataName') 271 | .that.deep.equals({ 272 | default: 'attributeDataName', 273 | default2: 'attributeDataName' 274 | }); 275 | }); 276 | 277 | it('expect to not allow to change property', function () { 278 | expect(function () { 279 | objectAttribute.name = 'will not change'; 280 | }).to.throw(Error); 281 | 282 | expect(objectAttribute).to.have.property('name') 283 | .that.equals('attribute'); 284 | 285 | expect(function () { 286 | objectAttribute.type = 'will not change'; 287 | }).to.throw(Error); 288 | 289 | expect(objectAttribute).to.have.property('type') 290 | .that.equals(ObjectAttribute); 291 | 292 | expect(function () { 293 | objectAttribute.multiplicity = 'will not change'; 294 | }).to.throw(Error); 295 | 296 | expect(objectAttribute).to.have.property('multiplicity') 297 | .that.equals('0..1'); 298 | 299 | expect(function () { 300 | objectAttribute.default = 'will not change'; 301 | }).to.throw(Error); 302 | 303 | expect(objectAttribute).to.have.property('default') 304 | .that.deep.equals({ propertyTest: 'justATest' }); 305 | 306 | expect(function () { 307 | objectAttribute.dataName = 'will not change'; 308 | }).to.throw(Error); 309 | 310 | expect(objectAttribute).to.have.property('dataName') 311 | .that.deep.equals({ 312 | default: 'attributeDataName', 313 | default2: 'attributeDataName' 314 | }); 315 | }); 316 | 317 | it('expect to have the right default values', function () { 318 | objectAttribute = new ObjectAttribute('attributeName'); 319 | 320 | expect(objectAttribute.name).to.equal('attributeName'); 321 | expect(objectAttribute.type).to.equal(ObjectAttribute); 322 | expect(objectAttribute.multiplicity).to.equal('1'); 323 | expect(objectAttribute.default).to.equal(null); 324 | expect(objectAttribute.dataName).to.equal(null); 325 | }); 326 | }); 327 | 328 | describe('#validateValue', function () { 329 | it('expect to work correctly', function () { 330 | objectAttribute.validateValue({}); 331 | objectAttribute.validateValue(new Date()); 332 | objectAttribute.validateValue(new EntityProxy()); 333 | expect(function () { 334 | objectAttribute.validateValue(1); 335 | }).to.throw(ValidationError); 336 | expect(function () { 337 | objectAttribute.validateValue(null); 338 | }).to.throw(ValidationError); 339 | expect(function () { 340 | objectAttribute.validateValue(function () {}); 341 | }).to.throw(ValidationError); 342 | expect(function () { 343 | objectAttribute.validateValue(false); 344 | }).to.throw(ValidationError); 345 | expect(function () { 346 | objectAttribute.validateValue(true); 347 | }).to.throw(ValidationError); 348 | }); 349 | }); 350 | }); 351 | -------------------------------------------------------------------------------- /tests/unit/back/models/attributes/types/stringAttribute.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../../../src/back/utils').classes; 11 | var models = require('../../../../../../').models; 12 | var ValidationError = models.errors.ValidationError; 13 | var attributes = models.attributes; 14 | var Attribute = attributes.Attribute; 15 | var StringAttribute = attributes.types.StringAttribute; 16 | 17 | require('../../../../settings'); 18 | 19 | describe('StringAttribute', function () { 20 | var stringAttribute; 21 | 22 | context('interface tests', function () { 23 | it('expect to not work without arguments', function () { 24 | expect(function () { 25 | stringAttribute = new StringAttribute(); 26 | }).to.throw(AssertionError); 27 | }); 28 | 29 | it('expect to not work with null argument', function () { 30 | expect(function () { 31 | stringAttribute = new StringAttribute(null); 32 | }).to.throw(AssertionError); 33 | }); 34 | 35 | it('expect to not work with empty object', function () { 36 | expect(function () { 37 | stringAttribute = new StringAttribute({}); 38 | }).to.throw(AssertionError); 39 | }); 40 | 41 | it('expect to work with right arguments passing as an object', 42 | function () { 43 | stringAttribute = new StringAttribute({ 44 | name: 'attribute' 45 | }); 46 | 47 | stringAttribute = new StringAttribute({ 48 | name: 'attribute', 49 | default: null 50 | }); 51 | 52 | stringAttribute = new StringAttribute({ 53 | name: 'attribute', 54 | multiplicity: '0..1' 55 | }); 56 | 57 | 58 | stringAttribute = new StringAttribute({ 59 | name: 'attribute', 60 | multiplicity: '0..1', 61 | default: null 62 | }); 63 | 64 | stringAttribute = new StringAttribute({ 65 | name: 'attribute', 66 | multiplicity: '0..1', 67 | default: null, 68 | dataName: 'attributeDataName' 69 | }); 70 | 71 | stringAttribute = new StringAttribute({ 72 | name: 'attribute', 73 | multiplicity: '0..1', 74 | default: null, 75 | dataName: { 76 | default: 'attributeDataName', 77 | default2: 'attributeDataName' 78 | } 79 | }); 80 | } 81 | ); 82 | 83 | it('expect to work with right arguments passing as arguments', 84 | function () { 85 | stringAttribute = new StringAttribute( 86 | 'attribute' 87 | ); 88 | 89 | stringAttribute = new StringAttribute( 90 | 'attribute', 91 | '0..1' 92 | ); 93 | 94 | stringAttribute = new StringAttribute( 95 | 'attribute', 96 | '0..1', 97 | { propertyTest: 'justATest' } 98 | ); 99 | 100 | stringAttribute = new StringAttribute( 101 | 'attribute', 102 | '0..1', 103 | { propertyTest: 'justATest' }, 104 | 'attributeDataName' 105 | ); 106 | 107 | stringAttribute = new StringAttribute( 108 | 'attribute', 109 | '0..1', 110 | { propertyTest: 'justATest' }, 111 | { 112 | default: 'attributeDataName', 113 | default2: 'attributeDataName' 114 | } 115 | ); 116 | } 117 | ); 118 | 119 | it('expect to not work with wrong arguments', function () { 120 | expect(function () { 121 | stringAttribute = new StringAttribute( 122 | 'attribute', 123 | '0..1', 124 | null, 125 | null, 126 | null 127 | ); 128 | }).to.throw(AssertionError); 129 | 130 | expect(function () { 131 | stringAttribute = new StringAttribute(function () {}); 132 | }).to.throw(AssertionError); 133 | 134 | expect(function () { 135 | stringAttribute = new StringAttribute({ 136 | multiplicity: '0..1', 137 | default: null, 138 | dataName: 'dataName' 139 | }); 140 | }).to.throw(AssertionError); 141 | 142 | expect(function () { 143 | stringAttribute = new StringAttribute({ 144 | name: null, 145 | multiplicity: '0..1', 146 | default: null, 147 | dataName: 'dataName' 148 | }); 149 | }).to.throw(AssertionError); 150 | 151 | expect(function () { 152 | stringAttribute = new StringAttribute({ 153 | name: 'attribute', 154 | multiplicity: '0..1', 155 | default: null, 156 | dataName: 'dataName', 157 | doesNotExist: null 158 | }); 159 | }).to.throw(AssertionError); 160 | 161 | expect(function () { 162 | stringAttribute = new StringAttribute({ 163 | name: 'attribute', 164 | type: 'String', 165 | multiplicity: '0..1', 166 | default: null, 167 | dataName: 'dataName' 168 | }); 169 | }).to.throw(AssertionError); 170 | 171 | expect(function () { 172 | stringAttribute = new StringAttribute({ 173 | name: 'attribute', 174 | multiplicity: null, 175 | default: null, 176 | dataName: 'dataName' 177 | }); 178 | }).to.throw(AssertionError); 179 | 180 | expect(function () { 181 | stringAttribute = new StringAttribute({ 182 | name: 'attribute', 183 | multiplicity: '1', 184 | default: null, 185 | dataName: function () {} 186 | }); 187 | }).to.throw(AssertionError); 188 | }); 189 | 190 | it('expect to find correct typeName', function () { 191 | expect(StringAttribute).to.have.property('typeName') 192 | .that.equals('String'); 193 | }); 194 | }); 195 | 196 | context('functional tests', function () { 197 | it('expect to be a specialization of Attribute', function () { 198 | expect(classes.isGeneral(Attribute, StringAttribute)).to.equal(true); 199 | 200 | expect(new StringAttribute('myStringAttribute')) 201 | .to.be.an.instanceof(Attribute); 202 | }); 203 | 204 | it('expect to have all properties storing the right values', function () { 205 | expect(stringAttribute).to.have.property('name') 206 | .that.equals('attribute'); 207 | 208 | expect(stringAttribute).to.have.property('type') 209 | .that.equals(StringAttribute); 210 | 211 | expect(stringAttribute).to.have.property('multiplicity') 212 | .that.equals('0..1'); 213 | 214 | expect(stringAttribute).to.have.property('default') 215 | .that.deep.equals({ propertyTest: 'justATest'}); 216 | 217 | expect(stringAttribute).to.have.property('dataName') 218 | .that.deep.equals( 219 | { 220 | default: 'attributeDataName', 221 | default2: 'attributeDataName' 222 | } 223 | ); 224 | }); 225 | 226 | it('expect to be not extensible', function () { 227 | expect(Object.isExtensible(stringAttribute)).to.equal(false); 228 | 229 | expect(function () { 230 | stringAttribute.doesNotExist = {}; 231 | }).to.throw(TypeError); 232 | 233 | expect(stringAttribute).to.not.respondTo('doesNotExist'); 234 | }); 235 | 236 | it('expect to not allow to delete property', function () { 237 | expect(function () { 238 | delete stringAttribute.name; 239 | }).to.throw(Error); 240 | 241 | expect(stringAttribute).to.have.property('name') 242 | .that.equals('attribute'); 243 | 244 | expect(function () { 245 | delete stringAttribute.type; 246 | }).to.throw(Error); 247 | 248 | expect(stringAttribute).to.have.property('type') 249 | .that.equals(StringAttribute); 250 | 251 | expect(function () { 252 | delete stringAttribute.multiplicity; 253 | }).to.throw(Error); 254 | 255 | expect(stringAttribute).to.have.property('multiplicity') 256 | .that.equals('0..1'); 257 | 258 | expect(function () { 259 | delete stringAttribute.default; 260 | }).to.throw(Error); 261 | 262 | expect(stringAttribute).to.have.property('default') 263 | .that.deep.equals({ propertyTest: 'justATest' }); 264 | 265 | expect(function () { 266 | delete stringAttribute.dataName; 267 | }).to.throw(Error); 268 | 269 | expect(stringAttribute).to.have.property('dataName') 270 | .that.deep.equals({ 271 | default: 'attributeDataName', 272 | default2: 'attributeDataName' 273 | }); 274 | }); 275 | 276 | it('expect to not allow to change property', function () { 277 | expect(function () { 278 | stringAttribute.name = 'will not change'; 279 | }).to.throw(Error); 280 | 281 | expect(stringAttribute).to.have.property('name') 282 | .that.equals('attribute'); 283 | 284 | expect(function () { 285 | stringAttribute.type = 'will not change'; 286 | }).to.throw(Error); 287 | 288 | expect(stringAttribute).to.have.property('type') 289 | .that.equals(StringAttribute); 290 | 291 | expect(function () { 292 | stringAttribute.multiplicity = 'will not change'; 293 | }).to.throw(Error); 294 | 295 | expect(stringAttribute).to.have.property('multiplicity') 296 | .that.equals('0..1'); 297 | 298 | expect(function () { 299 | stringAttribute.default = 'will not change'; 300 | }).to.throw(Error); 301 | 302 | expect(stringAttribute).to.have.property('default') 303 | .that.deep.equals({ propertyTest: 'justATest' }); 304 | 305 | expect(function () { 306 | stringAttribute.dataName = 'will not change'; 307 | }).to.throw(Error); 308 | 309 | expect(stringAttribute).to.have.property('dataName') 310 | .that.deep.equals({ 311 | default: 'attributeDataName', 312 | default2: 'attributeDataName' 313 | }); 314 | }); 315 | 316 | it('expect to have the right default values', function () { 317 | stringAttribute = new StringAttribute('attributeName'); 318 | 319 | expect(stringAttribute.name).to.equal('attributeName'); 320 | expect(stringAttribute.type).to.equal(StringAttribute); 321 | expect(stringAttribute.multiplicity).to.equal('1'); 322 | expect(stringAttribute.default).to.equal(null); 323 | expect(stringAttribute.dataName).to.equal(null); 324 | }); 325 | }); 326 | 327 | describe('#validateValue', function () { 328 | it('expect to work correctly', function () { 329 | stringAttribute.validateValue(''); 330 | stringAttribute.validateValue('anything'); 331 | /* jshint ignore:start */ 332 | stringAttribute.validateValue(new String()); 333 | /* jshint ignore:end */ 334 | expect(function () { 335 | stringAttribute.validateValue(1); 336 | }).to.throw(ValidationError); 337 | expect(function () { 338 | stringAttribute.validateValue(null); 339 | }).to.throw(ValidationError); 340 | expect(function () { 341 | stringAttribute.validateValue(function () {}); 342 | }).to.throw(ValidationError); 343 | expect(function () { 344 | stringAttribute.validateValue(false); 345 | }).to.throw(ValidationError); 346 | expect(function () { 347 | stringAttribute.validateValue(true); 348 | }).to.throw(ValidationError); 349 | }); 350 | }); 351 | }); 352 | -------------------------------------------------------------------------------- /tests/unit/back/models/index.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var modelsIndex = require('../../../..//src/back/models'); 9 | var Entity = require('../../../../src/back/models/Entity'); 10 | var EntitySpecification = require( 11 | '../../../../src/back/models/EntitySpecification' 12 | ); 13 | var attributes = require('../../../../src/back/models/attributes'); 14 | var methods = require('../../../../src/back/models/methods'); 15 | var errors = require('../../../../src/back/models/errors'); 16 | 17 | require('../../settings'); 18 | 19 | describe('modelsIndex', function () { 20 | it('expect to export Entity in the Entity property', function () { 21 | expect(modelsIndex).to.have.property('Entity') 22 | .that.equals(Entity); 23 | }); 24 | 25 | it( 26 | 'expect to export EntitySpecification in the EntitySpecification property', 27 | function () { 28 | expect(modelsIndex).to.have.property('EntitySpecification') 29 | .that.equals(EntitySpecification); 30 | } 31 | ); 32 | 33 | it('expect to export attributes in the attributes property', function () { 34 | expect(modelsIndex).to.have.property('attributes') 35 | .that.equals(attributes); 36 | }); 37 | 38 | it('expect to export methods in the methods property', function () { 39 | expect(modelsIndex).to.have.property('methods') 40 | .that.equals(methods); 41 | }); 42 | 43 | it('expect to export errors in the errors property', function () { 44 | expect(modelsIndex).to.have.property('errors') 45 | .that.equals(errors); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /tests/unit/back/models/methods.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 02/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var methods = require('../../../../').models.methods; 11 | 12 | require('../../settings'); 13 | 14 | describe('methods', function () { 15 | it( 16 | 'expect to export MethodDictionary in the MethodDictionary property', 17 | function () { 18 | expect(methods).to.have.property('MethodDictionary'); 19 | } 20 | ); 21 | 22 | describe('MethodDictionary', function () { 23 | var methodDictionary; 24 | 25 | context('interface tests', function () { 26 | it('expect to work without arguments', function () { 27 | methodDictionary = new methods.MethodDictionary(); 28 | }); 29 | 30 | it('expect to work with null argument', function () { 31 | methodDictionary = new methods.MethodDictionary(null); 32 | }); 33 | 34 | it('expect to work with empty object', function () { 35 | methodDictionary = new methods.MethodDictionary({}); 36 | }); 37 | 38 | it('expect to work with right arguments', function () { 39 | methodDictionary = new methods.MethodDictionary({ 40 | method1: function () { return 'method1'; }, 41 | method2: function () { return 'method2'; } 42 | }); 43 | }); 44 | 45 | it('expect to not work with wrong arguments', function () { 46 | expect(function () { 47 | methodDictionary = new methods.MethodDictionary({}, {}); 48 | }).to.throw(AssertionError); 49 | 50 | expect(function () { 51 | methodDictionary = new methods.MethodDictionary(function () {}); 52 | }).to.throw(AssertionError); 53 | 54 | expect(function () { 55 | methodDictionary = new methods.MethodDictionary({ 56 | method1: {} 57 | }); 58 | }).to.throw(AssertionError); 59 | }); 60 | }); 61 | 62 | context('functional tests', function () { 63 | it('expect to allow execute functions correctly', function () { 64 | expect(methodDictionary.method1()).to.equal('method1'); 65 | expect(methodDictionary.method2()).to.equal('method2'); 66 | }); 67 | 68 | it('expect to allow to list methods', function () { 69 | var methods = []; 70 | 71 | for (var method in methodDictionary) { 72 | methods.push(method); 73 | } 74 | 75 | expect(methods).to.be.deep.equal(['method1', 'method2']); 76 | }); 77 | 78 | it('expect to be not extensible', function () { 79 | expect(Object.isExtensible(methodDictionary)).to.equal(false); 80 | 81 | expect(function () { 82 | methodDictionary.method3 = function () { 83 | return 'will never execute'; 84 | }; 85 | }).to.throw(TypeError); 86 | 87 | expect(methodDictionary).to.not.respondTo('method3'); 88 | }); 89 | 90 | it('expect to not allow to delete method', function () { 91 | expect(function () { 92 | delete methodDictionary.method1; 93 | }).to.throw(Error); 94 | 95 | expect(methodDictionary).to.respondTo('method1'); 96 | }); 97 | 98 | it('expect to not allow to change method', function () { 99 | expect(function () { 100 | methodDictionary.method1 = function () { 101 | return 'will never execute'; 102 | }; 103 | }).to.throw(Error); 104 | 105 | expect(methodDictionary.method1()).to.equal('method1'); 106 | }); 107 | }); 108 | 109 | describe('.concat', function () { 110 | var methodDictionary; 111 | var concatenatedMethodDictionary; 112 | 113 | it( 114 | 'expect to work with right arguments and have specified behavior', 115 | function () { 116 | methodDictionary = new methods.MethodDictionary({ 117 | method1: function () { return 'method1'; }, 118 | method2: function () { return 'method2'; } 119 | }); 120 | 121 | concatenatedMethodDictionary = 122 | methods.MethodDictionary.concat( 123 | methodDictionary, 124 | function () { return 'method3'; }, 125 | 'method3' 126 | ); 127 | 128 | expect(concatenatedMethodDictionary) 129 | .to.not.deep.equal(methodDictionary); 130 | 131 | expect(Object.keys(concatenatedMethodDictionary)) 132 | .to.deep.equal(['method1', 'method2', 'method3']); 133 | 134 | expect(concatenatedMethodDictionary.method1()) 135 | .to.equal('method1'); 136 | expect(concatenatedMethodDictionary.method2()) 137 | .to.equal('method2'); 138 | expect(concatenatedMethodDictionary.method3()) 139 | .to.equal('method3'); 140 | } 141 | ); 142 | 143 | it('expect to not work with wrong arguments', function () { 144 | expect(function () { 145 | concatenatedMethodDictionary = 146 | methods.MethodDictionary.concat( 147 | methodDictionary, 148 | function () { return 'method3'; } 149 | ); 150 | }).to.throw(AssertionError); 151 | 152 | expect(function () { 153 | concatenatedMethodDictionary = 154 | methods.MethodDictionary.concat( 155 | methodDictionary, 156 | function () { return 'method3'; }, 157 | 'method3', 158 | null 159 | ); 160 | }).to.throw(AssertionError); 161 | 162 | expect(function () { 163 | concatenatedMethodDictionary = 164 | methods.MethodDictionary.concat( 165 | {}, 166 | function () { return 'method3'; }, 167 | 'method3' 168 | ); 169 | }).to.throw(AssertionError); 170 | 171 | expect(function () { 172 | concatenatedMethodDictionary = 173 | methods.MethodDictionary.concat( 174 | methodDictionary, 175 | {}, 176 | 'method3' 177 | ); 178 | }).to.throw(AssertionError); 179 | 180 | expect(function () { 181 | concatenatedMethodDictionary = 182 | methods.MethodDictionary.concat( 183 | methodDictionary, 184 | function () { return 'method3'; }, 185 | null 186 | ); 187 | }).to.throw(AssertionError); 188 | }); 189 | 190 | it('expect to not work with duplicated', function () { 191 | expect(function () { 192 | concatenatedMethodDictionary = 193 | methods.MethodDictionary.concat( 194 | concatenatedMethodDictionary, 195 | function () { return 'method3'; }, 196 | 'method3' 197 | ); 198 | }).to.throw(AssertionError); 199 | }); 200 | }); 201 | }); 202 | }); 203 | -------------------------------------------------------------------------------- /tests/unit/back/models/user.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai'); 4 | var expect = chai.expect; 5 | var User = require('../../../../').models.User; 6 | var Promise = require('bluebird'); 7 | 8 | require('../../settings'); 9 | 10 | var user = new User({ 11 | username: 'test', 12 | email: 'email@test.com', 13 | password: '$2a$10$Bd4I9p6xSuphD3gSPk006.fMR5/Dr9LjJD7JhvJcm7hpDaS0wJruq' 14 | // the hash refers to 'test' 15 | }); 16 | 17 | describe('User', function () { 18 | 19 | it('has attributes', function () { 20 | expect(user).to.have.property('username'); 21 | expect(user).to.have.property('email'); 22 | expect(user).to.have.property('password'); 23 | }); 24 | 25 | it('#authenticate', function () { 26 | var promises = [ 27 | user.authenticate('wrong_password').then(function (res) { 28 | expect(res).to.equal(false); 29 | }), 30 | user.authenticate('test').then(function (res) { 31 | expect(res).to.equal(true); 32 | }) 33 | ]; 34 | return Promise.all(promises); 35 | }); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /tests/unit/back/settings.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var settings = require('../../../src/back/settings'); 9 | 10 | require('../settings'); 11 | 12 | describe('settings', function () { 13 | it( 14 | 'expect to export ADAPTERS in the ADAPTERS property and be an' + 15 | 'object', 16 | function () { 17 | expect(settings).to.have.property('ADAPTERS') 18 | .that.is.an('object'); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/unit/back/utils/classes.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var classes = require('../../../../src/back/utils').classes; 11 | 12 | require('../../settings'); 13 | 14 | describe('classes', function () { 15 | describe('~generalize', function () { 16 | context('interface tests', function () { 17 | it('expect to exist as an inner method', function () { 18 | expect(classes).to.respondTo('generalize'); 19 | }); 20 | 21 | it('expect to work with functions', function () { 22 | classes.generalize(function () {}, function () {}); 23 | }); 24 | 25 | it('expect to throw AssertionError with objects', function () { 26 | expect(function () { 27 | classes.generalize({}, {}); 28 | }).to.throw(AssertionError); 29 | 30 | expect(function () { 31 | classes.generalize(function () {}, {}); 32 | }).to.throw(AssertionError); 33 | }); 34 | 35 | it( 36 | 'expect to throw AssertionError with more than two parameters', 37 | function () { 38 | expect(function () { 39 | classes.generalize(function () {}, function () {}, function () {}); 40 | }).to.throw(AssertionError); 41 | } 42 | ); 43 | 44 | it( 45 | 'expect to throw AssertionError with more less than two parameters', 46 | function () { 47 | expect(function () { 48 | classes.generalize(function () {}); 49 | }).to.throw(AssertionError); 50 | } 51 | ); 52 | }); 53 | 54 | context('functional tests', function () { 55 | var GeneralClass; 56 | var SpecificClass; 57 | var g; 58 | var s; 59 | 60 | it('expect to run without error', function () { 61 | GeneralClass = function (ga1, ga2) { 62 | var g = this; 63 | 64 | g.ga1 = ga1; 65 | g.ga2 = ga2; 66 | }; 67 | 68 | GeneralClass.prototype.gm1 = function () { 69 | return 'gm1'; 70 | }; 71 | 72 | GeneralClass.prototype.gm2 = function () { 73 | return 'gm2'; 74 | }; 75 | 76 | GeneralClass.gsa1 = 'gsa1'; 77 | GeneralClass.gsa2 = 'gsa2'; 78 | 79 | GeneralClass.gsm1 = function () { 80 | return 'gsm1'; 81 | }; 82 | 83 | GeneralClass.gsm2 = function () { 84 | return 'gsm2'; 85 | }; 86 | 87 | SpecificClass = function (ga1, ga2, sa) { 88 | var s = this; 89 | 90 | GeneralClass.call(s, ga1, ga2); 91 | 92 | s.sa = sa; 93 | }; 94 | 95 | classes.generalize(GeneralClass, SpecificClass); 96 | 97 | SpecificClass.prototype.gm1 = function () { 98 | return 'sm1'; 99 | }; 100 | 101 | SpecificClass.prototype.sm = function () { 102 | return 'sm'; 103 | }; 104 | 105 | SpecificClass.gsa1 = 'ssa1'; 106 | SpecificClass.ssa = 'ssa'; 107 | 108 | SpecificClass.gsm1 = function () { 109 | return 'ssm1'; 110 | }; 111 | 112 | SpecificClass.ssm = function () { 113 | return 'ssm'; 114 | }; 115 | 116 | g = new GeneralClass('ga1', 'ga2'); 117 | s = new SpecificClass('sa1', 'sa2', 'sa'); 118 | }); 119 | 120 | it( 121 | 'expect instances to be of correct types', 122 | function () { 123 | expect(s).to.be.an.instanceof(SpecificClass); 124 | expect(s).to.be.an.instanceof(GeneralClass); 125 | expect(g).to.be.an.instanceof(GeneralClass); 126 | } 127 | ); 128 | 129 | it( 130 | 'expect attributes to be correctly inherited', 131 | function () { 132 | expect(g).to.have.property('ga1') 133 | .that.equals('ga1'); 134 | expect(g).to.have.property('ga2') 135 | .that.equals('ga2'); 136 | 137 | expect(s).to.have.property('ga1') 138 | .that.equals('sa1'); 139 | expect(s).to.have.property('ga2') 140 | .that.equals('sa2'); 141 | expect(s).to.have.property('sa') 142 | .that.equals('sa'); 143 | } 144 | ); 145 | 146 | it( 147 | 'expect instance methods to be correctly inherited', 148 | function () { 149 | expect(g.gm1()).to.equal('gm1'); 150 | expect(g.gm2()).to.equal('gm2'); 151 | 152 | expect(s.gm1()).to.equal('sm1'); 153 | expect(s.gm2()).to.equal('gm2'); 154 | expect(s.sm()).to.equal('sm'); 155 | } 156 | ); 157 | 158 | it( 159 | 'expect static attributes to be correctly inherited', 160 | function () { 161 | expect(GeneralClass).to.have.property('gsa1') 162 | .that.equals('gsa1'); 163 | expect(GeneralClass).to.have.property('gsa2') 164 | .that.equals('gsa2'); 165 | 166 | expect(SpecificClass).to.have.property('gsa1') 167 | .that.equals('ssa1'); 168 | expect(SpecificClass).to.have.property('gsa2') 169 | .that.equals('gsa2'); 170 | expect(SpecificClass).to.have.property('ssa') 171 | .that.equals('ssa'); 172 | } 173 | ); 174 | 175 | it( 176 | 'expect static methods to be correctly inherited', 177 | function () { 178 | expect(GeneralClass.gsm1()).to.equal('gsm1'); 179 | expect(GeneralClass.gsm2()).to.equal('gsm2'); 180 | 181 | expect(SpecificClass.gsm1()).to.equal('ssm1'); 182 | expect(SpecificClass.gsm2()).to.equal('gsm2'); 183 | expect(SpecificClass.ssm()).to.equal('ssm'); 184 | } 185 | ); 186 | }); 187 | }); 188 | 189 | describe('~isGeneral', function () { 190 | context('interface tests', function () { 191 | it('expect to exist as an inner method', function () { 192 | expect(classes).to.respondTo('isGeneral'); 193 | }); 194 | 195 | it('expect to work with functions', function () { 196 | classes.isGeneral(function () {}, function () {}); 197 | }); 198 | 199 | it('expect to throw AssertionError with objects', function () { 200 | expect(function () { 201 | classes.isGeneral({}, {}); 202 | }).to.throw(AssertionError); 203 | 204 | expect(function () { 205 | classes.isGeneral(function () {}, {}); 206 | }).to.throw(AssertionError); 207 | }); 208 | 209 | it( 210 | 'expect to throw AssertionError with more than two parameters', 211 | function () { 212 | expect(function () { 213 | classes.isGeneral(function () {}, function () {}, function () {}); 214 | }).to.throw(AssertionError); 215 | } 216 | ); 217 | 218 | it( 219 | 'expect to throw AssertionError with less than two parameters', 220 | function () { 221 | expect(function () { 222 | classes.isGeneral(function () {}); 223 | }).to.throw(AssertionError); 224 | } 225 | ); 226 | }); 227 | 228 | context('functional tests', function () { 229 | function GeneralClass() {} 230 | 231 | function SpecificClass() { 232 | GeneralClass.call(this); 233 | } 234 | 235 | classes.generalize(GeneralClass, SpecificClass); 236 | 237 | it( 238 | 'expect to return true when first class generalizes the second one', 239 | function () { 240 | expect(classes.isGeneral(GeneralClass, SpecificClass)).to.equal(true); 241 | } 242 | ); 243 | 244 | it( 245 | 'expect to return false when first class does not generalize the ' + 246 | 'second one', 247 | function () { 248 | expect(classes.isGeneral(SpecificClass, GeneralClass)) 249 | .to.equal(false); 250 | } 251 | ); 252 | 253 | it( 254 | 'expect to return true when first class is equal to the second one', 255 | function () { 256 | expect(classes.isGeneral(GeneralClass, GeneralClass)).to.equal(true); 257 | 258 | expect(classes.isGeneral(SpecificClass, SpecificClass)) 259 | .to.equal(true); 260 | } 261 | ); 262 | }); 263 | }); 264 | }); 265 | -------------------------------------------------------------------------------- /tests/unit/back/utils/index.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var utilsIndex = require('../../../..//src/back/utils'); 9 | var classes = require('../../../../src/back/utils/classes'); 10 | var objects = require('../../../../src/back/utils/objects'); 11 | 12 | require('../../settings'); 13 | 14 | describe('utilsIndex', function () { 15 | it('expect to export classes in the classes property', function () { 16 | expect(utilsIndex).to.have.property('classes') 17 | .that.equals(classes); 18 | }); 19 | 20 | it('expect to export objects in the objects property', function () { 21 | expect(utilsIndex).to.have.property('objects') 22 | .that.equals(objects); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /tests/unit/back/utils/objects.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 09/10/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var chai = require('chai'); 8 | var expect = chai.expect; 9 | var AssertionError = chai.AssertionError; 10 | var objects = require('../../../../src/back/utils').objects; 11 | 12 | require('../../settings'); 13 | 14 | describe('objects', function () { 15 | describe('~copy', function () { 16 | context('interface tests', function () { 17 | it('expect to exist as an inner method', function () { 18 | expect(objects).to.respondTo('copy'); 19 | }); 20 | 21 | it('expect to work with object', function () { 22 | objects.copy({}); 23 | 24 | function MyClass() {} 25 | 26 | var myObject = new MyClass(); 27 | 28 | objects.copy(myObject); 29 | }); 30 | 31 | it('expect to throw AssertionError with no objects', function () { 32 | expect(function () { 33 | objects.copy(true); 34 | }).to.throw(AssertionError); 35 | 36 | expect(function () { 37 | objects.copy(null); 38 | }).to.throw(AssertionError); 39 | 40 | expect(function () { 41 | objects.copy(undefined); 42 | }).to.throw(AssertionError); 43 | 44 | expect(function () { 45 | objects.copy(function () {}); 46 | }).to.throw(AssertionError); 47 | }); 48 | 49 | it( 50 | 'expect to throw AssertionError with no parameters', 51 | function () { 52 | expect(function () { 53 | objects.copy(); 54 | }).to.throw(AssertionError); 55 | } 56 | ); 57 | 58 | it( 59 | 'expect to throw AssertionError with more than 1 parameter', 60 | function () { 61 | expect(function () { 62 | objects.copy({}, null); 63 | }).to.throw(AssertionError); 64 | } 65 | ); 66 | }); 67 | 68 | context('functional tests', function () { 69 | var o = { 70 | o1: 'o1' 71 | }; 72 | 73 | var copy = objects.copy(o); 74 | 75 | expect(copy).to.not.equal(o); 76 | 77 | expect(copy).to.deep.equal(o); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tests/unit/index.test.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 21/09/15. 3 | // 4 | 5 | 'use strict'; 6 | 7 | var expect = require('chai').expect; 8 | var index = require('../../'); 9 | var backIndex = require('../../src/back'); 10 | 11 | require('./settings'); 12 | 13 | describe('index', function () { 14 | it('expect to export back index', function () { 15 | expect(index).to.equal(backIndex); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/unit/settings.js: -------------------------------------------------------------------------------- 1 | // 2 | // Created by davimacedo on 22/10/15. 3 | // 4 | 5 | var settings = require('../../').settings; 6 | var MockAdapter = require('./back/adapters/MockAdapter'); 7 | 8 | settings.ADAPTERS.default = new MockAdapter(); 9 | -------------------------------------------------------------------------------- /tests/visual/editor-multi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Code Editor + RequireJS 6 | 7 | 8 | 9 |

Code Editor + RequireJS Visual Test

10 |

Open Developer tools > Console

11 | 12 | 13 | 14 |
15 |
'use strict';
 16 | 
 17 | /* Animal.js */
 18 | 
 19 | var Entity = require('back4app-entity').models.Entity;
 20 | 
 21 | module.exports = Entity.specify({
 22 |   name: 'Animal',
 23 |   attributes: {
 24 |     legs: {
 25 |       type: 'Number',
 26 |       default: 4
 27 |     },
 28 |     createdAt: {
 29 |       type: 'Datetime',
 30 |       default: Date.now
 31 |     }
 32 |   },
 33 |   methods: {
 34 |     getInfo: function () {
 35 |       return "I'm an Animal with {{legs}} legs, created at {{createdAt}}"
 36 |         .replace('{{legs}}', this.legs)
 37 |         .replace('{{createdAt}}', new Date(this.createdAt));
 38 |     }
 39 |   }
 40 | });
 41 | 
42 |
43 | 44 |

45 | 46 |

47 | 48 | 49 | 50 |
51 |
'use strict';
 52 | 
 53 | /* Dog.js */
 54 | 
 55 | module.exports = require('./Animal').specify({
 56 |   name: 'Dog',
 57 |   attributes: {
 58 |     name: {
 59 |       type: 'String',
 60 |       default: 'Toby'
 61 |     }
 62 |   },
 63 |   methods: {
 64 |     getInfo: function () {
 65 |       return "I'm a Dog named '{{name}}', with {{legs}} legs, created at {{createdAt}}"
 66 |         .replace('{{name}}', this.name)
 67 |         .replace('{{legs}}', this.legs)
 68 |         .replace('{{createdAt}}', new Date(this.createdAt));
 69 |     }
 70 |   }
 71 | });
 72 | 
73 |
74 | 75 |

76 | 77 |

78 | 79 | 80 | 81 |
82 |
'use strict';
 83 | 
 84 | /* Boy.js */
 85 | 
 86 | var Entity = require('back4app-entity').models.Entity;
 87 | 
 88 | module.exports = Entity.specify({
 89 |   name: 'Boy',
 90 |   attributes: {
 91 |     name: {
 92 |       type: 'String',
 93 |       default: 'John'
 94 |     },
 95 |     dog: {
 96 |       // type: 'Dog'
 97 |       default: Entity.new('Dog')
 98 |     }
 99 |   },
100 |   methods: {
101 |     getInfo: function () {
102 |       return "I'm a Boy named '{{name}}', who has a dog named '{{dogName}}'"
103 |         .replace('{{name}}', this.name)
104 |         .replace('{{dogName}}', this.dog.name);
105 |     }
106 |   }
107 | });
108 | 
109 |
110 | 111 |

112 | 113 |

114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /tests/visual/editor-multi/main.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var editor1; 5 | var editor2; 6 | var editor3; 7 | var back4appEntityCode; 8 | 9 | setupEditors(); 10 | setupButtons(); 11 | 12 | function setupEditors() { 13 | // editor1: Animal 14 | editor1 = ace.edit('editor1'); 15 | editor1.setTheme('ace/theme/monokai'); 16 | editor1.getSession().setMode('ace/mode/javascript'); 17 | 18 | // editor2: Dog 19 | editor2 = ace.edit('editor2'); 20 | editor2.setTheme('ace/theme/monokai'); 21 | editor2.getSession().setMode('ace/mode/javascript'); 22 | 23 | // editor3: Boy 24 | editor3 = ace.edit('editor3'); 25 | editor3.setTheme('ace/theme/monokai'); 26 | editor3.getSession().setMode('ace/mode/javascript'); 27 | } 28 | 29 | function setupButtons() { 30 | // button1: Animal 31 | var button1 = document.getElementById('run-code-btn1'); 32 | button1.onclick = function () { 33 | var script = {name: 'Animal', code: editor1.getSession().getValue()}; 34 | var otherScripts = [ 35 | {name: 'Dog', code: editor2.getSession().getValue()}, 36 | {name: 'Boy', code: editor3.getSession().getValue()} 37 | ]; 38 | shuffle(otherScripts); // randomize dependencies order, for testing 39 | execute(script, otherScripts); 40 | }; 41 | 42 | // button2: Dog 43 | var button2 = document.getElementById('run-code-btn2'); 44 | button2.onclick = function () { 45 | var script = {name: 'Dog', code: editor2.getSession().getValue()}; 46 | var otherScripts = [ 47 | {name: 'Animal', code: editor1.getSession().getValue()}, 48 | {name: 'Boy', code: editor3.getSession().getValue()} 49 | ]; 50 | shuffle(otherScripts); // randomize dependencies order, for testing 51 | execute(script, otherScripts); 52 | }; 53 | 54 | // button3: Boy 55 | var button3 = document.getElementById('run-code-btn3'); 56 | button3.onclick = function () { 57 | var script = {name: 'Boy', code: editor3.getSession().getValue()}; 58 | var otherScripts = [ 59 | {name: 'Animal', code: editor1.getSession().getValue()}, 60 | {name: 'Dog', code: editor2.getSession().getValue()} 61 | ]; 62 | shuffle(otherScripts); // randomize dependencies order, for testing 63 | execute(script, otherScripts); 64 | }; 65 | } 66 | 67 | function shuffle(array) { 68 | var counter = array.length, temp, index; 69 | 70 | // while there are elements in the array 71 | while (counter > 0) { 72 | // pick a random index 73 | index = Math.floor(Math.random() * counter); 74 | 75 | // decrease counter by 1 76 | counter--; 77 | 78 | // and swap the last element with it 79 | temp = array[counter]; 80 | array[counter] = array[index]; 81 | array[index] = temp; 82 | } 83 | 84 | return array; 85 | } 86 | 87 | function execute(script, otherScripts) { 88 | makeNewContext(); 89 | definePlugin(script, otherScripts); 90 | redefineBack4appEntity(function (entity) { 91 | // set default adapter 92 | var Adapter = entity.adapters.Adapter; 93 | var MockAdapter = makeMockAdapter(Adapter); 94 | 95 | entity.settings.ADAPTERS = { 96 | default: new MockAdapter() 97 | }; 98 | 99 | // require user entity 100 | require(['$commonjs!' + script.name], function (CustomEntity) { 101 | // test entity instance 102 | var obj = new CustomEntity(); 103 | console.log(obj.getInfo()); 104 | }); 105 | }); 106 | } 107 | 108 | function makeNewContext() { 109 | var contextName = 'test'; 110 | 111 | // delete old context 112 | delete requirejs.s.contexts[contextName]; 113 | 114 | // create new context 115 | var oldConfig = requirejs.s.contexts._.config; 116 | var config = {}; 117 | for (var key in oldConfig) { 118 | if (oldConfig.hasOwnProperty(key)) { 119 | config[key] = oldConfig[key]; 120 | } 121 | } 122 | config.context = contextName; 123 | 124 | window.require = requirejs.config(config); 125 | } 126 | 127 | function definePlugin(script, otherScripts) { 128 | define('$commonjs', [], { 129 | load: function (name, req, onload) { 130 | // wrap CommonJS code in AMD-friendly format 131 | var amdCode = 132 | 'define(\'' + name + '\', function(require, exports, module) {\n' + 133 | script.code + '\n' + 134 | 'return module.exports;\n' + 135 | '});\n'; 136 | 137 | for (var i = 0; i < otherScripts.length; i++) { 138 | var oName = otherScripts[i].name; 139 | var oCode = otherScripts[i].code; 140 | 141 | // wrap dependencies in AMD-friendly format 142 | amdCode += 143 | 'define(\'' + oName + '\', function(require, exports, module) {\n' + 144 | oCode + '\n' + 145 | 'return module.exports;\n' + 146 | '});\n'; 147 | 148 | // require dependencies with module, 149 | // to be accessible at runtime (e.g. `Entity.new('...')`) 150 | amdCode += 'require([\'' + oName + '\'], function () {});'; 151 | } 152 | 153 | onload.fromText(amdCode); 154 | } 155 | }); 156 | } 157 | 158 | function redefineBack4appEntity(cb) { 159 | // define plugin to load `back4app-entity` from string cache 160 | define('$cache', [], { 161 | load: function (name, req, onload) { 162 | onload.fromText(back4appEntityCode); 163 | } 164 | }); 165 | 166 | // check if code is already cached 167 | if (typeof back4appEntityCode === 'undefined') { 168 | require(['text!back4app-entity.js'], function (code) { 169 | back4appEntityCode = code; 170 | requireFromCache(); 171 | }); 172 | } else { 173 | requireFromCache(); 174 | } 175 | 176 | function requireFromCache() { 177 | require(['$cache!back4app-entity'], function (entity) { 178 | cb(entity); 179 | }); 180 | } 181 | } 182 | 183 | function makeMockAdapter(Adapter) { 184 | // create class 185 | var MockAdapter = function () {}; 186 | 187 | // inherit from base Adapter 188 | MockAdapter.prototype = Object.create(Adapter.prototype); 189 | MockAdapter.prototype.constructor = MockAdapter; 190 | 191 | // implement stub methods 192 | MockAdapter.prototype.loadEntity = function () {}; 193 | MockAdapter.prototype.loadEntityAttribute = function () {}; 194 | MockAdapter.prototype.insertObject = function () {}; 195 | MockAdapter.prototype.updateObject = function () {}; 196 | 197 | return MockAdapter; 198 | } 199 | })(); 200 | -------------------------------------------------------------------------------- /tests/visual/editor-multi/style.css: -------------------------------------------------------------------------------- 1 | .editor-container { 2 | position: relative; 3 | width: 600px; 4 | height: 500px; 5 | } 6 | 7 | #editor1 { 8 | position: absolute; 9 | top: 0; 10 | right: 0; 11 | bottom: 0; 12 | left: 0; 13 | } 14 | 15 | #editor2 { 16 | position: absolute; 17 | top: 0; 18 | right: 0; 19 | bottom: 0; 20 | left: 0; 21 | } 22 | 23 | #editor3 { 24 | position: absolute; 25 | top: 0; 26 | right: 0; 27 | bottom: 0; 28 | left: 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/visual/editor-single/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Code Editor + RequireJS 6 | 7 | 8 | 9 |

Code Editor + RequireJS Visual Test

10 |

Open Developer tools > Console

11 | 12 |
13 |
'use strict';
14 | 
15 | /* Animal.js */
16 | 
17 | var Entity = require('back4app-entity').models.Entity;
18 | 
19 | module.exports = Entity.specify({
20 |   name: 'Animal',
21 |   attributes: {
22 |     name: {
23 |       type: 'String'
24 |     },
25 |     createdAt: {
26 |       type: 'Datetime',
27 |       default: Date.now
28 |     }
29 |   },
30 |   methods: {
31 |     getInfo: function () {
32 |       return 'I am ' + this.name + ', created at ' + new Date(this.createdAt);
33 |     }
34 |   }
35 | });
36 | 
37 |
38 | 39 |

40 | 41 |

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/visual/editor-single/main.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var editor; 5 | var back4appEntityCode; 6 | 7 | setupEditor(); 8 | setupButton(); 9 | 10 | function setupEditor() { 11 | editor = ace.edit('editor'); 12 | editor.setTheme('ace/theme/monokai'); 13 | editor.getSession().setMode('ace/mode/javascript'); 14 | } 15 | 16 | function setupButton() { 17 | var button = document.getElementById('run-code-btn'); 18 | button.onclick = function () { 19 | var code = editor.getSession().getValue(); 20 | execute(code); 21 | }; 22 | } 23 | 24 | function execute(code) { 25 | makeNewContext(); 26 | definePlugin(code); 27 | redefineBack4appEntity(function (entity) { 28 | // set default adapter 29 | var Adapter = entity.adapters.Adapter; 30 | var MockAdapter = makeMockAdapter(Adapter); 31 | 32 | entity.settings.ADAPTERS = { 33 | default: new MockAdapter() 34 | }; 35 | 36 | // require user entity 37 | require(['$commonjs!Animal'], function (Animal) { 38 | // test entity instance 39 | var animal = new Animal(); 40 | animal.name = 'Bob'; 41 | console.log(animal.getInfo()); 42 | }); 43 | }); 44 | } 45 | 46 | function makeNewContext() { 47 | var contextName = 'test'; 48 | 49 | // delete old context 50 | delete requirejs.s.contexts[contextName]; 51 | 52 | // create new context 53 | var oldConfig = requirejs.s.contexts._.config; 54 | var config = {}; 55 | for (var key in oldConfig) { 56 | if (oldConfig.hasOwnProperty(key)) { 57 | config[key] = oldConfig[key]; 58 | } 59 | } 60 | config.context = contextName; 61 | 62 | window.require = requirejs.config(config); 63 | } 64 | 65 | function definePlugin(code) { 66 | define('$commonjs', [], { 67 | load: function (name, req, onload) { 68 | // wrap CommonJS code in AMD-friendly format 69 | var amdCode = 70 | 'define(\'' + name + '\', function(require, exports, module) {\n' + 71 | code + '\n' + 72 | 'return module.exports;\n' + 73 | '});\n'; 74 | onload.fromText(amdCode); 75 | } 76 | }); 77 | } 78 | 79 | function redefineBack4appEntity(cb) { 80 | // define plugin to load `back4app-entity` from string cache 81 | define('$cache', [], { 82 | load: function (name, req, onload) { 83 | onload.fromText(back4appEntityCode); 84 | } 85 | }); 86 | 87 | // check if code is already cached 88 | if (typeof back4appEntityCode === 'undefined') { 89 | require(['text!back4app-entity.js'], function (code) { 90 | back4appEntityCode = code; 91 | requireFromCache(); 92 | }); 93 | } else { 94 | requireFromCache(); 95 | } 96 | 97 | function requireFromCache() { 98 | require(['$cache!back4app-entity'], function (entity) { 99 | cb(entity); 100 | }); 101 | } 102 | } 103 | 104 | function makeMockAdapter(Adapter) { 105 | // create class 106 | var MockAdapter = function () {}; 107 | 108 | // inherit from base Adapter 109 | MockAdapter.prototype = Object.create(Adapter.prototype); 110 | MockAdapter.prototype.constructor = MockAdapter; 111 | 112 | // implement stub methods 113 | MockAdapter.prototype.loadEntity = function () {}; 114 | MockAdapter.prototype.loadEntityAttribute = function () {}; 115 | MockAdapter.prototype.insertObject = function () {}; 116 | MockAdapter.prototype.updateObject = function () {}; 117 | 118 | return MockAdapter; 119 | } 120 | })(); 121 | -------------------------------------------------------------------------------- /tests/visual/editor-single/style.css: -------------------------------------------------------------------------------- 1 | #editor-container { 2 | position: relative; 3 | width: 600px; 4 | height: 500px; 5 | } 6 | 7 | #editor { 8 | position: absolute; 9 | top: 0; 10 | right: 0; 11 | bottom: 0; 12 | left: 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/visual/requirejs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RequireJS 6 | 7 | 8 | 9 | 10 | 11 |

RequireJS Visual Test

12 |

Open Developer tools > Console

13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/visual/requirejs/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function makeMockAdapter(Adapter) { 4 | // create class 5 | var MockAdapter = function () {}; 6 | 7 | // inherit from base Adapter 8 | MockAdapter.prototype = Object.create(Adapter.prototype); 9 | MockAdapter.prototype.constructor = MockAdapter; 10 | 11 | // implement stub methods 12 | MockAdapter.prototype.loadEntity = function () {}; 13 | MockAdapter.prototype.loadEntityAttribute = function () {}; 14 | MockAdapter.prototype.insertObject = function () {}; 15 | MockAdapter.prototype.updateObject = function () {}; 16 | 17 | return MockAdapter; 18 | } 19 | 20 | require(['back4app-entity'], function (entity) { 21 | var Adapter = entity.adapters.Adapter; 22 | var Entity = entity.models.Entity; 23 | 24 | // set default adapter 25 | var MockAdapter = makeMockAdapter(Adapter); 26 | 27 | entity.settings.ADAPTERS = { 28 | default: new MockAdapter() 29 | }; 30 | 31 | // create new entity class 32 | var Person = Entity.specify({ 33 | name: 'Person', 34 | attributes: { 35 | name: { 36 | type: 'String' 37 | }, 38 | createdAt: { 39 | type: 'Datetime', 40 | default: Date.now 41 | }, 42 | friends: { 43 | type: 'String', 44 | multiplicity: '*' 45 | } 46 | }, 47 | methods: { 48 | getInfo: function () { 49 | return 'I am ' + this.name + ', created at ' + new Date(this.createdAt); 50 | } 51 | } 52 | }); 53 | 54 | // test entity instance 55 | var person = new Person(); 56 | person.name = 'John'; 57 | console.log(person.getInfo()); 58 | }); 59 | --------------------------------------------------------------------------------