├── .gitignore ├── .npmignore ├── README.md ├── context.json ├── coverage └── blanket.js ├── gruntfile.js ├── history.md ├── index.js ├── lib ├── aspect │ ├── cacheAspect.js │ └── transactionAspect.js ├── bearcat-dao.js ├── connection │ ├── cache │ │ ├── redisClusterConnectionManager.js │ │ ├── redisConnection.js │ │ └── redisConnectionManager.js │ └── sql │ │ ├── ddbConnectionManager.js │ │ └── mysqlConnectionManager.js ├── core │ ├── domainDaoSupport.js │ └── sqlDaoSupport.js ├── definition │ ├── deleteDefinition.js │ ├── expression │ │ ├── columnDefinition.js │ │ ├── conditionDefinition.js │ │ ├── groupByDefinition.js │ │ └── orderByDefinition.js │ ├── insertDefinition.js │ ├── selectDefinition.js │ ├── sqlDefinition.js │ ├── tableDefinition.js │ └── updateDefinition.js ├── loader │ └── sqlLoader.js ├── parser │ └── sqlParser.js ├── plan │ ├── performers │ │ ├── directPlanPerformer.js │ │ ├── queryPlanPerformer.js │ │ └── updatePlanPerformer.js │ ├── planHelper.js │ ├── planMaker.js │ ├── planManager.js │ ├── plans │ │ ├── aggregatePlan.js │ │ ├── directPlan.js │ │ ├── groupByPlan.js │ │ ├── havingPlan.js │ │ ├── limitPlan.js │ │ ├── orderByPlan.js │ │ ├── queryPlan.js │ │ ├── selectPlan.js │ │ ├── simpleSelectPlan.js │ │ └── updatePlan.js │ └── queryPlanFactory.js ├── support │ ├── fieldConfig.js │ └── tableConfig.js ├── template │ ├── cache │ │ ├── command │ │ │ └── multiCommand.js │ │ ├── redisClusterTemplate.js │ │ └── redisTemplate.js │ └── sql │ │ ├── ddbTemplate.js │ │ └── mysqlTemplate.js ├── transaction │ ├── cacheTransactionManager.js │ ├── dbTransactionManager.js │ └── transactionStatus.js └── util │ ├── beanBuilderUtil.js │ ├── constant.js │ ├── countDownLatch.js │ ├── domainFactory.js │ ├── fieldUtil.js │ ├── fileUtil.js │ ├── shardingUtil.js │ ├── sqlBuilderUtil.js │ ├── sqlUtil.js │ └── utils.js ├── package.json ├── test-context.json ├── test-ddb-context.json └── test ├── aspect └── transactionAspect.js ├── bearcat-dao.js ├── connection ├── cache │ └── redisConnectionManager.js └── sql │ └── mysqlConnectionManager.js ├── core ├── debug.js └── domainDaoSupport.js ├── debug.js ├── loader ├── debug.js └── sqlLoader.js ├── mock ├── domain │ ├── joinPerson.js │ ├── person.js │ ├── person1.js │ └── person2.js ├── mock-redis.js ├── model │ ├── authorModel.js │ ├── blogModel.js │ ├── blogResultModel.js │ ├── commentModel.js │ ├── ddb │ │ └── blogModel.js │ ├── person.js │ ├── person1.js │ └── person2.js ├── schema.sql └── sql │ ├── query1.sql │ ├── query2.sql │ ├── query3.sql │ └── queryBlog.sql ├── template ├── cache │ ├── redisClusterTemplate.js │ └── redisTemplate.js └── sql │ └── DDBTemplate.js ├── transaction ├── dao │ ├── person1Dao.js │ └── personDao.js └── service │ └── personService.js └── util ├── countDownLatch.js ├── sqlBuilderUtil.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | */node-log.log 3 | logs/*.log 4 | *.log 5 | !.gitignore 6 | node_modules/* 7 | .project 8 | .settings/ 9 | **/*.svn 10 | *.svn 11 | *.swp 12 | *.sublime-project 13 | *.sublime-workspace 14 | lib/doc/ 15 | lib-cov/ 16 | coverage.html 17 | .DS_Store 18 | .idea/* 19 | test_/* 20 | design/* 21 | knex 22 | bookshelf -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | docs/ 3 | examples/ 4 | support/ 5 | test/ 6 | testing.js 7 | .DS_Store 8 | coverage.html 9 | lib-cov 10 | design/ 11 | express/ 12 | node_modules/ 13 | test_/ 14 | bookshelf/ 15 | design/ 16 | knex/ 17 | sequelize/ 18 | config/ 19 | test_ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Bearcat-dao -- a SQL mapping dao framework 2 | 3 | ## Overview 4 | [bearcat-dao](https://github.com/bearcatjs/bearcat-dao) is a DAO (domain access objects) framework for [node.js](http://nodejs.org/). It implements SQL mapping as its main concept compared to O/R mapping, therefore SQL is still the main concern using with bearcat-dao, and bearcat-dao will map the datebase resultset into [bearcat model](http://bearcatjs.org/guide/model.html) object. 5 | 6 | ## SQL mapping vs O/R mapping 7 | Structured Query Language (SQL) has been around for a long time, relational database and SQL have been claimed to have stood the test of time. Moreover, we have experiences whereby the database and even the SQL itself have outlived the application source code, and even mulitiple versions of the source code. 8 | SQL mapping is on the idea that there is value in relational database and SQL, developers write SQL and maps data resultsets into objects. Therefore, it is easy for enterprise application to optimize, reuse SQL, maintain. 9 | In another way, O/R mapping enables developers to write mapping object to database table, ORM framework then generates the specific SQL to execute on the database. So, as we can see, developers have to take great knowledge of the ORM framework in order to use the database well, especially when optimization is needed. 10 | 11 | ## Model 12 | model definition is using [bearcat model](http://bearcatjs.org/guide/model.html) 13 | therefore it is easy to be mapped into table and setup constraint, relation 14 | 15 | for example, if we have a test table with single primary id 16 | 17 | ``` 18 | create table test( 19 | id bigint(20) NOT NULL COMMENT 'id', 20 | 21 | PRIMARY KEY (id) 22 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 23 | ``` 24 | 25 | the we can define the following model 26 | 27 | ``` 28 | var TestModel = function() { 29 | this.$mid = "testModel"; 30 | this.$table = "test"; 31 | this.id = "$primary;type:Number"; 32 | } 33 | 34 | module.exports = TestModel; 35 | ``` 36 | 37 | in the ***TestModel***, we use ***$table*** attribute to setup the mapping table name, in ***id*** attribute we use ***primary*** to mark it as a primary key, then we add with a type constraint 38 | 39 | ## Relation 40 | Tables in relational database can have relations, there are one-to-one relation, one-to-many relation, many-to-many relation 41 | 42 | ### One-to-one relation 43 | One-to-one relation means in two models, one model has the reference of the other model 44 | 45 | for example, if we have a ***test1*** table with primary id and reference id of the ***test2*** table 46 | 47 | ``` 48 | create table test1( 49 | id bigint(20) NOT NULL COMMENT 'id', 50 | rid bigint(20) NOT NULL COMMENT 'reference to test2 id', 51 | 52 | PRIMARY KEY (id) 53 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 54 | ``` 55 | 56 | ``` 57 | create table test2( 58 | id bigint(20) NOT NULL COMMENT 'id', 59 | 60 | PRIMARY KEY (id) 61 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 62 | ``` 63 | 64 | then we can define the following two models 65 | 66 | ``` 67 | var Test1Model = function() { 68 | this.$mid = "test1Model"; 69 | this.$table = "test1"; 70 | this.id = "$primary;type:Number"; 71 | this.test2 = "$type:Object;ref:test2Model" 72 | } 73 | 74 | module.exports = Test1Model; 75 | ``` 76 | 77 | ``` 78 | var Test2Model = function() { 79 | this.$mid = "test2Model"; 80 | this.$table = "test2"; 81 | this.id = "$primary;type:Number"; 82 | } 83 | 84 | module.exports = Test2Model; 85 | ``` 86 | 87 | as we can see, in ***Test1Model.test2*** attribute we use ***ref:test2Model*** to set the reference to ***test2Model*** 88 | 89 | ### One-to-many relation 90 | One-to-many relation means one model refer to the array of other model. In the real world, for example, we can have a blog, and a blog have many commnets, so blog and comment are one-to-many relation. 91 | 92 | ``` 93 | var Test1Model = function() { 94 | this.$mid = "test1Model"; 95 | this.$table = "test1"; 96 | this.id = "$primary;type:Number"; 97 | this.test2 = "$type:Array;ref:test2Model" 98 | } 99 | 100 | module.exports = Test1Model; 101 | ``` 102 | 103 | therefore, in the above example, we simply modify the ***test2*** attribute type to ***Array***, it becomes a one-to-many relation 104 | 105 | ### Many-to-many relation 106 | many-to-many relation can be spilted into two one-many relation through middle table 107 | 108 | ## SQL template 109 | When writing complex sql, it is not quite well writing as a String, the better way is using SQL template. 110 | 111 | write SQL tempalte is easy 112 | 113 | for example, we can define SQL template with id ***testResultSql*** 114 | 115 | ``` 116 | sql testResultSql 117 | select * from test 118 | end 119 | ``` 120 | 121 | then we can use this sql in dao, like this 122 | 123 | ``` 124 | domainDaoSupport.getList("$testResultSql", null, "testModel", function(err, results) { 125 | // results is testModel type array 126 | }); 127 | ``` 128 | 129 | in domainDaoSupport.getList api, the first argument can be SQL tempalte id, the second argument is the SQL arguments, the third argument is the SQL result mapping model id, then in the callback function, we can get the results which are already mapped with testModel array 130 | 131 | Moreover, SQL template can include other SQL template 132 | 133 | for example 134 | ``` 135 | sql testResultSql 136 | select * from ${testResultTable} 137 | end 138 | 139 | sql testResultTable 140 | test 141 | end 142 | ``` 143 | 144 | then testResultSql template is equal to the above 145 | 146 | ## ResultSet mapping 147 | ResultSet is an array of field/value objects, therefore the process of mapping resultSet is like filling objects with specific key/value pairs, to make the key match with the resultSet, we can use ***prefix*** in [model magic attribute value](http://bearcatjs.org/guide/model.html#model_magic_attribute_value) or use ***prefix*** in [model attribute](http://bearcatjs.org/guide/magic-javaScript-objects-in-details.html) to mark all attributes in this model will be prefixed 148 | 149 | for example, if you query for a resultSet like this 150 | 151 | ``` 152 | [{ 153 | "id": 1, 154 | "title": "blog_title", 155 | "content": "blog_content", 156 | "create_at": 1234567, 157 | "update_at": 1234567 158 | }] 159 | ``` 160 | 161 | then mapping model can be like this 162 | 163 | ``` 164 | var BlogModel = function() { 165 | this.$mid = "blogModel"; 166 | this.$table = "ba_blog"; 167 | this.id = "$primary;type:Number"; 168 | this.aid = "$type:Number"; 169 | this.title = "$type:String"; 170 | this.content = "$type:String"; 171 | this.create_at = "$type:Number"; 172 | this.update_at = "$type:Number"; 173 | } 174 | 175 | module.exports = BlogModel; 176 | ``` 177 | 178 | if your resultSet is prefixed with ***blog_*** like this 179 | ``` 180 | [{ 181 | "blog_id": 1, 182 | "blog_title": "blog_title", 183 | "blog_content": "blog_content", 184 | "blog_create_at": 1234567, 185 | "blog_update_at": 1234567 186 | }] 187 | ``` 188 | 189 | then mapping model will be like this 190 | 191 | ``` 192 | var BlogModel = function() { 193 | this.$mid = "blogModel"; 194 | this.$table = "ba_blog"; 195 | this.$prefix = "blog_"; 196 | this.id = "$primary;type:Number"; 197 | this.aid = "$type:Number"; 198 | this.title = "$type:String"; 199 | this.content = "$type:String"; 200 | this.create_at = "$type:Number"; 201 | this.update_at = "$type:Number"; 202 | } 203 | 204 | module.exports = BlogModel; 205 | ``` 206 | 207 | just add ***this.$prefix*** model attribute 208 | 209 | ## DAO 210 | DAO is short for domain access object, we can use DAO objects to manage database 211 | 212 | bearcat-dao provides ***domainDaoSupport*** wrapping basic sql and cache operations 213 | add it with properties dependency injection, and init it by invoking ***initConfig*** method 214 | then you can use domainDaoSupport convenient methods to wrap your own daos 215 | 216 | simpleDao.js 217 | ``` 218 | var SimpleDao = function() { 219 | this.$id = "simpleDao"; 220 | this.$init = "init"; 221 | this.$domainDaoSupport = null; 222 | } 223 | 224 | SimpleDao.prototype.init = function() { 225 | // init with SimpleModel id to set up model mapping 226 | this.domainDaoSupport.initConfig("simpleModel"); 227 | } 228 | 229 | // query list all 230 | // callback return mapped SimpleModel array results 231 | SimpleDao.prototype.getList = function(cb) { 232 | var sql = ' 1 = 1'; 233 | this.$domainDaoSupport.getListByWhere(sql, null, null, cb); 234 | } 235 | 236 | module.exports = SimpleDao; 237 | ``` 238 | 239 | api reference for [domainDaoSupport](http://bearcatjs.github.io/bearcat-dao/domainDaoSupport.js.html) 240 | 241 | ## Configuration 242 | add bearcat-dao to your project 243 | 244 | ``` 245 | npm install bearcat-dao --save 246 | ``` 247 | 248 | modify context.json used by your project 249 | [placeholds](http://bearcatjs.org/guide/consistent-configuration.html) can be nicely used to switch between contexts 250 | 251 | ``` 252 | "dependencies": { 253 | "bearcat-dao": "*" 254 | }, 255 | "beans": [{ 256 | "id": "mysqlConnectionManager", 257 | "func": "node_modules.bearcat-dao.lib.connection.sql.mysqlConnectionManager", 258 | "props": [{ 259 | "name": "port", 260 | "value": "${mysql.port}" 261 | }, { 262 | "name": "host", 263 | "value": "${mysql.host}" 264 | }, { 265 | "name": "user", 266 | "value": "${mysql.user}" 267 | }, { 268 | "name": "password", 269 | "value": "${mysql.password}" 270 | }, { 271 | "name": "database", 272 | "value": "${mysql.database}" 273 | }] 274 | }, { 275 | "id": "redisConnectionManager", 276 | "func": "node_modules.bearcat-dao.lib.connection.cache.redisConnectionManager", 277 | "props": [{ 278 | "name": "port", 279 | "value": "${redis.port}" 280 | }, { 281 | "name": "host", 282 | "value": "${redis.host}" 283 | }] 284 | }] 285 | ``` 286 | 287 | if you do not use redis, you can remove ***redisConnectionManager*** definition 288 | 289 | ## Transaction 290 | 291 | bearcat-dao provides transaction support based on [bearcat AOP](http://bearcatjs.org/guide/aop.html). The aspect is [transactionAspect](https://github.com/bearcatjs/bearcat-dao/blob/master/lib/aspect/transactionAspect.js) which provides around advice, when target transaction method calls cb function with ***err***, rollback will be emited, otherwise it will commit the operations. 292 | 293 | The pointcut defined is: 294 | ``` 295 | "pointcut": "around:.*?Transaction$" 296 | ``` 297 | 298 | Therefore, any POJO method match this pointcut can a transcation method 299 | Since transaction must be within the same connection, in Bearcat-dao it is ***transactionStatus***, daos under the transaction method must hold the same transactionStatus 300 | ``` 301 | SimpleService.prototype.testMethodTransaction = function(cb, txStatus) { 302 | var self = this; 303 | 304 | this.simpleDao1.transaction(txStatus).addPerson(['aaa'], function(err, results) { 305 | if (err) { 306 | return cb(err); // if err occur, rollback will be emited 307 | } 308 | 309 | self.simpleDao2.transaction(txStatus).getList([1, 2], function(err, results) { 310 | if (err) { 311 | return cb(err); // if err occur, rollback will be emited 312 | } 313 | 314 | cb(null, results); // commit the operations 315 | }); 316 | }); 317 | } 318 | ``` 319 | 320 | ## Enable Debug Mode 321 | run with BEARCAT_DEBUG flag true 322 | ``` 323 | BEARCAT_DEBUG=true node xxx.js 324 | ``` 325 | 326 | ## Examples 327 | - [bearcat-todo](https://github.com/bearcatnode/todo) 328 | - [bearcat-dao example](https://github.com/bearcatjs/bearcat-examples/tree/master/bearcat-dao-example) 329 | 330 | ## License 331 | 332 | (The MIT License) 333 | 334 | Copyright (c) fantasyni and other contributors 335 | 336 | Permission is hereby granted, free of charge, to any person obtaining 337 | a copy of this software and associated documentation files (the 338 | 'Software'), to deal in the Software without restriction, including 339 | without limitation the rights to use, copy, modify, merge, publish, 340 | distribute, sublicense, and/or sell copies of the Software, and to 341 | permit persons to whom the Software is furnished to do so, subject to 342 | the following conditions: 343 | 344 | The above copyright notice and this permission notice shall be 345 | included in all copies or substantial portions of the Software. 346 | 347 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 348 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 349 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 350 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 351 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 352 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 353 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /context.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bearcat-dao", 3 | "beans": [{ 4 | "id": "domainDaoSupport", 5 | "func": "lib.core.domainDaoSupport", 6 | "scope": "prototype", 7 | "props": [{ 8 | "name": "sqlTemplate", 9 | "ref": "sqlTemplate" 10 | }, { 11 | "name": "cacheTemplate", 12 | "ref": "cacheTemplate" 13 | }], 14 | "proxy": false 15 | }, { 16 | "id": "sqlTemplate", 17 | "func": "lib.template.sql.mysqlTemplate", 18 | "props": [{ 19 | "name": "connectionManager", 20 | "ref": "mysqlConnectionManager" 21 | }, { 22 | "name": "transactionManager", 23 | "ref": "dbTransactionManager" 24 | }] 25 | }, { 26 | "id": "cacheTemplate", 27 | "func": "lib.template.cache.redisTemplate", 28 | "props": [{ 29 | "name": "connectionManager", 30 | "ref": "redisConnectionManager" 31 | }] 32 | }, { 33 | "id": "mysqlConnectionManager", 34 | "func": "lib.connection.sql.mysqlConnectionManager", 35 | "proxy": false 36 | }, { 37 | "id": "redisConnectionManager", 38 | "func": "lib.connection.cache.redisConnectionManager" 39 | }, { 40 | "id": "dbTransactionManager", 41 | "func": "lib.transaction.dbTransactionManager", 42 | "props": [{ 43 | "name": "connectionManager", 44 | "ref": "mysqlConnectionManager" 45 | }], 46 | "proxy": false 47 | }, { 48 | "id": "transactionAspect", 49 | "func": "lib.aspect.transactionAspect", 50 | "props": [{ 51 | "name": "dbTransactionManager", 52 | "ref": "dbTransactionManager" 53 | }], 54 | "aop": [{ 55 | "pointcut": "around:.*?Transaction$", 56 | "advice": "doInTransaction", 57 | "order": 100, 58 | "runtime": true 59 | }] 60 | }] 61 | } -------------------------------------------------------------------------------- /coverage/blanket.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var srcDir = path.join(__dirname, '..', 'lib'); 3 | 4 | require('blanket')({ 5 | // Only files that match the pattern will be instrumented 6 | pattern: srcDir 7 | }) -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | grunt.loadNpmTasks('grunt-mocha-test'); 6 | grunt.loadNpmTasks("grunt-jscoverage"); 7 | grunt.loadNpmTasks('grunt-contrib-clean'); 8 | grunt.loadNpmTasks('grunt-contrib-jshint'); 9 | 10 | var src = ['test/core/domainDaoSupport.js', 'test/connection/cache/*.js', 11 | 'test/connection/sql/*.js', 'test/template/cache/*.js', 'test/util/*.js', 12 | 'test/bearcat-dao.js', 'test/loader/*.js', 'test/aspect/*.js' 13 | ]; 14 | 15 | // Project configuration. 16 | grunt.initConfig({ 17 | // Metadata. 18 | pkg: grunt.file.readJSON('package.json'), 19 | jscoverage: { 20 | options: { 21 | inputDirectory: 'lib', 22 | outputDirectory: 'lib-cov' 23 | } 24 | }, 25 | mochaTest: { 26 | dot: { 27 | options: { 28 | reporter: 'dot', 29 | timeout: 100000, 30 | require: 'coverage/blanket' 31 | }, 32 | src: src 33 | }, 34 | coverage: { 35 | options: { 36 | reporter: 'html-cov', 37 | quiet: true, 38 | captureFile: 'coverage.html' 39 | }, 40 | src: src 41 | } 42 | }, 43 | clean: { 44 | "coverage.html": { 45 | src: ['coverage.html'] 46 | } 47 | }, 48 | jshint: { 49 | all: ['lib/*'] 50 | } 51 | }); 52 | // Default task. 53 | // grunt.registerTask('default', ['clean', 'jscoverage', 'mochaTest:dot', 'jshint:all']); 54 | grunt.registerTask('default', ['clean', 'jscoverage', 'mochaTest']); 55 | }; -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | 0.2.12 / 2016-1-28 2 | ================== 3 | * update mysqlTemplate add directQuery, directAdd interface to be compatible with ddbTemplate 4 | 5 | 0.2.11 / 2015-10-14 6 | ================== 7 | * make domainDaoSupport support $ prefix sql 8 | 9 | 0.2.10 / 2015-5-24 10 | ================== 11 | * redisClusterTemplate add multi command same key transaction 12 | 13 | 0.2.9 / 2015-5-24 14 | ================== 15 | * redisClusterTemplate add multi command support 16 | 17 | 0.2.5 / 2015-4-28 18 | ================== 19 | * fix modelGet get value bug 20 | 21 | 0.2.4 / 2015-4-24 22 | ================== 23 | * fix directPlan get connection bug 24 | 25 | 0.2.3 / 2015-4-23 26 | ================== 27 | * add dependency bearcat-sql 28 | 29 | 0.2.2 / 2015-4-23 30 | ================== 31 | * add mysql and redis cluster client sharding support based on bearcat-ha 32 | 33 | 0.2.1 / 2015-3-1 34 | ================== 35 | * fix some bugs, make improvements 36 | 37 | 0.2.0 / 2015-3-1 38 | ================== 39 | * release 0.2.0, see [bearcat-dao](http://bearcatjs.org/topic/dao.html) 40 | 41 | 0.1.x ~ 0.2.0 42 | ================ 43 | dao, sql mapping, transaction -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/bearcat-dao'); -------------------------------------------------------------------------------- /lib/aspect/cacheAspect.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bearcatjs/bearcat-dao/5affc25fd2705e3aeaca5e82ad6ac21fdaa4c0af/lib/aspect/cacheAspect.js -------------------------------------------------------------------------------- /lib/aspect/transactionAspect.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao TransactionAspect 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'TransactionAspect'); 15 | 16 | /** 17 | * TransactionAspect constructor function. 18 | * 19 | * @api public 20 | */ 21 | var TransactionAspect = function() { 22 | this.dbTransactionManager = null; 23 | } 24 | 25 | module.exports = TransactionAspect; 26 | 27 | /** 28 | * TransactionAspect set dbTransactionManager. 29 | * 30 | * @param {Object} dbTransactionManager 31 | * @api public 32 | */ 33 | TransactionAspect.prototype.setDbTransactionManager = function(dbTransactionManager) { 34 | this.dbTransactionManager = dbTransactionManager; 35 | } 36 | 37 | /** 38 | * TransactionAspect get dbTransactionManager. 39 | * 40 | * @param {Object} dbTransactionManager 41 | * @api public 42 | */ 43 | TransactionAspect.prototype.getDbTransactionManager = function() { 44 | return this.dbTransactionManager; 45 | } 46 | 47 | /** 48 | * TransactionAspect do transaction action. 49 | * 50 | * @api public 51 | */ 52 | TransactionAspect.prototype.doInTransaction = function() { 53 | var self = this; 54 | arguments = Array.prototype.slice.apply(arguments); 55 | var target = arguments.shift(); 56 | var method = arguments.shift(); 57 | var next = arguments.pop(); 58 | var args = arguments; 59 | var nargs = []; 60 | 61 | logger.info('begain transaction'); 62 | this.dbTransactionManager.getTransaction(function(err, transactionStatus) { 63 | if (err) { 64 | logger.error('get transaction error ' + err.message); 65 | return; 66 | } 67 | 68 | var n = function(err) { 69 | arguments = Array.prototype.slice.apply(arguments); 70 | nargs = arguments; 71 | if (err) { 72 | logger.error('transaction error ' + err.message); 73 | self.dbTransactionManager.rollback(transactionStatus, function() { 74 | next.apply(null, nargs); 75 | }); 76 | return; 77 | } 78 | 79 | self.dbTransactionManager.commit(transactionStatus, function(err) { 80 | if (err) { 81 | logger.error('transaction commit error' + err.message); 82 | self.dbTransactionManager.rollback(transactionStatus, function() { 83 | next.apply(null, nargs); 84 | }); 85 | return; 86 | } 87 | logger.info('transaction success'); 88 | next.apply(null, nargs); 89 | }); 90 | } 91 | 92 | args.push(n); 93 | args.push(transactionStatus); 94 | try { 95 | target[method].apply(target, args); 96 | } catch (e) { 97 | if (e) { 98 | logger.error('transaction error ' + e.stack); 99 | self.dbTransactionManager.rollback(transactionStatus, function() { 100 | next.apply(null, nargs); 101 | return; 102 | }); 103 | } 104 | } 105 | }); 106 | } -------------------------------------------------------------------------------- /lib/bearcat-dao.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao App 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'app'); 15 | var ShardingUtil = require('./util/shardingUtil'); 16 | var SqlLoader = require('./loader/sqlLoader'); 17 | var PlanHelper = require('./plan/planHelper'); 18 | var Package = require('../package.json'); 19 | var Utils = require('./util/utils'); 20 | 21 | var BearcatDao = { 22 | configLocations: [], 23 | version: Package.version, 24 | sqlLoader: new SqlLoader() 25 | }; 26 | 27 | BearcatDao.getSQL = function(sqlId) { 28 | return this.sqlLoader.getSQL(sqlId); 29 | } 30 | 31 | BearcatDao.loadSQL = function(configLocations) { 32 | if (!Utils.checkArray(configLocations)) { 33 | logger.error('configLocations must be Array.'); 34 | return; 35 | } 36 | 37 | this.addConfigLocations(configLocations); 38 | this.sqlLoader.load(configLocations); 39 | } 40 | 41 | BearcatDao.addConfigLocations = function(locations) { 42 | this.configLocations = this.configLocations.concat(locations); 43 | } 44 | 45 | BearcatDao.calDestDB = PlanHelper.calDestDB; 46 | 47 | BearcatDao.calDestDBs = PlanHelper.calDestDBs; 48 | 49 | BearcatDao.getDestDBAll = PlanHelper.getDestDBAll; 50 | 51 | BearcatDao.getShardingUtil = function(type) { 52 | return ShardingUtil(type); 53 | } 54 | 55 | module.exports = BearcatDao; -------------------------------------------------------------------------------- /lib/connection/cache/redisClusterConnectionManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao RedisClusterConnectionManager 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'RedisClusterConnectionManager'); 15 | var EventEmitter = require('events').EventEmitter; 16 | var Constant = require('../../util/constant'); 17 | var utils = require('../../util/utils'); 18 | var BearcatHa = require('bearcat-ha'); 19 | var HASTATE = BearcatHa.HASTATE; 20 | var redis = require('redis'); 21 | var Util = require('util'); 22 | 23 | /** 24 | * RedisClusterConnectionManager constructor function. 25 | * 26 | * @api public 27 | */ 28 | var RedisClusterConnectionManager = function() { 29 | this.poolMap = {}; 30 | this.dbUrlMap = {}; 31 | this.password = null; // redis password 32 | this.retry_max_delay = Constant.REDIS_RETRY_MAX_DELAY; 33 | this.options = {}; 34 | this.usePool = true; 35 | this.connectionCb = Constant.DEFAULT_REDIS_CONNECT_CB; 36 | this.zkChroot = null; 37 | this.zkServers = null; 38 | this.zkUsername = null; 39 | this.zkPassword = null; 40 | this.haClient = null; 41 | } 42 | 43 | Util.inherits(RedisClusterConnectionManager, EventEmitter); 44 | 45 | RedisClusterConnectionManager.prototype.initHaClient = function(cb) { 46 | var opts = { 47 | chroot: this.zkChroot, 48 | servers: this.zkServers, 49 | username: this.zkUsername, 50 | password: this.zkPassword 51 | }; 52 | 53 | var haClient = BearcatHa.createClient(opts); 54 | 55 | var self = this; 56 | haClient.on('ready', function() { 57 | logger.info('this.haClient ready, state: %j', haClient.haState); 58 | cb && cb(); 59 | }); 60 | 61 | haClient.on('change', function(name, state) { 62 | logger.info('haClient %s state changed: %j', name, state); 63 | }); 64 | 65 | haClient.on('nodeAdd', function(name, state) { 66 | logger.info('haClient %s state nodeAdd: %j', name, state); 67 | }); 68 | 69 | haClient.on('nodeRemove', function(name, state) { 70 | logger.info('haClient %s state nodeRemove: %j', name, state); 71 | }); 72 | 73 | haClient.on('masterChange', function(name, state) { 74 | logger.error('haClient %s master changed, state: %j', name, state); 75 | }); 76 | 77 | haClient.on('error', function(err) { 78 | logger.error('haClient error ' + err.stack); 79 | }); 80 | 81 | this.haClient = haClient; 82 | } 83 | 84 | /** 85 | * RedisClusterConnectionManager get connection. 86 | * 87 | * @param {Function} cb callback function 88 | * @api public 89 | */ 90 | RedisClusterConnectionManager.prototype.getConnection = function(node, role, cb) { 91 | this.fetchConnection(node, role, function(err, connection) { 92 | if (err) { 93 | return cb(err); 94 | } 95 | 96 | cb(err, connection); 97 | }); 98 | } 99 | 100 | RedisClusterConnectionManager.prototype.restartHaClient = function() { 101 | if (this.haClient) { 102 | this.haClient.restart(); 103 | } 104 | } 105 | 106 | /** 107 | * RedisClusterConnectionManager release connection. 108 | * 109 | * @param {Object} connection 110 | * @api public 111 | */ 112 | RedisClusterConnectionManager.prototype.release = function(connection) { 113 | connection.end(); 114 | } 115 | 116 | /** 117 | * RedisClusterConnectionManager end connection. 118 | * 119 | * @param {Object} connection 120 | * @api public 121 | */ 122 | RedisClusterConnectionManager.prototype.end = function(connection) { 123 | connection.end(); 124 | } 125 | 126 | /** 127 | * RedisClusterConnectionManager destroy connection. 128 | * 129 | * @param {Object} connection 130 | * @api public 131 | */ 132 | RedisClusterConnectionManager.prototype.destroy = function(connection) { 133 | connection.destroy(); 134 | } 135 | 136 | /** 137 | * RedisClusterConnectionManager fetch connection. 138 | * 139 | * @param {Function} cb callback function 140 | * @api public 141 | */ 142 | RedisClusterConnectionManager.prototype.fetchConnection = function(node, role, cb) { 143 | if (!utils.checkFunction(cb)) { 144 | cb = this.connectionCb; 145 | } 146 | 147 | var self = this; 148 | if (!this.haClient) { 149 | this.initHaClient(function() { 150 | self.fetchConnection(node, role, cb); 151 | }); 152 | return; 153 | } 154 | 155 | if (this.haClient) { 156 | var haStatus = this.haClient.state; 157 | if (haStatus < HASTATE.STATE_READY) { 158 | // when haClient zookeeper is initing or reconnecting 159 | if (haStatus != HASTATE.STATE_TIMEOUT) { 160 | // haState is not ready, just wait in event-loop to try again and again 161 | return setTimeout(function() { 162 | self.fetchConnection(node, role, cb); 163 | }, 1000); 164 | } else { 165 | // connect zookeeper timeout, no need to retry for the case that closure memory will leak 166 | return cb(); 167 | } 168 | } 169 | } 170 | 171 | var targetDB = this.getTargetDB(node, role); 172 | if (!targetDB) { 173 | return cb(); 174 | } 175 | 176 | var parsedTargetDB = this.parseTargetDB(targetDB); 177 | 178 | var connection = this.poolMap[targetDB]; 179 | if (!connection) { 180 | connection = this.createConnection(parsedTargetDB); 181 | connection['nodeName'] = node; 182 | connection['clientName'] = targetDB; 183 | this.poolMap[targetDB] = connection; 184 | // logger.debug('createConnection %s %s %j', node, role, targetDB); 185 | } 186 | 187 | return cb(null, connection); 188 | } 189 | 190 | RedisClusterConnectionManager.prototype.getTargetDB = function(node, role) { 191 | var targetNode = this.haClient.getClient(node, role); 192 | return targetNode; 193 | } 194 | 195 | RedisClusterConnectionManager.prototype.parseTargetDB = function(targetDB) { 196 | if (!targetDB) { 197 | return; 198 | } 199 | 200 | var urlMap = this.dbUrlMap[targetDB]; 201 | if (urlMap) { 202 | return urlMap; 203 | } 204 | 205 | urlMap = this.doParseTargetDB(targetDB); 206 | if (!urlMap) { 207 | return; 208 | } 209 | 210 | this.dbUrlMap[targetDB] = urlMap; 211 | return urlMap; 212 | } 213 | 214 | RedisClusterConnectionManager.prototype.doParseTargetDB = function(targetDB) { 215 | var hosts = targetDB.split(":"); 216 | if (hosts.length <= 1) { 217 | return; 218 | } 219 | 220 | var host = hosts[0]; 221 | var port = parseInt(hosts[1]); 222 | 223 | return { 224 | host: host, 225 | port: port 226 | } 227 | } 228 | 229 | RedisClusterConnectionManager.prototype.bindEvents = function(connection) { 230 | connection.on("ready", function() { 231 | logger.info('redis %s %s ready', connection['nodeName'], connection['clientName']); 232 | }); 233 | 234 | connection.on("connect", function() { 235 | logger.info('redis %s %s connect', connection['nodeName'], connection['clientName']); 236 | }); 237 | 238 | connection.on("error", function(err) { 239 | logger.error('redis %s %s error %s', connection['nodeName'], connection['clientName'], err.stack); 240 | }); 241 | 242 | connection.on("end", function() { 243 | logger.error('redis %s %s end', connection['nodeName'], connection['clientName']); 244 | }); 245 | 246 | var haClient = this.haClient; 247 | var self = this; 248 | connection.on("end", function() { 249 | var nodeName = connection['nodeName']; 250 | var clientName = connection['clientName']; 251 | 252 | if (!haClient.checkValid(nodeName, clientName)) { 253 | self.removePoolNode(clientName); 254 | } 255 | }); 256 | 257 | connection.on("drain", this.emit.bind(this, 'drain')); 258 | 259 | connection.on("idle", this.emit.bind(this, 'idle')); 260 | } 261 | 262 | /** 263 | * RedisClusterConnectionManager create connection. 264 | * 265 | * @api public 266 | */ 267 | RedisClusterConnectionManager.prototype.createConnection = function(dbOptions) { 268 | var options = this.getConnectionOptions(); 269 | 270 | // logger.debug('createConnection %j %j', dbOptions, options); 271 | var connection = redis.createClient(dbOptions['port'], dbOptions['host'], options); 272 | this.bindEvents(connection); 273 | 274 | return this.postProcessConnection(connection); 275 | } 276 | 277 | /** 278 | * RedisClusterConnectionManager get connection options. 279 | * 280 | * @return {Object} connection options 281 | * @api public 282 | */ 283 | RedisClusterConnectionManager.prototype.getConnectionOptions = function() { 284 | var options = this.options || {}; 285 | options['auth_pass'] = this.password; 286 | options['retry_max_delay'] = this.retry_max_delay; 287 | 288 | return options 289 | } 290 | 291 | /** 292 | * RedisClusterConnectionManager post process connection. 293 | * 294 | * @param {Object} connection 295 | * @api public 296 | */ 297 | RedisClusterConnectionManager.prototype.postProcessConnection = function(connection) { 298 | return connection; 299 | } 300 | 301 | /** 302 | * RedisClusterConnectionManager set password. 303 | * 304 | * @param {String} password 305 | * @api public 306 | */ 307 | RedisClusterConnectionManager.prototype.setPassword = function(password) { 308 | this.password = password; 309 | } 310 | 311 | /** 312 | * RedisClusterConnectionManager get password. 313 | * 314 | * @return {String} password 315 | * @api public 316 | */ 317 | RedisClusterConnectionManager.prototype.getPassword = function() { 318 | return this.password; 319 | } 320 | 321 | /** 322 | * RedisClusterConnectionManager set options. 323 | * 324 | * @param {Object} options 325 | * @api public 326 | */ 327 | RedisClusterConnectionManager.prototype.setOptions = function(options) { 328 | this.options = options; 329 | } 330 | 331 | /** 332 | * RedisClusterConnectionManager get options. 333 | * 334 | * @return {Object} options 335 | * @api public 336 | */ 337 | RedisClusterConnectionManager.prototype.getOptions = function() { 338 | return this.options; 339 | } 340 | 341 | /** 342 | * RedisClusterConnectionManager set pool. 343 | * 344 | * @return {Object} pool 345 | * @api public 346 | */ 347 | RedisClusterConnectionManager.prototype.setPool = function(key, pool) { 348 | this.poolMap[key] = pool; 349 | } 350 | 351 | /** 352 | * RedisClusterConnectionManager get pool. 353 | * 354 | * @return {Object} pool 355 | * @api public 356 | */ 357 | RedisClusterConnectionManager.prototype.getPool = function(key) { 358 | return this.poolMap; 359 | } 360 | 361 | /** 362 | * RedisClusterConnectionManager remove pool node. 363 | * 364 | * @return {String} key pool key 365 | * @api private 366 | */ 367 | RedisClusterConnectionManager.prototype.removePoolNode = function(key) { 368 | var connection = this.poolMap[key]; 369 | if (!connection) { 370 | return; 371 | } 372 | 373 | connection.end(); 374 | delete this.poolMap[key]; 375 | } 376 | 377 | module.exports = RedisClusterConnectionManager; -------------------------------------------------------------------------------- /lib/connection/cache/redisConnection.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao RedisConnection 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var EventEmitter = require('events').EventEmitter; 15 | var Constant = require('../../util/constant'); 16 | var redis = require('redis'); 17 | var util = require('util'); 18 | 19 | /** 20 | * RedisConnection constructor function. 21 | * 22 | * @api public 23 | */ 24 | var RedisConnection = function() { 25 | this.connection = null; 26 | } 27 | 28 | util.inherits(RedisConnection, EventEmitter); 29 | 30 | /** 31 | * RedisConnection set connection. 32 | * 33 | * @param {Object} connection 34 | * @api public 35 | */ 36 | RedisConnection.prototype.setConnection = function(connection) { 37 | this.connection = connection; 38 | } 39 | 40 | /** 41 | * RedisConnection create connection by host, port. 42 | * 43 | * @param {Number} pot 44 | * @param {String} host 45 | * @param {Object} options 46 | * @api public 47 | */ 48 | module.exports.createConnection = function(port, host, options) { 49 | var connection = redis.createClient(this.port, this.host, this.options); 50 | var rConnection = new RedisConnection(); 51 | rConnection.setConnection(connection); 52 | return rConnection; 53 | } 54 | 55 | /** 56 | * RedisConnection create connection by unix. 57 | * 58 | * @param {String} unixDomain 59 | * @api public 60 | */ 61 | module.exports.createConnectionUnix = function(unixDomain) { 62 | var connection = redis.createClient(this.unixDomain); 63 | var rConnection = new RedisConnection(); 64 | rConnection.setConnection(connection); 65 | return rConnection; 66 | } -------------------------------------------------------------------------------- /lib/connection/cache/redisConnectionManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao RedisConnectionManager 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var EventEmitter = require('events').EventEmitter; 15 | var Constant = require('../../util/constant'); 16 | var redis = require('redis'); 17 | var util = require('util'); 18 | 19 | /** 20 | * RedisConnectionManager constructor function. 21 | * 22 | * @api public 23 | */ 24 | var RedisConnectionManager = function() { 25 | this.port = Constant.DEFAULT_REDIS_PORT; 26 | this.host = Constant.DEFAULT_REDIS_HOST; 27 | this.password = null; 28 | this.unixDomain = null; 29 | this.options = null; 30 | } 31 | 32 | util.inherits(RedisConnectionManager, EventEmitter); 33 | 34 | module.exports = RedisConnectionManager; 35 | 36 | /** 37 | * RedisConnectionManager get connection. 38 | * 39 | * @api public 40 | */ 41 | RedisConnectionManager.prototype.getConnection = function() { 42 | var connection = this.fetchConnector(); 43 | this.bindEvents(connection); 44 | 45 | return this.postProcessConnection(connection); 46 | } 47 | 48 | /** 49 | * RedisConnectionManager release connection. 50 | * 51 | * @param {Object} connection 52 | * @api public 53 | */ 54 | RedisConnectionManager.prototype.release = function(connection) { 55 | connection.end(); 56 | } 57 | 58 | /** 59 | * RedisConnectionManager get connection(unixDomain). 60 | * 61 | * @api public 62 | */ 63 | RedisConnectionManager.prototype.getConnectionUnix = function() { 64 | var useUnixDomain = true; 65 | var connection = this.fetchConnector(useUnixDomain); 66 | this.bindEvents(connection); 67 | 68 | return this.postProcessConnection(connection); 69 | } 70 | 71 | /** 72 | * RedisConnectionManager fetch connection. 73 | * 74 | * @param {Boolean} useUnixDomain 75 | * @api public 76 | */ 77 | RedisConnectionManager.prototype.fetchConnector = function(useUnixDomain) { 78 | var connection = null; 79 | if (!useUnixDomain) { 80 | connection = redis.createClient(this.getPort(), this.getHost(), this.getOptions()); 81 | } else { 82 | connection = redis.createClient(this.getUnixDomain()); 83 | } 84 | 85 | var password = this.getPassword(); 86 | if (password) { 87 | connection.auth(password) 88 | } 89 | 90 | return connection; 91 | } 92 | 93 | /** 94 | * RedisConnectionManager bind connection. 95 | * 96 | * @param {Object} connection 97 | * @api public 98 | */ 99 | RedisConnectionManager.prototype.bindEvents = function(connection) { 100 | connection.on("ready", this.emit.bind(this, 'ready')); 101 | 102 | connection.on("connect", this.emit.bind(this, 'connect')); 103 | 104 | connection.on("error", this.emit.bind(this, 'error')); 105 | 106 | connection.on("end", this.emit.bind(this, 'end')); 107 | 108 | connection.on("drain", this.emit.bind(this, 'drain')); 109 | 110 | connection.on("idle", this.emit.bind(this, 'idle')); 111 | } 112 | 113 | /** 114 | * RedisConnectionManager post process connection. 115 | * 116 | * @param {Object} connection 117 | * @api public 118 | */ 119 | RedisConnectionManager.prototype.postProcessConnection = function(connection) { 120 | return connection; 121 | } 122 | 123 | /** 124 | * RedisConnectionManager set port. 125 | * 126 | * @param {Number} port 127 | * @api public 128 | */ 129 | RedisConnectionManager.prototype.setPort = function(port) { 130 | this.port = port; 131 | } 132 | 133 | /** 134 | * RedisConnectionManager get port. 135 | * 136 | * @return {Number} port 137 | * @api public 138 | */ 139 | RedisConnectionManager.prototype.getPort = function() { 140 | return this.port; 141 | } 142 | 143 | /** 144 | * RedisConnectionManager set host. 145 | * 146 | * @param {String} host 147 | * @api public 148 | */ 149 | RedisConnectionManager.prototype.setHost = function(host) { 150 | this.host = host; 151 | } 152 | 153 | /** 154 | * RedisConnectionManager get host. 155 | * 156 | * @param {String} host 157 | * @api public 158 | */ 159 | RedisConnectionManager.prototype.getHost = function() { 160 | return this.host; 161 | } 162 | 163 | /** 164 | * RedisConnectionManager set password. 165 | * 166 | * @param {String} password 167 | * @api public 168 | */ 169 | RedisConnectionManager.prototype.setPassword = function(password) { 170 | this.password = password; 171 | } 172 | 173 | /** 174 | * RedisConnectionManager get password. 175 | * 176 | * @return {String} password 177 | * @api public 178 | */ 179 | RedisConnectionManager.prototype.getPassword = function() { 180 | return this.password; 181 | } 182 | 183 | /** 184 | * RedisConnectionManager set unixDomain. 185 | * 186 | * @param {Boolean} unixDomain 187 | * @api public 188 | */ 189 | RedisConnectionManager.prototype.setUnixDomain = function(unixDomain) { 190 | this.unixDomain = unixDomain; 191 | } 192 | 193 | /** 194 | * RedisConnectionManager get unixDomain. 195 | * 196 | * @return {Boolean} unixDomain 197 | * @api public 198 | */ 199 | RedisConnectionManager.prototype.getUnixDomain = function() { 200 | return this.unixDomain; 201 | } 202 | 203 | /** 204 | * RedisConnectionManager set options. 205 | * 206 | * @param {Object} options 207 | * @api public 208 | */ 209 | RedisConnectionManager.prototype.setOptions = function(options) { 210 | this.options = options; 211 | } 212 | 213 | /** 214 | * RedisConnectionManager get options. 215 | * 216 | * @return {Object} options 217 | * @api public 218 | */ 219 | RedisConnectionManager.prototype.getOptions = function() { 220 | return this.options; 221 | } -------------------------------------------------------------------------------- /lib/connection/sql/ddbConnectionManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DDBConnectionManager 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'DDBConnectionManager'); 15 | var EventEmitter = require('events').EventEmitter; 16 | var Constant = require('../../util/constant'); 17 | var utils = require('../../util/utils'); 18 | var BearcatHa = require('bearcat-ha'); 19 | var HASTATE = BearcatHa.HASTATE; 20 | var mysql = require('mysql'); 21 | var Util = require('util'); 22 | 23 | /** 24 | * DDBConnectionManager constructor function. 25 | * 26 | * @api public 27 | */ 28 | var DDBConnectionManager = function() { 29 | this.poolMap = {}; 30 | this.dbUrlMap = {}; 31 | this.user = null; // mysql username 32 | this.password = null; // mysql password 33 | this.options = {}; 34 | this.usePool = Constant.DEFAULT_MYSQL_USE_POOL; 35 | this.connectionCb = Constant.DEFAULT_MYSQL_CONNECT_CB; 36 | this.charset = null; 37 | this.zkChroot = null; 38 | this.zkServers = null; 39 | this.zkUsername = null; 40 | this.zkPassword = null; 41 | this.haClient = null; 42 | } 43 | 44 | Util.inherits(DDBConnectionManager, EventEmitter); 45 | 46 | DDBConnectionManager.prototype.initHaClient = function(cb) { 47 | var opts = { 48 | chroot: this.zkChroot, 49 | servers: this.zkServers, 50 | username: this.zkUsername, 51 | password: this.zkPassword 52 | }; 53 | 54 | var haClient = BearcatHa.createClient(opts); 55 | 56 | haClient.once('ready', function() { 57 | logger.info('this.haClient ready, state: %j', haClient.haState); 58 | cb && cb(); 59 | }); 60 | 61 | haClient.on('change', function(name, state) { 62 | logger.info('haClient %s state changed: %j', name, state); 63 | }); 64 | 65 | haClient.on('nodeAdd', function(name, state) { 66 | logger.info('haClient %s state nodeAdd: %j', name, state); 67 | }); 68 | 69 | haClient.on('nodeRemove', function(name, state) { 70 | logger.info('haClient %s state nodeRemove: %j', name, state); 71 | }); 72 | 73 | haClient.on('masterChange', function(name, state) { 74 | logger.error('haClient %s master changed, state: %j', name, state); 75 | }); 76 | 77 | haClient.on('error', function(err) { 78 | logger.error('haClient error ' + err.stack); 79 | }); 80 | 81 | this.haClient = haClient; 82 | } 83 | 84 | /** 85 | * DDBConnectionManager get connection. 86 | * 87 | * @param {Function} cb callback function 88 | * @api public 89 | */ 90 | DDBConnectionManager.prototype.getConnection = function(node, role, cb) { 91 | var self = this; 92 | this.fetchConnection(node, role, function(err, connection) { 93 | if (err) { 94 | return cb(err); 95 | } 96 | 97 | self.bindEvents(connection); 98 | 99 | cb(err, connection); 100 | }); 101 | } 102 | 103 | /** 104 | * DDBConnectionManager release connection. 105 | * 106 | * @param {Object} connection 107 | * @api public 108 | */ 109 | DDBConnectionManager.prototype.release = function(connection) { 110 | if (this.usePool) { 111 | connection.release(); 112 | } else { 113 | connection.end(); 114 | } 115 | } 116 | 117 | /** 118 | * DDBConnectionManager end connection. 119 | * 120 | * @param {Object} connection 121 | * @api public 122 | */ 123 | DDBConnectionManager.prototype.end = function(connection) { 124 | connection.end(); 125 | } 126 | 127 | /** 128 | * DDBConnectionManager destroy connection. 129 | * 130 | * @param {Object} connection 131 | * @api public 132 | */ 133 | DDBConnectionManager.prototype.destroy = function(connection) { 134 | connection.destroy(); 135 | } 136 | 137 | /** 138 | * DDBConnectionManager fetch connection. 139 | * 140 | * @param {Function} cb callback function 141 | * @api public 142 | */ 143 | DDBConnectionManager.prototype.fetchConnection = function(node, role, cb) { 144 | if (!utils.checkFunction(cb)) { 145 | cb = this.connectionCb; 146 | } 147 | 148 | var self = this; 149 | if (!this.haClient) { 150 | this.initHaClient(function() { 151 | self.fetchConnection(node, role, cb); 152 | }); 153 | return; 154 | } 155 | 156 | if (this.haClient) { 157 | var haStatus = this.haClient.state; 158 | if (haStatus < HASTATE.STATE_READY) { 159 | // when haClient zookeeper is initing or reconnecting 160 | if (haStatus != HASTATE.STATE_TIMEOUT) { 161 | // haState is not ready, just wait in event-loop to try again and again 162 | return setTimeout(function() { 163 | self.fetchConnection(node, role, cb); 164 | }, 1000); 165 | } else { 166 | // connect zookeeper timeout, no need to retry for the case that closure memory will leak 167 | return cb(); 168 | } 169 | } 170 | } 171 | 172 | var targetDB = this.getTargetDB(node, role); 173 | var parsedTargetDB = this.parseTargetDB(targetDB); 174 | 175 | if (this.usePool) { 176 | if (!this.poolMap[targetDB]) { 177 | this.setPool(targetDB, this.createPool(parsedTargetDB)); 178 | } 179 | this.poolMap[targetDB].getConnection(cb); 180 | } else { 181 | var connection = this.createConnection(parsedTargetDB); 182 | cb(null, connection); 183 | } 184 | } 185 | 186 | DDBConnectionManager.prototype.getTargetDB = function(node, role) { 187 | var targetNode = this.haClient.getClient(node, role); 188 | return targetNode; 189 | } 190 | 191 | DDBConnectionManager.prototype.parseTargetDB = function(targetDB) { 192 | var urlMap = this.dbUrlMap[targetDB]; 193 | if (urlMap) { 194 | return urlMap; 195 | } 196 | 197 | urlMap = this.doParseTargetDB(targetDB); 198 | if (!urlMap) { 199 | return; 200 | } 201 | 202 | this.dbUrlMap[targetDB] = urlMap; 203 | return urlMap; 204 | } 205 | 206 | DDBConnectionManager.prototype.doParseTargetDB = function(targetDB) { 207 | var hosts = targetDB.split(":"); 208 | if (hosts.length <= 1) { 209 | return; 210 | } 211 | 212 | var host = hosts[0]; 213 | var left = hosts[1]; 214 | 215 | var ports = left.split("/"); 216 | if (ports.length <= 1) { 217 | return { 218 | host: host, 219 | port: left 220 | }; 221 | } 222 | 223 | var port = ports[0]; 224 | var database = ports[1]; 225 | 226 | return { 227 | host: host, 228 | port: port, 229 | database: database 230 | } 231 | } 232 | 233 | DDBConnectionManager.prototype.bindEvents = function(connection) { 234 | 235 | } 236 | 237 | /** 238 | * DDBConnectionManager create connection pool. 239 | * 240 | * @api public 241 | */ 242 | DDBConnectionManager.prototype.createPool = function(dbOptions) { 243 | var options = this.getConnectionOptions(); 244 | 245 | for (var key in dbOptions) { 246 | options[key] = dbOptions[key]; 247 | } 248 | 249 | var pool = mysql.createPool(options); 250 | 251 | return pool; 252 | } 253 | 254 | /** 255 | * DDBConnectionManager create connection. 256 | * 257 | * @api public 258 | */ 259 | DDBConnectionManager.prototype.createConnection = function(dbOptions) { 260 | var options = this.getConnectionOptions(); 261 | 262 | for (var key in dbOptions) { 263 | options[key] = dbOptions[key]; 264 | } 265 | 266 | var connection = mysql.createConnection(options); 267 | 268 | return this.postProcessConnection(connection); 269 | } 270 | 271 | /** 272 | * DDBConnectionManager get connection options. 273 | * 274 | * @return {Object} connection options 275 | * @api public 276 | */ 277 | DDBConnectionManager.prototype.getConnectionOptions = function() { 278 | var options = this.options || {}; 279 | options['host'] = this.host; 280 | options['port'] = this.port; 281 | options['user'] = this.user; 282 | options['password'] = this.password; 283 | options['database'] = this.database; 284 | options['charset'] = this.charset; 285 | 286 | return options 287 | } 288 | 289 | /** 290 | * DDBConnectionManager post process connection. 291 | * 292 | * @param {Object} connection 293 | * @api public 294 | */ 295 | DDBConnectionManager.prototype.postProcessConnection = function(connection) { 296 | return connection; 297 | } 298 | 299 | /** 300 | * DDBConnectionManager set user. 301 | * 302 | * @param {String} user username 303 | * @api public 304 | */ 305 | DDBConnectionManager.prototype.setUser = function(user) { 306 | this.user = user; 307 | } 308 | 309 | /** 310 | * DDBConnectionManager get user. 311 | * 312 | * @return {String} username 313 | * @api public 314 | */ 315 | DDBConnectionManager.prototype.getUser = function() { 316 | return this.user; 317 | } 318 | 319 | /** 320 | * DDBConnectionManager set password. 321 | * 322 | * @param {String} password 323 | * @api public 324 | */ 325 | DDBConnectionManager.prototype.setPassword = function(password) { 326 | this.password = password; 327 | } 328 | 329 | /** 330 | * DDBConnectionManager get password. 331 | * 332 | * @return {String} password 333 | * @api public 334 | */ 335 | DDBConnectionManager.prototype.getPassword = function() { 336 | return this.password; 337 | } 338 | 339 | /** 340 | * DDBConnectionManager set options. 341 | * 342 | * @param {Object} options 343 | * @api public 344 | */ 345 | DDBConnectionManager.prototype.setOptions = function(options) { 346 | this.options = options; 347 | } 348 | 349 | /** 350 | * DDBConnectionManager get options. 351 | * 352 | * @return {Object} options 353 | * @api public 354 | */ 355 | DDBConnectionManager.prototype.getOptions = function() { 356 | return this.options; 357 | } 358 | 359 | /** 360 | * DDBConnectionManager set usePool. 361 | * 362 | * @param {Boolean} usePool 363 | * @api public 364 | */ 365 | DDBConnectionManager.prototype.setUsePool = function(usePool) { 366 | this.usePool = usePool; 367 | } 368 | 369 | /** 370 | * DDBConnectionManager get usePool. 371 | * 372 | * @return {Boolean} usePool 373 | * @api public 374 | */ 375 | DDBConnectionManager.prototype.getUsePool = function() { 376 | return this.usePool; 377 | } 378 | 379 | /** 380 | * DDBConnectionManager set pool. 381 | * 382 | * @return {Object} pool 383 | * @api public 384 | */ 385 | DDBConnectionManager.prototype.setPool = function(key, pool) { 386 | this.poolMap[key] = pool; 387 | } 388 | 389 | /** 390 | * DDBConnectionManager get pool. 391 | * 392 | * @return {Object} pool 393 | * @api public 394 | */ 395 | DDBConnectionManager.prototype.getPool = function(key) { 396 | return this.poolMap; 397 | } 398 | 399 | module.exports = DDBConnectionManager; -------------------------------------------------------------------------------- /lib/connection/sql/mysqlConnectionManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao MysqlConnectionManager 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var EventEmitter = require('events').EventEmitter; 15 | var Constant = require('../../util/constant'); 16 | var utils = require('../../util/utils'); 17 | var mysql = require('mysql'); 18 | var util = require('util'); 19 | 20 | /** 21 | * MysqlConnectionManager constructor function. 22 | * 23 | * @api public 24 | */ 25 | var MysqlConnectionManager = function() { 26 | this.pool = null; 27 | this.user = null; 28 | this.options = {}; 29 | this.password = null; 30 | this.database = null; 31 | this.port = Constant.DEFAULT_MYSQL_PORT; 32 | this.host = Constant.DEFAULT_MYSQL_HOST; 33 | this.usePool = Constant.DEFAULT_MYSQL_USE_POOL; 34 | this.connectionCb = Constant.DEFAULT_MYSQL_CONNECT_CB; 35 | this.charset = null; 36 | } 37 | 38 | util.inherits(MysqlConnectionManager, EventEmitter); 39 | 40 | module.exports = MysqlConnectionManager; 41 | 42 | /** 43 | * MysqlConnectionManager get connection. 44 | * 45 | * @param {Function} cb callback function 46 | * @api public 47 | */ 48 | MysqlConnectionManager.prototype.getConnection = function(cb) { 49 | var self = this; 50 | this.fetchConnector(function(err, connection) { 51 | if (err) { 52 | cb(err); 53 | return; 54 | } 55 | 56 | self.bindEvents(connection); 57 | 58 | cb(err, connection); 59 | }); 60 | } 61 | 62 | MysqlConnectionManager.prototype.genId = function(connection, tableName) { 63 | 64 | } 65 | 66 | /** 67 | * MysqlConnectionManager release connection. 68 | * 69 | * @param {Object} connection 70 | * @api public 71 | */ 72 | MysqlConnectionManager.prototype.release = function(connection) { 73 | if (this.usePool) { 74 | connection.release(); 75 | } else { 76 | connection.end(); 77 | } 78 | } 79 | 80 | /** 81 | * MysqlConnectionManager end connection. 82 | * 83 | * @param {Object} connection 84 | * @api public 85 | */ 86 | MysqlConnectionManager.prototype.end = function(connection) { 87 | connection.end(); 88 | } 89 | 90 | /** 91 | * MysqlConnectionManager destroy connection. 92 | * 93 | * @param {Object} connection 94 | * @api public 95 | */ 96 | MysqlConnectionManager.prototype.destroy = function(connection) { 97 | connection.destroy(); 98 | } 99 | 100 | /** 101 | * MysqlConnectionManager fetch connection. 102 | * 103 | * @param {Function} cb callback function 104 | * @api public 105 | */ 106 | MysqlConnectionManager.prototype.fetchConnector = function(cb) { 107 | if (!utils.checkFunction(cb)) { 108 | cb = this.connectionCb; 109 | } 110 | if (this.usePool) { 111 | if (!this.pool) { 112 | this.setPool(this.createPool()); 113 | } 114 | this.pool.getConnection(function(err, connection) { 115 | // connected! (unless `err` is set) 116 | cb(err, connection); 117 | }); 118 | } else { 119 | var connection = this.createConnection(); 120 | cb(null, connection); 121 | } 122 | } 123 | 124 | MysqlConnectionManager.prototype.bindEvents = function(connection) { 125 | 126 | } 127 | 128 | /** 129 | * MysqlConnectionManager create connection pool. 130 | * 131 | * @api public 132 | */ 133 | MysqlConnectionManager.prototype.createPool = function() { 134 | var options = this.getConnectionOptions(); 135 | 136 | var pool = mysql.createPool(options); 137 | 138 | return pool; 139 | } 140 | 141 | /** 142 | * MysqlConnectionManager create connection. 143 | * 144 | * @api public 145 | */ 146 | MysqlConnectionManager.prototype.createConnection = function() { 147 | var options = this.getConnectionOptions(); 148 | 149 | var connection = mysql.createConnection(options); 150 | 151 | return this.postProcessConnection(connection); 152 | } 153 | 154 | /** 155 | * MysqlConnectionManager get connection options. 156 | * 157 | * @return {Object} connection options 158 | * @api public 159 | */ 160 | MysqlConnectionManager.prototype.getConnectionOptions = function() { 161 | var options = this.options || {}; 162 | options['host'] = this.host; 163 | options['port'] = this.port; 164 | options['user'] = this.user; 165 | options['password'] = this.password; 166 | options['database'] = this.database; 167 | options['charset'] = this.charset; 168 | 169 | return options 170 | } 171 | 172 | /** 173 | * MysqlConnectionManager post process connection. 174 | * 175 | * @param {Object} connection 176 | * @api public 177 | */ 178 | MysqlConnectionManager.prototype.postProcessConnection = function(connection) { 179 | return connection; 180 | } 181 | 182 | /** 183 | * MysqlConnectionManager set port. 184 | * 185 | * @param {Number} port 186 | * @api public 187 | */ 188 | MysqlConnectionManager.prototype.setPort = function(port) { 189 | this.port = port; 190 | } 191 | 192 | /** 193 | * MysqlConnectionManager get port. 194 | * 195 | * @return {Number} port 196 | * @api public 197 | */ 198 | MysqlConnectionManager.prototype.getPort = function() { 199 | return this.port; 200 | } 201 | 202 | /** 203 | * MysqlConnectionManager set host. 204 | * 205 | * @param {String} host 206 | * @api public 207 | */ 208 | MysqlConnectionManager.prototype.setHost = function(host) { 209 | this.host = host; 210 | } 211 | 212 | /** 213 | * MysqlConnectionManager get host. 214 | * 215 | * @return {String} host 216 | * @api public 217 | */ 218 | MysqlConnectionManager.prototype.getHost = function() { 219 | return this.host; 220 | } 221 | 222 | /** 223 | * MysqlConnectionManager set user. 224 | * 225 | * @param {String} user username 226 | * @api public 227 | */ 228 | MysqlConnectionManager.prototype.setUser = function(user) { 229 | this.user = user; 230 | } 231 | 232 | /** 233 | * MysqlConnectionManager get user. 234 | * 235 | * @return {String} username 236 | * @api public 237 | */ 238 | MysqlConnectionManager.prototype.getUser = function() { 239 | return this.user; 240 | } 241 | 242 | /** 243 | * MysqlConnectionManager set password. 244 | * 245 | * @param {String} password 246 | * @api public 247 | */ 248 | MysqlConnectionManager.prototype.setPassword = function(password) { 249 | this.password = password; 250 | } 251 | 252 | /** 253 | * MysqlConnectionManager get password. 254 | * 255 | * @return {String} password 256 | * @api public 257 | */ 258 | MysqlConnectionManager.prototype.getPassword = function() { 259 | return this.password; 260 | } 261 | 262 | /** 263 | * MysqlConnectionManager set database. 264 | * 265 | * @param {String} database 266 | * @api public 267 | */ 268 | MysqlConnectionManager.prototype.setDatabase = function(database) { 269 | this.database = database; 270 | } 271 | 272 | /** 273 | * MysqlConnectionManager get database. 274 | * 275 | * @return {String} database 276 | * @api public 277 | */ 278 | MysqlConnectionManager.prototype.getDatabase = function() { 279 | return this.database; 280 | } 281 | 282 | /** 283 | * MysqlConnectionManager set options. 284 | * 285 | * @param {Object} options 286 | * @api public 287 | */ 288 | MysqlConnectionManager.prototype.setOptions = function(options) { 289 | this.options = options; 290 | } 291 | 292 | /** 293 | * MysqlConnectionManager get options. 294 | * 295 | * @return {Object} options 296 | * @api public 297 | */ 298 | MysqlConnectionManager.prototype.getOptions = function() { 299 | return this.options; 300 | } 301 | 302 | /** 303 | * MysqlConnectionManager set usePool. 304 | * 305 | * @param {Boolean} usePool 306 | * @api public 307 | */ 308 | MysqlConnectionManager.prototype.setUsePool = function(usePool) { 309 | this.usePool = usePool; 310 | } 311 | 312 | /** 313 | * MysqlConnectionManager get usePool. 314 | * 315 | * @return {Boolean} usePool 316 | * @api public 317 | */ 318 | MysqlConnectionManager.prototype.getUsePool = function() { 319 | return this.usePool; 320 | } 321 | 322 | /** 323 | * MysqlConnectionManager set pool. 324 | * 325 | * @return {Object} pool 326 | * @api public 327 | */ 328 | MysqlConnectionManager.prototype.setPool = function(pool) { 329 | this.pool = pool; 330 | } 331 | 332 | /** 333 | * MysqlConnectionManager get pool. 334 | * 335 | * @return {Object} pool 336 | * @api public 337 | */ 338 | MysqlConnectionManager.prototype.getPool = function() { 339 | return this.pool; 340 | } -------------------------------------------------------------------------------- /lib/core/sqlDaoSupport.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bearcatjs/bearcat-dao/5affc25fd2705e3aeaca5e82ad6ac21fdaa4c0af/lib/core/sqlDaoSupport.js -------------------------------------------------------------------------------- /lib/definition/deleteDefinition.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DeleteDefinition 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var SqlDefinition = require('./sqlDefinition'); 15 | var Util = require('util'); 16 | 17 | var DeleteDefinition = function() { 18 | SqlDefinition.call(this); 19 | this.type = "delete"; 20 | } 21 | 22 | Util.inherits(DeleteDefinition, SqlDefinition); 23 | 24 | module.exports = DeleteDefinition; -------------------------------------------------------------------------------- /lib/definition/expression/columnDefinition.js: -------------------------------------------------------------------------------- 1 | var ColumnDefinition = function() { 2 | this.name = null; 3 | this.type = null; 4 | this.alias = null; 5 | this.distinct = false; 6 | } 7 | 8 | ColumnDefinition.prototype.setName = function(name) { 9 | this.name = name; 10 | } 11 | 12 | ColumnDefinition.prototype.getName = function() { 13 | return this.name; 14 | } 15 | 16 | ColumnDefinition.prototype.setType = function(type) { 17 | this.type = type; 18 | } 19 | 20 | ColumnDefinition.prototype.getType = function() { 21 | return this.type; 22 | } 23 | 24 | ColumnDefinition.prototype.setAlias = function(alias) { 25 | this.alias = alias; 26 | } 27 | 28 | ColumnDefinition.prototype.getAlias = function() { 29 | return this.alias; 30 | } 31 | 32 | ColumnDefinition.prototype.setDistinct = function(distinct) { 33 | this.distinct = distinct; 34 | } 35 | 36 | ColumnDefinition.prototype.isDistinct = function() { 37 | return this.distinct; 38 | } 39 | 40 | ColumnDefinition.prototype.getSQL = function() { 41 | var sql = this.name; 42 | 43 | if (this.alias && this.name != this.alias) { 44 | sql = sql + " AS " + this.alias; 45 | } 46 | 47 | return sql; 48 | } 49 | 50 | module.exports = ColumnDefinition; -------------------------------------------------------------------------------- /lib/definition/expression/conditionDefinition.js: -------------------------------------------------------------------------------- 1 | var Constant = require('../../util/constant'); 2 | var SqlUtil = require('../../util/sqlUtil'); 3 | 4 | var ConditionDefinition = function() { 5 | this.name = null; 6 | this.relate = null; 7 | this.values = null; 8 | } 9 | 10 | ConditionDefinition.prototype.setName = function(name) { 11 | this.name = name; 12 | } 13 | 14 | ConditionDefinition.prototype.getName = function() { 15 | return this.name; 16 | } 17 | 18 | ConditionDefinition.prototype.setRelate = function(relate) { 19 | this.relate = relate; 20 | } 21 | 22 | ConditionDefinition.prototype.getRelate = function() { 23 | return this.relate; 24 | } 25 | 26 | ConditionDefinition.prototype.setValues = function(values) { 27 | this.values = values; 28 | } 29 | 30 | ConditionDefinition.prototype.getValues = function() { 31 | return this.values; 32 | } 33 | 34 | ConditionDefinition.prototype.getSQL = function() { 35 | var sql = this.name; 36 | var relate = SqlUtil.getRelate(this.relate); 37 | 38 | if (relate === Constant.SELECT_CONDITION_NOT_NULL) { 39 | sql += (" is " + relate); 40 | return sql; 41 | } 42 | 43 | sql += (" " + relate + " "); 44 | 45 | sql += this.getSQLValue(relate); 46 | 47 | return sql; 48 | } 49 | 50 | ConditionDefinition.prototype.getSQLValue = function(relate) { 51 | var values = this.values; 52 | var sqlValue = ""; 53 | 54 | if (!values) { 55 | return sqlValue; 56 | } 57 | 58 | var len = values.length; 59 | 60 | if (relate === Constant.SELECT_CONDITION_IN || relate === Constant.SELECT_CONDITION_NOT_IN) { 61 | sqlValue += "("; 62 | 63 | for (var i = 0; i < len; i++) { 64 | var value = values[i][0]; 65 | sqlValue += this.getConditionValue(value); 66 | if (i < len - 1) { 67 | sqlValue += ","; 68 | } else { 69 | sqlValue += ")"; 70 | } 71 | } 72 | } else if (relate === Constant.SELECT_CONDITION_BETWEEN) { 73 | var from = values[0][0]; 74 | var to = values[1][0]; 75 | sqlValue += (this.getConditionValue(from) + " AND " + this.getConditionValue(to)); 76 | } else { 77 | len = values[0].length; 78 | for (var i = 0; i < len; i++) { 79 | var value = values[0][i]; 80 | if (i == len - 1) { 81 | sqlValue += " "; 82 | } 83 | sqlValue += this.getConditionValue(value); 84 | } 85 | } 86 | 87 | return sqlValue; 88 | } 89 | 90 | ConditionDefinition.prototype.getConditionValue = function(value) { 91 | var sql = ""; 92 | var text = value['text']; 93 | var type = value['type']; 94 | 95 | if (type === Constant.SELECT_CONDITION_VALUE_TYPE_STRING) { 96 | sql += ('\"' + text + '\"'); 97 | } else if (type === Constant.SELECT_CONDITION_VALUE_TYPE_KEYWORD || type === Constant.SELECT_CONDITION_VALUE_TYPE_OPERATOR) { 98 | sql += (' ' + text); 99 | } else { 100 | sql = text; 101 | } 102 | 103 | return sql; 104 | } 105 | 106 | module.exports = ConditionDefinition; -------------------------------------------------------------------------------- /lib/definition/expression/groupByDefinition.js: -------------------------------------------------------------------------------- 1 | var GroupByDefinition = function() { 2 | this.name = null; 3 | this.type = null; 4 | } 5 | 6 | GroupByDefinition.prototype.setName = function(name) { 7 | this.name = name; 8 | } 9 | 10 | GroupByDefinition.prototype.getName = function() { 11 | return this.name; 12 | } 13 | 14 | GroupByDefinition.prototype.setType = function(type) { 15 | this.type = type; 16 | } 17 | 18 | GroupByDefinition.prototype.getType = function() { 19 | return this.type; 20 | } 21 | 22 | GroupByDefinition.prototype.getSQL = function() { 23 | var sql = this.name; 24 | 25 | return sql; 26 | } 27 | 28 | module.exports = GroupByDefinition; -------------------------------------------------------------------------------- /lib/definition/expression/orderByDefinition.js: -------------------------------------------------------------------------------- 1 | var OrderByDefinition = function() { 2 | this.name = null; 3 | this.type = null; 4 | this.orderType = null; 5 | } 6 | 7 | OrderByDefinition.prototype.setName = function(name) { 8 | this.name = name; 9 | } 10 | 11 | OrderByDefinition.prototype.getName = function() { 12 | return this.name; 13 | } 14 | 15 | OrderByDefinition.prototype.setType = function(type) { 16 | this.type = type; 17 | } 18 | 19 | OrderByDefinition.prototype.getType = function() { 20 | return this.type; 21 | } 22 | 23 | OrderByDefinition.prototype.setOrderType = function(orderType) { 24 | this.orderType = orderType; 25 | } 26 | 27 | OrderByDefinition.prototype.getOrderType = function() { 28 | return this.orderType; 29 | } 30 | 31 | OrderByDefinition.prototype.getSQL = function() { 32 | var sql = this.name; 33 | 34 | return sql; 35 | } 36 | 37 | module.exports = OrderByDefinition; -------------------------------------------------------------------------------- /lib/definition/insertDefinition.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao InsertDefinition 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var SqlDefinition = require('./sqlDefinition'); 15 | var Util = require('util'); 16 | 17 | var InsertDefinition = function() { 18 | SqlDefinition.call(this); 19 | this.type = "insert"; 20 | } 21 | 22 | Util.inherits(InsertDefinition, SqlDefinition); 23 | 24 | module.exports = InsertDefinition; -------------------------------------------------------------------------------- /lib/definition/selectDefinition.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao SelectDefinition 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var ConditionDefinition = require('./expression/conditionDefinition'); 15 | var OrderByDefinition = require('./expression/orderByDefinition'); 16 | var GroupByDefinition = require('./expression/groupByDefinition'); 17 | var ColumnDefinition = require('./expression/columnDefinition'); 18 | var TableDefinition = require('./tableDefinition'); 19 | var SqlDefinition = require('./sqlDefinition'); 20 | var Constant = require('../util/constant'); 21 | var Util = require('util'); 22 | 23 | var SelectDefinition = function() { 24 | SqlDefinition.call(this); 25 | this.type = "select"; 26 | this.originalSQL = null; 27 | this.sql = null; 28 | this.tableList = []; 29 | this.columnList = []; 30 | this.conditionList = []; 31 | this.having = null; 32 | this.orderList = []; 33 | this.hasOriginalGroupBy = false; 34 | this.groupList = []; 35 | this.hasAggColumn = false; 36 | this.hasAggDistinct = false; 37 | this.aggDistinctIndex = -1; 38 | this.limit = null; 39 | this.offset = null; 40 | this.isForUpdate = false; 41 | this.multiDDBQuery = false; 42 | this.hasFromClause = false; 43 | this.fakeGroupbyIndex = -1; 44 | this.manualAddGroupByCount = 0; 45 | this.pushDownSorting = false; 46 | this.orderByAgg = false; 47 | this.needJoin = false; 48 | this.isDistinct = false; 49 | this.groupOrderList = []; 50 | this.selectRole = Constant.ROLE_MASTER; 51 | } 52 | 53 | Util.inherits(SelectDefinition, SqlDefinition); 54 | 55 | SelectDefinition.prototype.init = function() { 56 | var sqlMeta = this.sqlMeta; 57 | 58 | var meta = sqlMeta[0]; 59 | 60 | for (var key in meta) { 61 | var value = meta[key]; 62 | this.doInit(key, value); 63 | } 64 | } 65 | 66 | SelectDefinition.prototype.doInit = function(key, value) { 67 | if (key === Constant.SQL_SELECT_PART.COLUMN) { 68 | return this.doInitColumn(value); 69 | } 70 | 71 | if (key === Constant.SQL_SELECT_PART.SOURCE) { 72 | return this.doInitSource(value); 73 | } 74 | 75 | if (key === Constant.SQL_SELECT_PART.WHERE) { 76 | return this.doInitWhere(value); 77 | } 78 | 79 | if (key === Constant.SQL_SELECT_PART.LIMIT) { 80 | return this.doInitLimit(value); 81 | } 82 | 83 | if (key === Constant.SQL_SELECT_PART.ORDERBY) { 84 | return this.doInitOrderBy(value); 85 | } 86 | 87 | if (key === Constant.SQL_SELECT_PART.GROUPBY) { 88 | return this.doInitGroupBy(value); 89 | } 90 | } 91 | 92 | SelectDefinition.prototype.doInitColumn = function(column) { 93 | for (var columnKey in column) { 94 | var columnValue = column[columnKey]; 95 | 96 | this.addColumn(columnKey, columnValue) 97 | } 98 | } 99 | 100 | SelectDefinition.prototype.doInitSource = function(source) { 101 | this.hasFromClause = true; 102 | for (var sourceKey in source) { 103 | var sourceValue = source[sourceKey]; 104 | var sourceType = sourceValue['type']; 105 | var sourceTable = sourceValue['source']; 106 | this.addTable(sourceKey, sourceTable, sourceType); 107 | } 108 | } 109 | 110 | SelectDefinition.prototype.doInitWhere = function(where) { 111 | for (var i = 0; i < where.length; i++) { 112 | var whereItem = where[i]; 113 | this.addWhere(whereItem); 114 | } 115 | } 116 | 117 | SelectDefinition.prototype.doInitLimit = function(limits) { 118 | if (limits.length <= 0) { 119 | return; 120 | } 121 | 122 | var offset = 0; 123 | var limit = 0; 124 | if (limits.length == 1) { 125 | limit = limits[0]['text']; 126 | } else if (limits.length > 1) { 127 | offset = limits[0]['text']; 128 | limit = limits[1]['text']; 129 | } 130 | 131 | this.offset = offset; 132 | this.limit = limit; 133 | } 134 | 135 | SelectDefinition.prototype.doInitOrderBy = function(orders) { 136 | for (var i = 0; i < orders.length; i++) { 137 | var orderItem = orders[i]; 138 | this.addOrder(orderItem); 139 | } 140 | } 141 | 142 | SelectDefinition.prototype.doInitGroupBy = function(groups) { 143 | for (var i = 0; i < groups.length; i++) { 144 | var groupItem = groups[i]; 145 | this.addGroup(groupItem); 146 | } 147 | } 148 | 149 | SelectDefinition.prototype.setDistinct = function(isDistinct) { 150 | this.isDistinct = isDistinct; 151 | } 152 | 153 | SelectDefinition.prototype.checkDistinct = function() { 154 | return this.isDistinct; 155 | } 156 | 157 | SelectDefinition.prototype.addTable = function(alias, table, type) { 158 | var tableDefinition = new TableDefinition(); 159 | tableDefinition.setName(table); 160 | tableDefinition.setType(type); 161 | tableDefinition.setAlias(alias); 162 | this.tableList.push(tableDefinition); 163 | } 164 | 165 | SelectDefinition.prototype.addColumn = function(columnKey, columnValue) { 166 | var distinct = columnValue['dist']; 167 | var expression = columnValue['expr']; 168 | 169 | var columnDefinition = new ColumnDefinition(); 170 | var columnName = expression[0]['text']; 171 | var columnType = expression[0]['type']; 172 | 173 | if (columnType === Constant.LEXTER_TYPE_NUMBER) { 174 | columnName = parseInt(columnName); 175 | } 176 | 177 | columnDefinition.setType(columnType); 178 | columnDefinition.setName(columnName); 179 | columnDefinition.setAlias(columnKey); 180 | 181 | if (distinct) { 182 | this.setDistinct(true); 183 | } 184 | 185 | this.columnList.push(columnDefinition); 186 | } 187 | 188 | SelectDefinition.prototype.addWhere = function(where) { 189 | var column = where['column']; 190 | var columnName = column['text']; 191 | var columnType = column['type']; 192 | 193 | var relate = where['relate']; 194 | var values = where['values']; 195 | 196 | var conditionDefinition = new ConditionDefinition(); 197 | conditionDefinition.setName(columnName); 198 | conditionDefinition.setRelate(relate); 199 | conditionDefinition.setValues(values); 200 | 201 | this.conditionList.push(conditionDefinition); 202 | } 203 | 204 | SelectDefinition.prototype.addOrder = function(order) { 205 | var orderType = order['type']; 206 | var value = order['expr'][0]; 207 | var name = value['text']; 208 | var type = value['type']; 209 | 210 | var orderByDefinition = new OrderByDefinition(); 211 | orderByDefinition.setName(name); 212 | orderByDefinition.setType(type); 213 | orderByDefinition.setOrderType(orderType); 214 | 215 | this.orderList.push(orderByDefinition); 216 | } 217 | 218 | SelectDefinition.prototype.addGroup = function(group) { 219 | var groupByDefinition = new GroupByDefinition(); 220 | var name = group[0]['text']; 221 | var type = group[0]['type']; 222 | groupByDefinition.setName(name); 223 | groupByDefinition.setType(type); 224 | 225 | this.groupList.push(groupByDefinition); 226 | } 227 | 228 | SelectDefinition.prototype.getLimit = function() { 229 | return this.limit; 230 | } 231 | 232 | SelectDefinition.prototype.getOffset = function() { 233 | return this.offset; 234 | } 235 | 236 | SelectDefinition.prototype.isOrderByAgg = function() { 237 | return this.orderByAgg; 238 | } 239 | 240 | SelectDefinition.prototype.getOrderList = function() { 241 | return this.orderList; 242 | } 243 | 244 | SelectDefinition.prototype.getGroupList = function() { 245 | return this.groupList; 246 | } 247 | 248 | SelectDefinition.prototype.getColumns = function() { 249 | return this.columnList; 250 | } 251 | 252 | SelectDefinition.prototype.isJoinNeeded = function() { 253 | return this.needJoin; 254 | } 255 | 256 | SelectDefinition.prototype.groupContainsBalanceField = function() { 257 | 258 | } 259 | 260 | SelectDefinition.prototype.getTableList = function() { 261 | return this.tableList; 262 | } 263 | 264 | SelectDefinition.prototype.getConditionList = function() { 265 | return this.conditionList; 266 | } 267 | 268 | SelectDefinition.prototype.setSelectRole = function(selectRole) { 269 | this.selectRole = selectRole; 270 | } 271 | 272 | SelectDefinition.prototype.getSelectRole = function() { 273 | return this.selectRole; 274 | } 275 | 276 | SelectDefinition.prototype.setOriginalSQL = function(originalSQL) { 277 | this.originalSQL = originalSQL; 278 | } 279 | 280 | SelectDefinition.prototype.getOriginalSQL = function() { 281 | return this.originalSQL; 282 | } 283 | 284 | SelectDefinition.prototype.getSQL = function() { 285 | if (!this.sql) { 286 | this.sql = this.buildSQL(); 287 | } 288 | 289 | return this.sql; 290 | } 291 | 292 | SelectDefinition.prototype.buildSQL = function() { 293 | var sql = "SELECT "; 294 | 295 | var columnList = this.columnList; 296 | 297 | for (var i = 0; i < columnList.length; i++) { 298 | var column = columnList[i]; 299 | if (i > 0) { 300 | sql += ", "; 301 | } 302 | 303 | sql += column.getSQL(); 304 | } 305 | 306 | if (!this.hasFromClause) { 307 | return sql; 308 | } 309 | 310 | sql += " FROM "; 311 | 312 | var tableList = this.tableList; 313 | 314 | for (var i = 0; i < tableList.length; i++) { 315 | var table = tableList[i]; 316 | if (i > 0) { 317 | sql += ", "; 318 | } 319 | 320 | sql += table.getSQL(); 321 | } 322 | 323 | var conditionList = this.conditionList; 324 | 325 | if (conditionList.length) { 326 | sql += " WHERE "; 327 | } 328 | 329 | for (var i = 0; i < conditionList.length; i++) { 330 | var condition = conditionList[i]; 331 | sql += condition.getSQL(); 332 | if (i < conditionList.length - 1) { 333 | sql += " AND "; 334 | } 335 | } 336 | 337 | var groupList = this.groupList; 338 | 339 | if (groupList.length) { 340 | sql += " GROUP BY " 341 | } 342 | 343 | for (var i = 0; i < groupList.length; i++) { 344 | var group = groupList[i]; 345 | sql += group.getSQL(); 346 | 347 | if (i < groupList.length - 1) { 348 | sql += " , "; 349 | } 350 | } 351 | 352 | return sql; 353 | } 354 | 355 | module.exports = SelectDefinition; -------------------------------------------------------------------------------- /lib/definition/sqlDefinition.js: -------------------------------------------------------------------------------- 1 | var SqlDefinition = function() { 2 | this.type = "sql"; 3 | this.sqlMeta = null; 4 | } 5 | 6 | SqlDefinition.prototype.setSQLMeta = function(sqlMeta) { 7 | this.sqlMeta = sqlMeta; 8 | } 9 | 10 | SqlDefinition.prototype.getType = function() { 11 | return this.type; 12 | } 13 | 14 | module.exports = SqlDefinition; -------------------------------------------------------------------------------- /lib/definition/tableDefinition.js: -------------------------------------------------------------------------------- 1 | var TableDefinition = function() { 2 | this.name = null; 3 | this.type = null; 4 | this.alias = null; 5 | } 6 | 7 | TableDefinition.prototype.setName = function(name) { 8 | this.name = name; 9 | } 10 | 11 | TableDefinition.prototype.getName = function() { 12 | return this.name; 13 | } 14 | 15 | TableDefinition.prototype.setType = function(type) { 16 | this.type = type; 17 | } 18 | 19 | TableDefinition.prototype.getType = function() { 20 | return this.type; 21 | } 22 | 23 | TableDefinition.prototype.setAlias = function(alias) { 24 | this.alias = alias; 25 | } 26 | 27 | TableDefinition.prototype.getAlias = function() { 28 | return this.alias; 29 | } 30 | 31 | TableDefinition.prototype.getSQL = function() { 32 | var sql = this.name; 33 | 34 | if (this.alias && this.name != this.alias) { 35 | sql = sql + " AS " + this.alias; 36 | } 37 | 38 | return sql; 39 | } 40 | 41 | module.exports = TableDefinition; -------------------------------------------------------------------------------- /lib/definition/updateDefinition.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao UpdateDefinition 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var SqlDefinition = require('./sqlDefinition'); 15 | var Util = require('util'); 16 | 17 | var UpdateDefinition = function() { 18 | SqlDefinition.call(this); 19 | this.type = "update"; 20 | } 21 | 22 | Util.inherits(UpdateDefinition, SqlDefinition); 23 | 24 | module.exports = UpdateDefinition; -------------------------------------------------------------------------------- /lib/loader/sqlLoader.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao SqlLoader 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'SqlLoader'); 15 | var Constant = require('../util/constant'); 16 | var FileUtil = require('../util/fileUtil'); 17 | var Utils = require('../util/utils'); 18 | 19 | var SqlLoader = function() { 20 | this.idMap = {}; 21 | this.idResultMap = {}; 22 | } 23 | 24 | SqlLoader.prototype.getSQL = function(sqlId) { 25 | if (!Utils.isNotNull(sqlId)) { 26 | logger.error('getSQL error sqlId must not be null'); 27 | return; 28 | } 29 | 30 | var resultSql = this.idResultMap[sqlId]; 31 | if (!resultSql) { 32 | resultSql = this.doGetSQL(sqlId); 33 | } 34 | 35 | return resultSql; 36 | } 37 | 38 | SqlLoader.prototype.doGetSQL = function(sqlId) { 39 | var originSql = this.idMap[sqlId]; 40 | 41 | if (!originSql) { 42 | logger.warn('get sql warn, no such sql %s exists', sqlId); 43 | return; 44 | } 45 | 46 | var refs = originSql.match(Constant.SQL_REF); 47 | 48 | if (!refs) { 49 | return originSql; 50 | } 51 | 52 | var resultSql = originSql; 53 | for (var i = 0; i < refs.length; i++) { 54 | var refSql = refs[i]; 55 | var refSqlId = refSql.match(Constant.SQL_REF_ID); 56 | if (!refSqlId) { 57 | continue; 58 | } 59 | 60 | refSqlId = refSqlId[1]; 61 | var refSqlContent = this.getSQL(refSqlId); 62 | if (refSqlContent) { 63 | resultSql = resultSql.replace(refSql, refSqlContent); 64 | } 65 | } 66 | 67 | this.updateSqlResultMap(sqlId, resultSql); 68 | return resultSql; 69 | } 70 | 71 | SqlLoader.prototype.load = function(locations) { 72 | for (var i = 0; i < locations.length; i++) { 73 | this.loadPath(locations[i]); 74 | } 75 | } 76 | 77 | SqlLoader.prototype.loadPath = function(location) { 78 | var files = []; 79 | FileUtil.readDirFiles(location, files); 80 | 81 | for (var i = 0; i < files.length; i++) { 82 | this.loadFile(files[i]); 83 | } 84 | } 85 | 86 | SqlLoader.prototype.loadFile = function(path) { 87 | if (!FileUtil.checkFileType(path, Constant.FILE_TYPE_SQL)) { 88 | return; 89 | } 90 | 91 | var content = FileUtil.readFileSync(path); 92 | this.loadContent(content); 93 | } 94 | 95 | SqlLoader.prototype.loadContent = function(content) { 96 | if (!content) { 97 | return; 98 | } 99 | 100 | // remove comments 101 | content = content.replace(Constant.COMMENT_LINE_1, "") 102 | content = content.replace(Constant.COMMENT_LINE_2, ""); 103 | content = content.replace(Constant.COMMENT_STAR, ""); 104 | 105 | content = content.trim(); 106 | 107 | var blocks = content.match(Constant.CONTENT_BLOCK); 108 | 109 | if (!blocks) { 110 | return; 111 | } 112 | 113 | for (var i = 0; i < blocks.length; i++) { 114 | var blockContent = blocks[i]; 115 | var sqlM = blockContent.match(Constant.CONTENT_BLOCK_SQL); 116 | if (!sqlM) { 117 | continue; 118 | } 119 | 120 | var sqlId = sqlM[1]; 121 | var sqlContent = sqlM[2]; 122 | this.updateSqlMap(sqlId, sqlContent); 123 | } 124 | 125 | this.prcessSQLPlaceHolder(); 126 | } 127 | 128 | SqlLoader.prototype.updateSqlMap = function(id, content) { 129 | content = content.replace(Constant.CONTENT_SQL_TRIM, " "); 130 | 131 | this.idMap[id] = content; 132 | } 133 | 134 | SqlLoader.prototype.updateSqlResultMap = function(id, content) { 135 | this.idResultMap[id] = content; 136 | } 137 | 138 | SqlLoader.prototype.getSqlMap = function() { 139 | return this.idMap; 140 | } 141 | 142 | SqlLoader.prototype.prcessSQLPlaceHolder = function() { 143 | var sqlMap = this.getSqlMap(); 144 | 145 | for (var id in sqlMap) { 146 | this.getSQL(id); 147 | } 148 | } 149 | 150 | module.exports = SqlLoader; -------------------------------------------------------------------------------- /lib/parser/sqlParser.js: -------------------------------------------------------------------------------- 1 | var SQLParser = function() { 2 | 3 | } 4 | 5 | SQLParser.prototype.format = function(sql, params) { 6 | 7 | } 8 | 9 | module.exports = SQLParser; -------------------------------------------------------------------------------- /lib/plan/performers/directPlanPerformer.js: -------------------------------------------------------------------------------- 1 | var DirectPlanPerformer = function() {} 2 | 3 | DirectPlanPerformer.prototype.executeQuery = function(directPlan, cb) { 4 | directPlan.start(cb); 5 | } 6 | 7 | module.exports = DirectPlanPerformer; -------------------------------------------------------------------------------- /lib/plan/performers/queryPlanPerformer.js: -------------------------------------------------------------------------------- 1 | var QueryPlanPerformer = function() {} 2 | 3 | QueryPlanPerformer.prototype.executeQuery = function(queryPlan, cb) { 4 | queryPlan.start(cb); 5 | } 6 | 7 | module.exports = QueryPlanPerformer; -------------------------------------------------------------------------------- /lib/plan/performers/updatePlanPerformer.js: -------------------------------------------------------------------------------- 1 | var UpdatePlanPerformer = function() { 2 | this.connectionManager = null; 3 | } 4 | 5 | UpdatePlanPerformer.prototype.setConnectionManager = function(connectionManager) { 6 | this.connectionManager = connectionManager; 7 | } 8 | 9 | 10 | module.exports = UpdatePlanPerformer; -------------------------------------------------------------------------------- /lib/plan/planHelper.js: -------------------------------------------------------------------------------- 1 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'PlanHelper'); 2 | var ShardingUtil = require('../util/shardingUtil'); 3 | var Constant = require('../util/constant'); 4 | var SqlUtil = require('../util/sqlUtil'); 5 | var Utils = require('../util/utils'); 6 | 7 | var shardingUtil = ShardingUtil("mysql"); 8 | // shardingUtil['shardingFile'] = Constant.MYSQL_CLUSTER_MAP_PATH; 9 | 10 | var PlanHelper = { 11 | cacheDBMap: {} 12 | } 13 | 14 | PlanHelper.getDestDB = function(selectDefinition) { 15 | if (selectDefinition == Constant.DEST_DB_ALL) { 16 | return shardingUtil.getDestDBAll(); 17 | } 18 | 19 | var destDB = this.getDestDBFromCache(selectDefinition); 20 | if (destDB) { 21 | return destDB; 22 | } 23 | 24 | destDB = []; 25 | 26 | var tableList = selectDefinition.getTableList(); 27 | var bearcat = Utils.getBearcat(); 28 | var beanFactory = bearcat.getBeanFactory(); 29 | var balanceTableMap = {}; 30 | 31 | for (var i = 0; i < tableList.length; i++) { 32 | var table = tableList[i]; 33 | var tableName = table.getName(); 34 | 35 | var modelDefinition = beanFactory.getModelDefinitionByTable(tableName); 36 | if (!modelDefinition) { 37 | continue; 38 | } 39 | 40 | var balance = modelDefinition.getBalance(); 41 | if (!balance) { 42 | continue; 43 | } 44 | 45 | balanceTableMap[balance] = modelDefinition; 46 | } 47 | 48 | var conditionList = selectDefinition.getConditionList(); 49 | 50 | var hasTargetDB = false; 51 | 52 | for (var i = 0; i < conditionList.length; i++) { 53 | var condition = conditionList[i]; 54 | var conditionName = condition.getName(); 55 | var conditionRelate = condition.getRelate(); 56 | var conditionValues = condition.getValues(); 57 | 58 | // balance condition 59 | if (SqlUtil.getRelate(conditionRelate) != Constant.SELECT_CONDITION_EQUAL) { 60 | continue; 61 | } 62 | 63 | if (!conditionValues) { 64 | continue; 65 | } 66 | 67 | if (conditionValues[0].length > 1) { 68 | continue; 69 | } 70 | 71 | var conditionValue = conditionValues[0][0]['text']; 72 | var tableModelDefinition = balanceTableMap[conditionName]; 73 | 74 | if (!tableModelDefinition) { 75 | continue; 76 | } 77 | 78 | var tableName = tableModelDefinition.getTable(); 79 | 80 | // balance equal condition 81 | var db = this.calDestDB(tableName, conditionName, conditionValue); 82 | destDB.push(db); 83 | hasTargetDB = true; 84 | } 85 | 86 | if (!hasTargetDB) { 87 | destDB = shardingUtil.getDestDBAll(); 88 | } 89 | 90 | this.setDestDBCache(selectDefinition, destDB); 91 | return destDB; 92 | } 93 | 94 | PlanHelper.calDestDB = function(table, field, value) { 95 | var key = table + field + value; 96 | var clusterMap = shardingUtil.getClusterMap(); 97 | if (!clusterMap) { 98 | return; 99 | } 100 | 101 | var hashValue = Utils.calHashValue(key, clusterMap.length); 102 | var target = clusterMap[hashValue]; 103 | 104 | // logger.debug('calDestDB hashValue %d target %j', hashValue, target); 105 | if (target && target['name']) { 106 | return target['name']; 107 | } 108 | } 109 | 110 | PlanHelper.calDestDBs = function(table, field, values) { 111 | if (!Utils.checkArray(values)) { 112 | return [this.calDestDB(table, field, values)]; 113 | } 114 | 115 | var dbs = []; 116 | 117 | for (var i = 0; i < values.length; i++) { 118 | dbs.push(this.calDestDB(table, field, values[i])); 119 | } 120 | 121 | return dbs; 122 | } 123 | 124 | PlanHelper.getDestDBFromCache = function(selectDefinition) { 125 | var originalSQL = selectDefinition.getOriginalSQL(); 126 | 127 | return this.cacheDBMap[originalSQL]; 128 | } 129 | 130 | PlanHelper.setDestDBCache = function(selectDefinition, destDB) { 131 | var originalSQL = selectDefinition.getOriginalSQL(); 132 | 133 | this.cacheDBMap[originalSQL] = destDB; 134 | } 135 | 136 | PlanHelper.getDestDBAll = shardingUtil.getDestDBAll.bind(shardingUtil); 137 | 138 | module.exports = PlanHelper; -------------------------------------------------------------------------------- /lib/plan/planMaker.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao PlanMaker 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var QueryPlanFactory = require('./queryPlanFactory'); 15 | var Constant = require('../util/constant'); 16 | 17 | var PlanMaker = function() { 18 | this.queryPlanFactory = new QueryPlanFactory(); 19 | } 20 | 21 | PlanMaker.prototype.makePlan = function(sqlDefinition, connectionManager) { 22 | var sqlType = sqlDefinition.getType(); 23 | 24 | if (sqlType === Constant.PLAN_QUERY) { 25 | return this.makeSelectPlan(sqlDefinition, connectionManager); 26 | } else { 27 | return this.makeUpdatePlan(sqlDefinition); 28 | } 29 | } 30 | 31 | PlanMaker.prototype.makeSelectPlan = function(selectDefinition, connectionManager) { 32 | return this.queryPlanFactory.buildQueryPlan(selectDefinition, connectionManager); 33 | } 34 | 35 | PlanMaker.prototype.makeUpdatePlan = function(updateDefinition, connectionManager) { 36 | return this.queryPlanFactory.buildUpdatePlan(updateDefinition, connectionManager); 37 | } 38 | 39 | PlanMaker.prototype.makeDirectPlan = function(sql, params, options, connectionManager) { 40 | return this.queryPlanFactory.buildDirectPlan(sql, params, options, connectionManager); 41 | } 42 | 43 | PlanMaker.prototype.optimizeQueryPlan = function() { 44 | 45 | } 46 | 47 | module.exports = PlanMaker; -------------------------------------------------------------------------------- /lib/plan/planManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao PlanManager 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'PlanManager'); 15 | var UpdatePlanPerformer = require('./performers/updatePlanPerformer'); 16 | var DirectPlanPerformer = require('./performers/directPlanPerformer'); 17 | var QueryPlanPerformer = require('./performers/queryPlanPerformer'); 18 | var Constant = require('../util/constant'); 19 | var SqlUtil = require('../util/sqlUtil'); 20 | var PlanMaker = require('./planMaker'); 21 | 22 | /** 23 | * PlanManager constructor function. 24 | * 25 | * @api public 26 | */ 27 | var PlanManager = function() { 28 | this.planMaker = null; 29 | this.connectionManager = null; 30 | this.queryPlanPerformer = null; 31 | this.updatePlanPerformer = null; 32 | this.directPlanPerformer = null; 33 | } 34 | 35 | PlanManager.prototype.directQuery = function(sql, params, options, cb) { 36 | var planMaker = this.getPlanMaker(); 37 | var planPerformer = this.getDirectPlanPerformer(); 38 | var connectionManager = this.connectionManager; 39 | 40 | var directPlan = planMaker.makeDirectPlan(sql, params, options, connectionManager); 41 | planPerformer.executeQuery(directPlan, cb); 42 | } 43 | 44 | PlanManager.prototype.executeQuery = function(sql, params, cb) { 45 | return this.parseAndMakePlan(sql, params, cb); 46 | } 47 | 48 | PlanManager.prototype.parseAndMakePlan = function(sql, params, cb) { 49 | var planMaker = this.getPlanMaker(); 50 | var execSQL = SqlUtil.format(sql, params); 51 | var parsedSQL = SqlUtil.parse(execSQL); 52 | 53 | var sqlType = parsedSQL['type']; 54 | var sqlResult = parsedSQL['result']; 55 | 56 | // logger.debug("parseAndMakePlan %j", parsedSQL); 57 | if (!sqlType) { 58 | return; 59 | } 60 | 61 | var SqlDefinition = require('../definition/' + sqlType + 'Definition'); 62 | var sqlDefinition = new SqlDefinition(); 63 | sqlDefinition.setOriginalSQL(execSQL); 64 | sqlDefinition.setSQLMeta(sqlResult); 65 | sqlDefinition.init(); 66 | 67 | var planPerformer = null; 68 | var connectionManager = this.connectionManager; 69 | var queryPlan = planMaker.makePlan(sqlDefinition, connectionManager); 70 | if (sqlType === Constant.PLAN_QUERY) { 71 | planPerformer = this.getQueryPlanPerformer(); 72 | return planPerformer.executeQuery(queryPlan, cb); 73 | } else { 74 | planPerformer = this.getUpdatePlanPerformer(); 75 | return planPerformer.executeUpdate(queryPlan, cb); 76 | } 77 | } 78 | 79 | PlanManager.prototype.getPlanMaker = function() { 80 | if (!this.planMaker) { 81 | this.planMaker = new PlanMaker(); 82 | } 83 | 84 | return this.planMaker; 85 | } 86 | 87 | PlanManager.prototype.getQueryPlanPerformer = function() { 88 | if (!this.queryPlanPerformer) { 89 | this.queryPlanPerformer = new QueryPlanPerformer(); 90 | } 91 | 92 | return this.queryPlanPerformer; 93 | } 94 | 95 | PlanManager.prototype.getUpdatePlanPerformer = function() { 96 | if (!this.updatePlanPerformer) { 97 | this.updatePlanPerformer = new UpdatePlanPerformer(); 98 | } 99 | 100 | return this.updatePlanPerformer; 101 | } 102 | 103 | PlanManager.prototype.getDirectPlanPerformer = function() { 104 | if (!this.directPlanPerformer) { 105 | this.directPlanPerformer = new DirectPlanPerformer(); 106 | } 107 | 108 | return this.directPlanPerformer; 109 | } 110 | 111 | module.exports = PlanManager; -------------------------------------------------------------------------------- /lib/plan/plans/aggregatePlan.js: -------------------------------------------------------------------------------- 1 | var QueryPlan = require('./queryPlan'); 2 | var Util = require('util'); 3 | 4 | var AggregatePlan = function() { 5 | QueryPlan.call(this); 6 | } 7 | 8 | Util.inherits(AggregatePlan, QueryPlan); 9 | 10 | AggregatePlan.prototype.start = function(cb) { 11 | var childPlan = this.getChildPlan(); 12 | 13 | childPlan.start(function(err, results) { 14 | if (err) { 15 | return cb(err); 16 | } 17 | 18 | cb(null, results); 19 | }); 20 | } 21 | 22 | module.exports = AggregatePlan; -------------------------------------------------------------------------------- /lib/plan/plans/directPlan.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DirectPlan 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'DirectPlan'); 15 | var Constant = require('../../util/constant'); 16 | var PlanHelper = require('../planHelper'); 17 | var QueryPlan = require('./queryPlan'); 18 | var async = require('async'); 19 | var Util = require('util'); 20 | 21 | var DirectPlan = function(sql, params, options, connectionManager) { 22 | QueryPlan.call(this); 23 | this.sql = sql; 24 | this.params = params || []; 25 | this.options = options || {}; 26 | this.connectionManager = connectionManager; 27 | } 28 | 29 | Util.inherits(DirectPlan, QueryPlan); 30 | 31 | DirectPlan.prototype.start = function(cb) { 32 | var sql = this.sql; 33 | var params = this.params; 34 | var options = this.options; 35 | var queryTimeout = options.timeout; 36 | var destDB = options.destDB || Constant.DEST_DB_ALL; 37 | var connectionManager = this.connectionManager; 38 | 39 | var self = this; 40 | 41 | var role = options.role || Constant.ROLE_MASTER; 42 | 43 | if (destDB == Constant.DEST_DB_ALL) { 44 | destDB = PlanHelper.getDestDB(destDB); 45 | } 46 | 47 | logger.debug('sql %s query options %j destDB %j', sql, options, destDB); 48 | 49 | var result = []; 50 | 51 | async.each(destDB, function(destNode, next) { 52 | connectionManager.getConnection(destNode, role, function(err, connection) { 53 | if (err) { 54 | return next(err); 55 | } 56 | 57 | var timerId = null; 58 | var timeoutFlag = false; 59 | if (queryTimeout) { 60 | timerId = setTimeout(function() { 61 | next(); 62 | timeoutFlag = true; 63 | logger.error('query sql %s %j timeout', sql, params); 64 | }, queryTimeout); 65 | } 66 | 67 | var query = connection.query(sql, params, function(err, results) { 68 | connectionManager.release(connection); 69 | if (timeoutFlag) { 70 | return; 71 | } 72 | 73 | clearTimeout(timerId); 74 | if (err) { 75 | return next(err); 76 | } 77 | 78 | result = result.concat(results); 79 | next(); 80 | }); 81 | 82 | self.print(query.sql); 83 | }); 84 | 85 | }, function(err) { 86 | cb(err, result); 87 | }); 88 | } 89 | 90 | DirectPlan.prototype.print = function(sql) { 91 | if (process.env.BEARCAT_DEBUG) { 92 | logger.debug(sql); 93 | } 94 | } 95 | 96 | module.exports = DirectPlan; -------------------------------------------------------------------------------- /lib/plan/plans/groupByPlan.js: -------------------------------------------------------------------------------- 1 | var QueryPlan = require('./queryPlan'); 2 | var Util = require('util'); 3 | 4 | var GroupByPlan = function(selectDefinition) { 5 | QueryPlan.call(this); 6 | this.oldColumns = []; 7 | this.groupByColumns = []; 8 | this.init(selectDefinition); 9 | } 10 | 11 | Util.inherits(GroupByPlan, QueryPlan); 12 | 13 | GroupByPlan.prototype.init = function(selectDefinition) { 14 | var groupByColumns = selectDefinition.getGroupList(); 15 | var columnList = selectDefinition.getColumns(); 16 | 17 | for (var i = 0; i < groupByColumns.length; i++) { 18 | var groupColumn = groupByColumns[i]; 19 | 20 | if (this.containsColumn(columnList, groupColumn)) { 21 | continue; 22 | } 23 | 24 | this.addOldColumns(columnList); 25 | 26 | columnList.push(groupColumn); // add groupByColumn to select column list 27 | } 28 | 29 | this.groupByColumns = groupByColumns; 30 | } 31 | 32 | GroupByPlan.prototype.containsColumn = function(columns, groupColumn) { 33 | for (var i = 0; i < columns.length; i++) { 34 | var column = columns[i]; 35 | var groupColumnName = groupColumn.getName(); 36 | if (column.getName() === groupColumnName || column.getAlias() === groupColumnName) { 37 | return true; 38 | } 39 | } 40 | 41 | return false; 42 | } 43 | 44 | GroupByPlan.prototype.addOldColumns = function(oldColumns) { 45 | if (!this.oldColumns) { 46 | this.oldColumns = oldColumns; 47 | } 48 | } 49 | 50 | GroupByPlan.prototype.start = function(cb) { 51 | var childPlan = this.getChildPlan(); 52 | 53 | var groupByColumns = this.groupByColumns; 54 | var groupByMap = {}; 55 | 56 | childPlan.start(function(err, results) { 57 | if (err) { 58 | return cb(err); 59 | } 60 | 61 | var r = []; 62 | 63 | for (var i = 0; i < results.length; i++) { 64 | var result = results[i]; 65 | 66 | var flag = true; 67 | for (var j = 0; j < groupByColumns.length; j++) { 68 | var groupColumn = groupByColumns[j]; 69 | var groupName = groupColumn.getName(); 70 | var resultValue = result[groupName]; 71 | 72 | if (!resultValue) { 73 | continue; 74 | } 75 | 76 | if (!groupByMap[groupName]) { 77 | groupByMap[groupName] = {}; 78 | } 79 | 80 | if (!groupByMap[groupName][resultValue]) { 81 | groupByMap[groupName][resultValue] = true; 82 | } else { 83 | flag = false; 84 | break; 85 | } 86 | } 87 | 88 | if (flag) { 89 | r.push(result); 90 | } 91 | } 92 | 93 | cb(null, r); 94 | }); 95 | } 96 | 97 | module.exports = GroupByPlan; -------------------------------------------------------------------------------- /lib/plan/plans/havingPlan.js: -------------------------------------------------------------------------------- 1 | var QueryPlan = require('./queryPlan'); 2 | var Util = require('util'); 3 | 4 | var HavingPlan = function() { 5 | QueryPlan.call(this); 6 | } 7 | 8 | Util.inherits(HavingPlan, QueryPlan); 9 | 10 | HavingPlan.prototype.start = function(cb) { 11 | var childPlan = this.getChildPlan(); 12 | 13 | childPlan.start(function(err, results) { 14 | if (err) { 15 | return cb(err); 16 | } 17 | 18 | cb(null, results); 19 | }); 20 | } 21 | 22 | module.exports = HavingPlan; -------------------------------------------------------------------------------- /lib/plan/plans/limitPlan.js: -------------------------------------------------------------------------------- 1 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'LimitPlan'); 2 | var Utils = require('../../util/utils'); 3 | var QueryPlan = require('./queryPlan'); 4 | var Util = require('util'); 5 | 6 | var LimitPlan = function(selectDefinition) { 7 | QueryPlan.call(this); 8 | this.limit = selectDefinition.getLimit(); 9 | this.offset = selectDefinition.getOffset(); 10 | this.orderByAgg = selectDefinition.isOrderByAgg(); 11 | } 12 | 13 | Util.inherits(LimitPlan, QueryPlan); 14 | 15 | LimitPlan.prototype.start = function(cb) { 16 | var offset = this.offset; 17 | var limit = this.limit; 18 | 19 | var childPlan = this.getChildPlan(); 20 | childPlan.start(function(err, results) { 21 | if (err) { 22 | return cb(err); 23 | } 24 | 25 | if (!Utils.isNotNull(offset)) { 26 | return cb(null, results); 27 | } 28 | 29 | var r = []; 30 | var len = results.length; 31 | var end = len; 32 | if (Utils.isNotNull(limit)) { 33 | end = offset + limit; 34 | } 35 | 36 | if (end > len) { 37 | end = len; 38 | } 39 | 40 | logger.debug('start %d %d', offset, end); 41 | for (var i = offset; i < end; i++) { 42 | r.push(results[i]); 43 | } 44 | 45 | cb(null, r); 46 | }); 47 | } 48 | 49 | LimitPlan.prototype.disableCurrentNode = function() { 50 | var queryPlanPerformer = this.getQueryPlanPerformer(); 51 | 52 | if (queryPlanPerformer.isSingleNode() && !queryPlanPerformer.hasJoin() && !this.orderByAgg) { 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | module.exports = LimitPlan; -------------------------------------------------------------------------------- /lib/plan/plans/orderByPlan.js: -------------------------------------------------------------------------------- 1 | var Constant = require('../../util/constant'); 2 | var QueryPlan = require('./queryPlan'); 3 | var Util = require('util'); 4 | 5 | var OrderByPlan = function(selectDefinition) { 6 | QueryPlan.call(this); 7 | this.oldColumns = []; 8 | this.orderByColumns = []; 9 | this.init(selectDefinition); 10 | } 11 | 12 | Util.inherits(OrderByPlan, QueryPlan); 13 | 14 | OrderByPlan.prototype.init = function(selectDefinition) { 15 | var orderByColumns = selectDefinition.getOrderList(); 16 | var columnList = selectDefinition.getColumns(); 17 | 18 | for (var i = 0; i < orderByColumns.length; i++) { 19 | var orderColumn = orderByColumns[i]; 20 | 21 | if (this.containsColumn(columnList, orderColumn)) { 22 | continue; 23 | } 24 | 25 | this.addOldColumns(columnList); 26 | 27 | columnList.push(orderColumn); // add orderByColumn to select column list 28 | } 29 | 30 | this.orderByColumns = orderByColumns; 31 | } 32 | 33 | OrderByPlan.prototype.containsColumn = function(columns, orderColumn) { 34 | for (var i = 0; i < columns.length; i++) { 35 | var column = columns[i]; 36 | var orderColumnName = orderColumn.getName(); 37 | if (column.getName() === orderColumnName || column.getAlias() === orderColumnName) { 38 | return true; 39 | } 40 | } 41 | 42 | return false; 43 | } 44 | 45 | OrderByPlan.prototype.addOldColumns = function(oldColumns) { 46 | if (!this.oldColumns) { 47 | this.oldColumns = oldColumns; 48 | } 49 | } 50 | 51 | OrderByPlan.prototype.start = function(cb) { 52 | var childPlan = this.getChildPlan(); 53 | var orderByColumns = this.orderByColumns; 54 | 55 | var cmp = function(a, b) { 56 | for (var i = 0; i < orderByColumns.length; i++) { 57 | var orderColumn = orderByColumns[i]; 58 | var name = orderColumn.getName(); 59 | var type = orderColumn.getType(); 60 | var orderType = orderColumn.getOrderType(); 61 | 62 | if (a[name] && b[name]) { 63 | if (a[name] == b[name]) { 64 | continue; 65 | } 66 | 67 | if (orderType === Constant.ORDER_ASC) { 68 | return a[name] < b[name] ? -1 : 1; 69 | } 70 | 71 | if (orderType === Constant.ORDER_DESC) { 72 | return a[name] < b[name] ? 1 : -1; 73 | } 74 | 75 | } 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | childPlan.start(function(err, results) { 82 | if (err) { 83 | return cb(err); 84 | } 85 | 86 | // sort by orderColumns 87 | if (orderByColumns.length) { 88 | results = results.sort(cmp); 89 | } 90 | 91 | return cb(null, results); 92 | }); 93 | } 94 | 95 | module.exports = OrderByPlan; -------------------------------------------------------------------------------- /lib/plan/plans/queryPlan.js: -------------------------------------------------------------------------------- 1 | var QueryPlan = function() { 2 | this.childPlan = null; 3 | this.queryPlanPerformer = null; 4 | } 5 | 6 | QueryPlan.prototype.setChildPlan = function(childPlan) { 7 | this.childPlan = childPlan; 8 | } 9 | 10 | QueryPlan.prototype.getChildPlan = function() { 11 | return this.childPlan; 12 | } 13 | 14 | QueryPlan.prototype.appendPlan = function(plan) { 15 | if (!plan) { 16 | return this; 17 | } 18 | 19 | var tmpPlan = this; 20 | while (tmpPlan.getChildPlan()) 21 | tmpPlan = tmpPlan.getChildPlan(); 22 | tmpPlan.setChildPlan(plan); 23 | 24 | return this; 25 | } 26 | 27 | QueryPlan.prototype.optimize = function() { 28 | var childPlan = this.getChildPlan(); 29 | 30 | if (childPlan) { 31 | childPlan.optimize(); 32 | 33 | if (childPlan.deletable()) { 34 | this.setChildPlan(childPlan.getChildPlan()); 35 | } 36 | } 37 | } 38 | 39 | QueryPlan.prototype.setQueryPlanPerformer = function(queryPlanPerformer) { 40 | this.queryPlanPerformer = queryPlanPerformer; 41 | } 42 | 43 | QueryPlan.prototype.getQueryPlanPerformer = function() { 44 | this.queryPlanPerformer; 45 | } 46 | 47 | QueryPlan.prototype.deletable = function() { 48 | return false; 49 | } 50 | 51 | QueryPlan.prototype.start = function() { 52 | 53 | } 54 | 55 | module.exports = QueryPlan; -------------------------------------------------------------------------------- /lib/plan/plans/selectPlan.js: -------------------------------------------------------------------------------- 1 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'SelectPlan'); 2 | var PlanHelper = require('../planHelper'); 3 | var QueryPlan = require('./queryPlan'); 4 | var async = require('async'); 5 | var Util = require('util'); 6 | 7 | var SelectPlan = function(selectDefinition, connectionManager) { 8 | QueryPlan.call(this); 9 | this.selectDefinition = selectDefinition; 10 | this.connectionManager = connectionManager; 11 | this.init(selectDefinition); 12 | } 13 | 14 | Util.inherits(SelectPlan, QueryPlan); 15 | 16 | SelectPlan.prototype.init = function(selectDefinition) { 17 | this.destDB = PlanHelper.getDestDB(selectDefinition); 18 | this.sql = selectDefinition.getSQL(); 19 | this.params = []; 20 | } 21 | 22 | SelectPlan.prototype.start = function(cb) { 23 | var connectionManager = this.connectionManager; 24 | var selectDefinition = this.selectDefinition; 25 | var destDB = this.destDB; 26 | var sql = this.sql; 27 | var self = this; 28 | 29 | var selectRole = selectDefinition.getSelectRole(); 30 | 31 | var result = []; 32 | logger.debug("destDB %j sql %s", destDB, sql); 33 | 34 | async.each(destDB, function(destNode, next) { 35 | connectionManager.getConnection(destNode, selectRole, function(err, connection) { 36 | if (err) { 37 | return next(err); 38 | } 39 | 40 | var query = connection.query(sql, [], function(err, results) { 41 | connectionManager.release(connection); 42 | if (err) { 43 | return next(err); 44 | } 45 | 46 | result = result.concat(results); 47 | next(); 48 | }); 49 | 50 | self.print(query.sql); 51 | }, function(err) { 52 | logger.debug('end %j', result); 53 | cb(err, result); 54 | }); 55 | }); 56 | } 57 | 58 | SelectPlan.prototype.print = function(sql) { 59 | // if (process.env.BEARCAT_DEBUG) { 60 | logger.debug(sql); 61 | // } 62 | } 63 | 64 | module.exports = SelectPlan; -------------------------------------------------------------------------------- /lib/plan/plans/simpleSelectPlan.js: -------------------------------------------------------------------------------- 1 | var SelectPlan = require('./selectPlan'); 2 | var Util = require('util'); 3 | 4 | var SimpleSelectPlan = function() { 5 | 6 | } 7 | 8 | Util.inherits(SelectPlan, SelectPlan); 9 | 10 | module.exports = SimpleSelectPlan; -------------------------------------------------------------------------------- /lib/plan/plans/updatePlan.js: -------------------------------------------------------------------------------- 1 | var UpdatePlan = function(sqlDefinition) { 2 | this.sqlDefinition = sqlDefinition; 3 | } 4 | 5 | module.exports = UpdatePlan; -------------------------------------------------------------------------------- /lib/plan/queryPlanFactory.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao QueryPlanFactory 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var AggregatePlan = require('./plans/aggregatePlan'); 15 | var OrderByPlan = require('./plans/orderByPlan'); 16 | var GroupByPlan = require('./plans/groupByPlan'); 17 | var DirectPlan = require('./plans/directPlan'); 18 | var SelectPlan = require('./plans/selectPlan'); 19 | var HavingPlan = require('./plans/havingPlan'); 20 | var LimitPlan = require('./plans/limitPlan'); 21 | 22 | var QueryPlanFactory = function() { 23 | 24 | } 25 | 26 | QueryPlanFactory.prototype.buildDirectPlan = function(sql, params, options, connectionManager) { 27 | return new DirectPlan(sql, params, options, connectionManager); 28 | } 29 | 30 | QueryPlanFactory.prototype.buildQueryPlan = function(selectDefinition, connectionManager) { 31 | var rootPlan = null; 32 | 33 | rootPlan = this.appendPlan(rootPlan, this.buildLimitPlan(selectDefinition)); 34 | rootPlan = this.appendPlan(rootPlan, this.buildOrderByPlan(selectDefinition)); 35 | 36 | // if (selectDefinition.isJoinNeeded() || (!selectDefinition.groupContainsBalanceField())) { 37 | rootPlan = this.appendPlan(rootPlan, this.buildHavingPlan(selectDefinition)); 38 | rootPlan = this.appendPlan(rootPlan, this.buildAggregatePlan(selectDefinition)); 39 | rootPlan = this.appendPlan(rootPlan, this.buildGroupByPlan(selectDefinition)); 40 | // } 41 | 42 | rootPlan = this.appendPlan(rootPlan, this.buildSelectPLan(selectDefinition, connectionManager)); 43 | return rootPlan; 44 | } 45 | 46 | QueryPlanFactory.prototype.buildUpdatePlan = function(updateDefinition, connectionManager) { 47 | 48 | } 49 | 50 | QueryPlanFactory.prototype.buildLimitPlan = function(selectDefinition) { 51 | return new LimitPlan(selectDefinition); 52 | } 53 | 54 | QueryPlanFactory.prototype.buildOrderByPlan = function(selectDefinition) { 55 | return new OrderByPlan(selectDefinition); 56 | } 57 | 58 | QueryPlanFactory.prototype.buildHavingPlan = function(selectDefinition) { 59 | return new HavingPlan(selectDefinition); 60 | } 61 | 62 | QueryPlanFactory.prototype.buildAggregatePlan = function(selectDefinition) { 63 | return new AggregatePlan(selectDefinition); 64 | } 65 | 66 | QueryPlanFactory.prototype.buildGroupByPlan = function(selectDefinition) { 67 | return new GroupByPlan(selectDefinition); 68 | } 69 | 70 | QueryPlanFactory.prototype.buildSelectPLan = function(selectDefinition, connectionManager) { 71 | return new SelectPlan(selectDefinition, connectionManager); 72 | } 73 | 74 | QueryPlanFactory.prototype.appendPlan = function(root, newPlan) { 75 | if (root) { 76 | root.appendPlan(newPlan); 77 | } else { 78 | root = newPlan; 79 | } 80 | 81 | return root; 82 | } 83 | 84 | module.exports = QueryPlanFactory; -------------------------------------------------------------------------------- /lib/support/fieldConfig.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao FieldConfig 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | /** 15 | * FieldConfig constructor function. 16 | * 17 | * @api public 18 | */ 19 | var FieldConfig = function() { 20 | this.name = null; 21 | this.type = null; 22 | } 23 | 24 | module.exports = FieldConfig; 25 | 26 | /** 27 | * FieldConfig get name. 28 | * 29 | * @return {String} field name 30 | * @api public 31 | */ 32 | FieldConfig.prototype.getName = function() { 33 | return this.name; 34 | } 35 | 36 | /** 37 | * FieldConfig set name. 38 | * 39 | * @param {String} name field name 40 | * @api public 41 | */ 42 | FieldConfig.prototype.setName = function(name) { 43 | this.name = name; 44 | } 45 | 46 | /** 47 | * FieldConfig get type. 48 | * 49 | * @return {String} field type 50 | * @api public 51 | */ 52 | FieldConfig.prototype.getType = function() { 53 | return this.type; 54 | } 55 | 56 | /** 57 | * FieldConfig get type. 58 | * 59 | * @param {String} type type name 60 | * @api public 61 | */ 62 | FieldConfig.prototype.setType = function(type) { 63 | this.type = type.toLowerCase(); 64 | } -------------------------------------------------------------------------------- /lib/support/tableConfig.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao TableConfig 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | /** 15 | * TableConfig constructor function. 16 | * 17 | * @api public 18 | */ 19 | var TableConfig = function() { 20 | this.mid = null; 21 | this.func = null; 22 | this.tableName = null; 23 | this.normalFields = []; 24 | this.primaryFields = []; 25 | } 26 | 27 | module.exports = TableConfig; 28 | 29 | /** 30 | * TableConfig set table name. 31 | * 32 | * @param {String} tableName table name 33 | * @api public 34 | */ 35 | TableConfig.prototype.setTableName = function(tableName) { 36 | this.tableName = tableName; 37 | } 38 | 39 | /** 40 | * TableConfig get table name. 41 | * 42 | * @return {String} table name 43 | * @api public 44 | */ 45 | TableConfig.prototype.getTableName = function() { 46 | return this.tableName; 47 | } 48 | 49 | /** 50 | * TableConfig set model id. 51 | * 52 | * @param {String} model id 53 | * @api public 54 | */ 55 | TableConfig.prototype.setMid = function(mid) { 56 | this.mid = mid; 57 | } 58 | 59 | /** 60 | * TableConfig get model id. 61 | * 62 | * @param {String} model id 63 | * @api public 64 | */ 65 | TableConfig.prototype.getMid = function() { 66 | return this.mid; 67 | } 68 | 69 | /** 70 | * TableConfig set constructor function. 71 | * 72 | * @param {Function} func constructor function 73 | * @api public 74 | */ 75 | TableConfig.prototype.setFunc = function(func) { 76 | this.func = func; 77 | } 78 | 79 | /** 80 | * TableConfig get constructor function. 81 | * 82 | * @return {Function} constructor function 83 | * @api public 84 | */ 85 | TableConfig.prototype.getFunc = function() { 86 | return this.func; 87 | } 88 | 89 | /** 90 | * TableConfig set primary fields. 91 | * 92 | * @param {Array} primaryFields primary fields 93 | * @api public 94 | */ 95 | TableConfig.prototype.setPrimaryFields = function(primaryFields) { 96 | this.primaryFields = primaryFields; 97 | } 98 | 99 | /** 100 | * TableConfig get primary fields. 101 | * 102 | * @return {Array} primary fields 103 | * @api public 104 | */ 105 | TableConfig.prototype.getPrimaryFields = function() { 106 | return this.primaryFields; 107 | } 108 | 109 | /** 110 | * TableConfig set normal fields. 111 | * 112 | * @param {Array} normalFields normal fields 113 | * @api public 114 | */ 115 | TableConfig.prototype.setNormalFields = function(normalFields) { 116 | this.normalFields = normalFields; 117 | } 118 | 119 | /** 120 | * TableConfig get primary fields. 121 | * 122 | * @return {Array} primary fields 123 | * @api public 124 | */ 125 | TableConfig.prototype.getNormalFields = function() { 126 | return this.normalFields; 127 | } 128 | 129 | /** 130 | * TableConfig get fields(all). 131 | * 132 | * @param {Array} fields 133 | * @api public 134 | */ 135 | TableConfig.prototype.getFields = function() { 136 | var fields = []; 137 | 138 | for (var i = 0; i < this.normalFields.length; i++) { 139 | fields.push(this.normalFields[i]); 140 | } 141 | 142 | for (var i = 0; i < this.primaryFields.length; i++) { 143 | fields.push(this.primaryFields[i]); 144 | } 145 | 146 | return fields; 147 | } -------------------------------------------------------------------------------- /lib/template/cache/command/multiCommand.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var MultiCommand = function(cmds, client, tx) { 4 | this.tx = tx; 5 | this.cmds = cmds; 6 | this.client = client; 7 | this.queue = []; 8 | } 9 | 10 | MultiCommand.prototype.exec = function(cb) { 11 | var errors = []; 12 | var replies = []; 13 | var self = this; 14 | var cmds = this.cmds; 15 | cb = cb || function() {}; 16 | 17 | if (!cmds || !cmds.length) { 18 | return cb(); 19 | } 20 | 21 | if (this.tx) { 22 | return this.execTx(cb); 23 | } 24 | 25 | async.eachSeries(cmds, function(cmd, next) { 26 | var key = cmd[1]; 27 | var command = cmd[0]; 28 | var args = cmd.slice(1); 29 | 30 | self.client.getClientByKey(key, function(err, clientProxy) { 31 | if (err) { 32 | errors.push(err); 33 | return next(); 34 | } 35 | 36 | if (!clientProxy) { 37 | errors.push(new Error('client is not exist for key: ' + key)); 38 | return next(); 39 | } 40 | 41 | clientProxy.send_command(command, args, function(err, reply) { 42 | if (err) { 43 | errors.push(err); 44 | replies.push(err.message); 45 | } else { 46 | replies.push(reply); 47 | } 48 | 49 | next(); 50 | }); 51 | }); 52 | }, function() { 53 | if (errors.length > 0) { 54 | cb(errors); 55 | } else { 56 | cb(null, replies); 57 | } 58 | }) 59 | } 60 | 61 | MultiCommand.prototype.execTx = function(cb) { 62 | var cmds = this.cmds; 63 | var cmd = cmds[0]; 64 | var key = cmd[1]; 65 | var self = this; 66 | 67 | self.client.getClientByKey(key, function(err, clientProxy) { 68 | if (err) { 69 | return cb(err); 70 | } 71 | 72 | clientProxy.multi(cmds).exec(cb); 73 | }); 74 | } 75 | 76 | module.exports = MultiCommand; -------------------------------------------------------------------------------- /lib/template/cache/redisClusterTemplate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao RedisClusterTemplate 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'RedisClusterTemplate'); 15 | var ShardingUtil = require('../../util/shardingUtil'); 16 | var MultiCommand = require('./command/multiCommand'); 17 | var EventEmitter = require('events').EventEmitter; 18 | var Constant = require('../../util/constant'); 19 | var Utils = require('../../util/utils'); 20 | var Util = require('util'); 21 | 22 | var shardingUtil = ShardingUtil("redis"); 23 | // shardingUtil['shardingFile'] = Constant.REDIS_CLUSTER_MAP_PATH; 24 | 25 | var REDIS_CLUSTER_COMMANDS = Constant.REDIS_CLUSTER_COMMANDS; 26 | 27 | /** 28 | * RedisClusterTemplate constructor function. 29 | * 30 | * @api public 31 | */ 32 | var RedisClusterTemplate = function() { 33 | this.connectionManager = null; 34 | this.role = Constant.ROLE_MASTER; 35 | } 36 | 37 | Util.inherits(RedisClusterTemplate, EventEmitter); 38 | 39 | RedisClusterTemplate.prototype.init = function() { 40 | var self = this; 41 | REDIS_CLUSTER_COMMANDS.forEach(function(command) { 42 | self[command] = function() { 43 | self.runCommand(command, arguments); 44 | }; 45 | }); 46 | } 47 | 48 | RedisClusterTemplate.prototype.runCommand = function(command, args) { 49 | var key = args[0]; 50 | this.getClientByKey(key, function(err, client) { 51 | if (!client) { 52 | var callback = args[args.length - 1]; 53 | if (Utils.checkFunction(callback)) { 54 | callback(new Error('client is not exist for key: ' + key)); 55 | } 56 | return; 57 | } 58 | 59 | client[command].apply(client, args); 60 | }); 61 | } 62 | 63 | // tx transaction flag, means cmds with the same key 64 | RedisClusterTemplate.prototype.multi = function(cmds, tx) { 65 | return new MultiCommand(cmds, this, tx); 66 | } 67 | 68 | RedisClusterTemplate.prototype.getClientByKey = function(key, cb) { 69 | var clusterMap = shardingUtil.getClusterMap(); 70 | if (!clusterMap) { 71 | return cb(new Error('getClientByKey redis clusterMap null')); 72 | } 73 | 74 | var hashValue = Utils.calHashValue(key, clusterMap.length); 75 | var target = clusterMap[hashValue]; 76 | 77 | if (target && target['name']) { 78 | var redisName = target['name']; 79 | return this.connectionManager.getConnection(redisName, this.role, cb); 80 | } 81 | 82 | cb(new Error('getClientByKey redis target client not exist')); 83 | } 84 | 85 | RedisClusterTemplate.prototype.getClientByNode = function(node, cb) { 86 | this.connectionManager.getConnection(node, this.role, cb); 87 | } 88 | 89 | RedisClusterTemplate.prototype.restartHaClient = function() { 90 | this.connectionManager.restartHaClient(); 91 | } 92 | 93 | module.exports = RedisClusterTemplate; -------------------------------------------------------------------------------- /lib/template/cache/redisTemplate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao RedisTemplate 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var EventEmitter = require('events').EventEmitter; 15 | var utils = require('../../util/utils'); 16 | var util = require('util'); 17 | 18 | /** 19 | * RedisTemplate constructor function. 20 | * 21 | * @api public 22 | */ 23 | var RedisTemplate = function() { 24 | this.connectionManager = null; 25 | this.connection = null; 26 | this.expireDay = -1; 27 | } 28 | 29 | module.exports = RedisTemplate; 30 | 31 | util.inherits(RedisTemplate, EventEmitter); 32 | 33 | /** 34 | * RedisTemplate set connection manager. 35 | * 36 | * @param {Object} connectionManager connection manager 37 | * @api public 38 | */ 39 | RedisTemplate.prototype.setConnectionManager = function(connectionManager) { 40 | this.connectionManager = connectionManager; 41 | } 42 | 43 | /** 44 | * RedisTemplate get connection manager. 45 | * 46 | * @return {Object} connection manager 47 | * @api public 48 | */ 49 | RedisTemplate.prototype.getConnectionManager = function() { 50 | return this.connectionManager; 51 | } 52 | 53 | /** 54 | * RedisTemplate set expire day. 55 | * 56 | * @param {Boolean} expireDay expire day 57 | * @api public 58 | */ 59 | RedisTemplate.prototype.setExpireDay = function(expireDay) { 60 | this.expireDay = expireDay; 61 | } 62 | 63 | /** 64 | * RedisTemplate get expire day. 65 | * 66 | * @return {Boolean} expire day 67 | * @api public 68 | */ 69 | RedisTemplate.prototype.getExpireDay = function() { 70 | return this.expireDay; 71 | } 72 | 73 | /** 74 | * RedisTemplate get connection. 75 | * 76 | * @return {Object} connection 77 | * @api public 78 | */ 79 | RedisTemplate.prototype.getConnection = function() { 80 | if (!this.connection) { 81 | this.connection = this.connectionManager.getConnection(); 82 | } 83 | 84 | return this.connection; 85 | } 86 | 87 | /** 88 | * RedisTemplate send_command proxy to node-redis client send_command method. 89 | * 90 | * @api private 91 | */ 92 | RedisTemplate.prototype.send_command = function(command, args, cb, argumentsAll) { 93 | if (Array.isArray(args) && typeof cb === "function") { 94 | return this.getConnection().send_command(command, args, cb); 95 | } else { 96 | return this.getConnection().send_command(command, argumentsAll); 97 | } 98 | } 99 | 100 | /** 101 | * RedisTemplate add to redis cache, simple key:value. 102 | * 103 | * @param {String} key cache key 104 | * @param {String} value cache value 105 | * @param {Number} expire expire time 106 | * @api public 107 | */ 108 | RedisTemplate.prototype.addToCache = function(key, value, expire) { 109 | if (key == null || value == null) { 110 | return; 111 | } 112 | 113 | this.getConnection().set(key, value); 114 | if (expire != null) { 115 | this.expire(key, expire); 116 | } 117 | } 118 | 119 | /** 120 | * RedisTemplate add to redis cache array, key:[]. 121 | * 122 | * @param {String} key cache key 123 | * @param {String} value cache value 124 | * @api public 125 | */ 126 | RedisTemplate.prototype.addToList = function(key, value) { 127 | if (key == null || value == null) { 128 | return; 129 | } 130 | 131 | this.getConnection().rpush(key, value); 132 | } 133 | 134 | /** 135 | * RedisTemplate get string from redis array, use lindex redis command. 136 | * 137 | * @api public 138 | */ 139 | RedisTemplate.prototype.getStringFromList = function(args, cb) { 140 | var command = "lindex"; 141 | return this.send_command(command, args, cb, utils.to_array(arguments)); 142 | } 143 | 144 | /** 145 | * RedisTemplate get redis array length, use llen redis command. 146 | * 147 | * @api public 148 | */ 149 | RedisTemplate.prototype.getListLength = function(args, cb) { 150 | var command = "llen"; 151 | return this.send_command(command, args, cb, utils.to_array(arguments)); 152 | } 153 | 154 | /** 155 | * RedisTemplate get redis array range value, use lrange redis command. 156 | * 157 | * @api public 158 | */ 159 | RedisTemplate.prototype.getStringListRange = function(args, cb) { 160 | var command = "lrange"; 161 | return this.send_command(command, args, cb, utils.to_array(arguments)); 162 | } 163 | 164 | /** 165 | * RedisTemplate check key if exists in redis. 166 | * 167 | * @api public 168 | */ 169 | RedisTemplate.prototype.keyExists = function(args, cb) { 170 | var command = "exists"; 171 | return this.send_command(command, args, cb, utils.to_array(arguments)); 172 | } 173 | 174 | /** 175 | * RedisTemplate set string to redis list. 176 | * 177 | * @param {String} key cache key 178 | * @param {Number} index list index 179 | * @param {String} value cache value 180 | * @api public 181 | */ 182 | RedisTemplate.prototype.setStringToList = function(key, index, value) { 183 | if (key == null || value == null) { 184 | return; 185 | } 186 | this.getConnection().lset(key, index, value); 187 | } 188 | 189 | /** 190 | * RedisTemplate delete string from redis list. 191 | * 192 | * @param {String} key cache key 193 | * @param {String} value cache value 194 | * @api public 195 | */ 196 | RedisTemplate.prototype.deleteStringFromList = function(key, value) { 197 | if (key == null || value == null) { 198 | return; 199 | } 200 | this.getConnection().lrem(key, 0, value); 201 | } 202 | 203 | /** 204 | * RedisTemplate delete strings from redis list. 205 | * 206 | * @param {String} key cache key 207 | * @param {Array} value cache values 208 | * @api public 209 | */ 210 | RedisTemplate.prototype.deleteStringsFromList = function(key, value) { 211 | if (key == null || value == null) { 212 | return; 213 | } 214 | if (Array.isArray(value)) { 215 | for (var i = 0; i < value.length; i++) { 216 | this.getConnection().lrem(key, 0, value[i]); 217 | } 218 | } 219 | } 220 | 221 | /** 222 | * RedisTemplate get key value from redis. 223 | * 224 | * @param {String} cache key 225 | * @api public 226 | */ 227 | RedisTemplate.prototype.getString = function(args, cb) { 228 | var command = "get"; 229 | return this.send_command(command, args, cb, utils.to_array(arguments)); 230 | } 231 | 232 | /** 233 | * RedisTemplate del key from redis. 234 | * 235 | * @param {String} key cache key 236 | * @api public 237 | */ 238 | RedisTemplate.prototype.delFromCache = function(key) { 239 | if (key == null) { 240 | return; 241 | } 242 | this.getConnection().del(key); 243 | } 244 | 245 | /** 246 | * RedisTemplate set counter. 247 | * 248 | * @param {String} key cache key 249 | * @param {Number} initCount 250 | * @param {Number} expire expire time 251 | * @api public 252 | */ 253 | RedisTemplate.prototype.setCounter = function(key, initCount, expire) { 254 | this.addToCache(key, initCount, expire); 255 | } 256 | 257 | /** 258 | * RedisTemplate get counter. 259 | * 260 | * @param {String} cache key 261 | * @param {Function} callback function 262 | * @api public 263 | */ 264 | RedisTemplate.prototype.getCounter = function(args, cb) { 265 | return this.getString(args, cb); 266 | } 267 | 268 | /** 269 | * RedisTemplate incr by increment. 270 | * 271 | * @param {String} cache key 272 | * @param {Number} increment number 273 | * @param {Function} callback function 274 | * @api public 275 | */ 276 | RedisTemplate.prototype.incrBy = function(args, cb) { 277 | var command = "incrBy"; 278 | return this.send_command(command, args, cb, utils.to_array(arguments)); 279 | } 280 | 281 | /** 282 | * RedisTemplate incr by 1. 283 | * 284 | * @param {String} key cache key 285 | * @api public 286 | */ 287 | RedisTemplate.prototype.incr = function(key) { 288 | return this.getConnection().incr(key); 289 | } 290 | 291 | /** 292 | * RedisTemplate set expire key. 293 | * 294 | * @param {String} key cache key 295 | * @param {Number} expire expire time 296 | * @api public 297 | */ 298 | RedisTemplate.prototype.expire = function(key, expire) { 299 | if (key == null) { 300 | return; 301 | } 302 | 303 | if (expire) { 304 | this.getConnection().expire(key, expire); 305 | } else if (this.getExpireDay()) { 306 | this.getConnection().expire(key, this.expireDay); 307 | } 308 | } -------------------------------------------------------------------------------- /lib/template/sql/ddbTemplate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DDBTemplate 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'DDBTemplate'); 15 | var SqlBuilderUtil = require('../../util/sqlBuilderUtil'); 16 | var EventEmitter = require('events').EventEmitter; 17 | var Constant = require('../../util/constant'); 18 | var Utils = require('../../util/utils'); 19 | var Util = require('util'); 20 | 21 | /** 22 | * DDBTemplate constructor function. 23 | * 24 | * @api public 25 | */ 26 | var DDBTemplate = function() { 27 | this.planManager = null; 28 | } 29 | 30 | Util.inherits(DDBTemplate, EventEmitter); 31 | 32 | /** 33 | * DDBTemplate execute query. 34 | * 35 | * @param {String} sql 36 | * @param {Array} params 37 | * @param {Function} cb callback function 38 | * @api public 39 | */ 40 | DDBTemplate.prototype.executeQuery = function(sql, params, cb) { 41 | this.planManager.executeQuery(sql, params, cb); 42 | return this; 43 | } 44 | 45 | /** 46 | * DDBTemplate direct query with destDBs. 47 | * 48 | * @param {String} sql 49 | * @param {Array} params 50 | * @param {Object} destDB, role options 51 | * @param {Function} cb callback function 52 | * @api public 53 | */ 54 | DDBTemplate.prototype.directQuery = function(sql, params, options, cb) { 55 | this.planManager.directQuery(sql, params, options, cb); 56 | return this; 57 | } 58 | 59 | /** 60 | * DDBTemplate direct add object. 61 | * 62 | * @param {Object} object 63 | * @param {Object} table, destDB, role options 64 | * @param {Function} cb callback function 65 | * @api public 66 | */ 67 | DDBTemplate.prototype.directAdd = function(object, options, cb) { 68 | return this.directBatchAdd([object], options, cb); 69 | } 70 | 71 | /** 72 | * DDBTemplate batch direct add objects. 73 | * 74 | * @param {Array} objects 75 | * @param {Object} table, destDB, role options 76 | * @param {Function} cb callback function 77 | * @api public 78 | */ 79 | DDBTemplate.prototype.directBatchAdd = function(objects, options, cb) { 80 | if (!Utils.checkArray(objects)) { 81 | return cb(); 82 | } 83 | 84 | var table = options['table']; 85 | if (!table) { 86 | return cb(new Error('directBatchAdd error no table options')); 87 | } 88 | 89 | var len = objects.length; 90 | if (!len) { 91 | return cb(); 92 | } 93 | 94 | var fields = []; 95 | var params = []; 96 | var flag = 0; 97 | 98 | for (var i = 0; i < len; i++) { 99 | var object = objects[i]; 100 | 101 | for (var key in object) { 102 | if (!flag) { 103 | fields.push(key); 104 | } 105 | params.push(object[key]); 106 | } 107 | 108 | flag = 1; 109 | } 110 | 111 | var sql = SqlBuilderUtil.buildBatchInsertSql(table, fields, len); 112 | 113 | return this.directQuery(sql, params, options, cb); 114 | } 115 | 116 | /** 117 | * DDBTemplate direct update object by id. 118 | * 119 | * @param {Object} object 120 | * @param {Object} table, destDB, role, id options 121 | * @param {Function} cb callback function 122 | * @api public 123 | */ 124 | DDBTemplate.prototype.directUpdateById = function(object, options, cb) { 125 | if (!object) { 126 | return cb(); 127 | } 128 | 129 | var table = options['table']; 130 | if (!table) { 131 | return cb(new Error('directUpdateById error no table options')); 132 | } 133 | 134 | var idField = options['id']; 135 | var ID_FIELD = idField || Constant.ID_FIELD; 136 | var fields = []; 137 | var params = []; 138 | var id = null; 139 | 140 | for (var key in object) { 141 | if (key == ID_FIELD) { 142 | id = object[ID_FIELD]; 143 | continue; 144 | } 145 | 146 | fields.push(key); 147 | params.push(object[key]); 148 | } 149 | 150 | params.push(id); 151 | 152 | var sql = SqlBuilderUtil.buildUpdateSql(table, fields, [ID_FIELD]); 153 | 154 | return this.directQuery(sql, params, options, cb); 155 | } 156 | 157 | /** 158 | * DDBTemplate print sql. 159 | * 160 | * @param {String} sql 161 | * @api private 162 | */ 163 | DDBTemplate.prototype.print = function(sql) { 164 | if (process.env.BEARCAT_DEBUG) { 165 | logger.debug(sql); 166 | } 167 | } 168 | 169 | /** 170 | * DDBTemplate error handler. 171 | * 172 | * @param {Object} error 173 | * @param {Function} cb callback function 174 | * @api private 175 | */ 176 | DDBTemplate.prototype.handleError = function(err, cb) { 177 | if (err) { 178 | cb(err); 179 | return true; 180 | } 181 | 182 | return false; 183 | } 184 | 185 | module.exports = DDBTemplate; -------------------------------------------------------------------------------- /lib/transaction/cacheTransactionManager.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bearcatjs/bearcat-dao/5affc25fd2705e3aeaca5e82ad6ac21fdaa4c0af/lib/transaction/cacheTransactionManager.js -------------------------------------------------------------------------------- /lib/transaction/dbTransactionManager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DbTransactionManager 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'DbTransactionManager'); 15 | var TransactionStatus = require('./transactionStatus'); 16 | var Constant = require('../util/constant'); 17 | 18 | /** 19 | * DBTransactionManager constructor function. 20 | * 21 | * @api public 22 | */ 23 | var DbTransactionManager = function() { 24 | this.id = 1; 25 | this.connectionMap = {}; 26 | this.connectionManager = null; 27 | } 28 | 29 | module.exports = DbTransactionManager; 30 | 31 | /** 32 | * DBTransactionManager get connection with transactionStatus. 33 | * 34 | * @param {Object} transactionStatus 35 | * @api public 36 | */ 37 | DbTransactionManager.prototype.getConnection = function(transactionStatus) { 38 | var id = transactionStatus.getId(); 39 | return this.connectionMap[id]; 40 | } 41 | 42 | /** 43 | * DBTransactionManager set connection manager. 44 | * 45 | * @param {Object} connectionManager connection manager 46 | * @api public 47 | */ 48 | DbTransactionManager.prototype.setConnectionManager = function(connectionManager) { 49 | this.connectionManager = connectionManager; 50 | } 51 | 52 | /** 53 | * DBTransactionManager get connection manager. 54 | * 55 | * @return {Object} connection manager 56 | * @api public 57 | */ 58 | DbTransactionManager.prototype.getConnectionManager = function() { 59 | return this.connectionManager; 60 | } 61 | 62 | /** 63 | * DBTransactionManager get transaction. 64 | * 65 | * @param {Function} cb callback function 66 | * @api public 67 | */ 68 | DbTransactionManager.prototype.getTransaction = function(cb) { 69 | var self = this; 70 | this.getConnectionManager().getConnection(function(err, connection) { 71 | if (err) { 72 | return cb(err); 73 | } 74 | 75 | connection.beginTransaction(function(err) { 76 | if (err) { 77 | return cb(err); 78 | } 79 | var id = self.id++; 80 | self.connectionMap[id] = connection; 81 | var transactionStatus = new TransactionStatus(); 82 | transactionStatus.setId(id); 83 | transactionStatus.setStatus(Constant.TRANSACTION_START); 84 | cb(null, transactionStatus); 85 | }); 86 | }); 87 | } 88 | 89 | /** 90 | * DBTransactionManager commit transaction. 91 | * 92 | * @param {Object} transactionStatus 93 | * @param {Function} cb callback function 94 | * @api public 95 | */ 96 | DbTransactionManager.prototype.commit = function(transactionStatus, cb) { 97 | var self = this; 98 | 99 | var connection = this.getConnection(transactionStatus); 100 | connection.commit(function(err) { 101 | if (err) { 102 | return self.rollback(transactionStatus, function() { 103 | cb(err); 104 | }); 105 | } 106 | cb(); 107 | logger.info('commit transaction id %s', transactionStatus["id"]); 108 | self.clear(transactionStatus); 109 | }); 110 | } 111 | 112 | /** 113 | * DBTransactionManager rollback transaction. 114 | * 115 | * @param {Object} transactionStatus 116 | * @param {Function} cb callback function 117 | * @api public 118 | */ 119 | DbTransactionManager.prototype.rollback = function(transactionStatus, cb) { 120 | var connection = this.getConnection(transactionStatus); 121 | var self = this; 122 | return connection.rollback(function() { 123 | cb(); 124 | logger.info('rollback transaction id %s', transactionStatus["id"]); 125 | self.clear(transactionStatus); 126 | }); 127 | } 128 | 129 | /** 130 | * DBTransactionManager clear transaction. 131 | * 132 | * @param {Object} transactionStatus 133 | * @api public 134 | */ 135 | DbTransactionManager.prototype.clear = function(transactionStatus) { 136 | var connection = this.getConnection(transactionStatus); 137 | this.getConnectionManager().release(connection); 138 | var id = transactionStatus.getId(); 139 | this.connectionMap[id] = null; 140 | } -------------------------------------------------------------------------------- /lib/transaction/transactionStatus.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao TransactionStatus 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var Constant = require('../util/constant'); 15 | 16 | /** 17 | * TransactionStatus constructor function. 18 | * 19 | * @api public 20 | */ 21 | var TransactionStatus = function() { 22 | this.id = null; 23 | this.status = Constant.TRANSACTION_DEFAULT; 24 | } 25 | 26 | module.exports = TransactionStatus; 27 | 28 | /** 29 | * TransactionStatus set id. 30 | * 31 | * @param {Number} id 32 | * @api public 33 | */ 34 | TransactionStatus.prototype.setId = function(id) { 35 | this.id = id; 36 | } 37 | 38 | /** 39 | * TransactionStatus get id. 40 | * 41 | * @return {Number} id 42 | * @api public 43 | */ 44 | TransactionStatus.prototype.getId = function() { 45 | return this.id; 46 | } 47 | 48 | /** 49 | * TransactionStatus set status. 50 | * 51 | * @param {Object} status 52 | * @api public 53 | */ 54 | TransactionStatus.prototype.setStatus = function(status) { 55 | this.status = status; 56 | } 57 | 58 | /** 59 | * TransactionStatus get status. 60 | * 61 | * @return {Object} status 62 | * @api public 63 | */ 64 | TransactionStatus.prototype.getStatus = function() { 65 | return this.status; 66 | } -------------------------------------------------------------------------------- /lib/util/beanBuilderUtil.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao BeanBuilderUtil 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var Utils = require('./utils'); 15 | var BeanBuilderUtil = {}; 16 | 17 | module.exports = BeanBuilderUtil; 18 | 19 | /** 20 | * BeanBuilderUtil build object list from resultset. 21 | * 22 | * @param {Array} results query resultset 23 | * @param {Function} func constructor function 24 | * @param {Array} fields fields array 25 | * @api public 26 | */ 27 | BeanBuilderUtil.buildObjectList = function(results, func, fields) { 28 | var r = []; 29 | 30 | for (var i = 0; i < results.length; i++) { 31 | var result = results[i]; 32 | var beanObject = new func(); 33 | 34 | for (var j = 0; j < fields.length; j++) { 35 | var field = fields[j]; 36 | var name = field.getName(); 37 | if (Utils.isNotNull(result[name])) { 38 | beanObject[name] = result[name]; 39 | } 40 | } 41 | 42 | r.push(beanObject); 43 | } 44 | 45 | return r; 46 | } 47 | 48 | /** 49 | * BeanBuilderUtil build models from resultset. 50 | * 51 | * @param {String} model id 52 | * @param {Array} result sets 53 | * @param {Array} result model sets 54 | * @api public 55 | */ 56 | BeanBuilderUtil.buildModels = function(modelId, resultSets) { 57 | var bearcat = Utils.getBearcat(); 58 | var beanFactory = bearcat.getBeanFactory(); 59 | var modelDefinition = beanFactory.getModelDefinition(modelId); 60 | 61 | var result; 62 | if (modelDefinition.isOneToMany()) { 63 | result = {}; 64 | var model = beanFactory.getModelProxy(modelId); 65 | for (var i = 0; i < resultSets.length; i++) { 66 | var r = model.$packResultSet(resultSets[i]); 67 | if (Utils.checkModelFilterError(r)) { 68 | return r; 69 | } 70 | } 71 | result = model; 72 | } else { 73 | result = []; 74 | for (var i = 0; i < resultSets.length; i++) { 75 | var model = beanFactory.getModelProxy(modelId); 76 | var r = model.$packResultSet(resultSets[i]); 77 | if (Utils.checkModelFilterError(r)) { 78 | return r; 79 | } 80 | 81 | result.push(model); 82 | } 83 | } 84 | 85 | return result; 86 | } 87 | 88 | /** 89 | * BeanBuilderUtil model set. 90 | * 91 | * @param {Object} model object 92 | * @param {String} key 93 | * @param {String} value 94 | * @api public 95 | */ 96 | BeanBuilderUtil.modelSet = function(object, key, value) { 97 | if (object['model'] && object['model']['$mid']) { 98 | object.$set(key, value); 99 | } else { 100 | object[key] = value; 101 | } 102 | } 103 | 104 | /** 105 | * BeanBuilderUtil model get. 106 | * 107 | * @param {Object} model object 108 | * @param {String} key 109 | * @api public 110 | */ 111 | BeanBuilderUtil.modelGet = function(object, key) { 112 | var value = object[key]; 113 | if (!Utils.isNotNull(value) && object['$get']) { 114 | value = object.$get(key); 115 | } 116 | 117 | return value; 118 | } -------------------------------------------------------------------------------- /lib/util/constant.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao Constant 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | module.exports = { 15 | DEFAULT_REDIS_PORT: 6379, 16 | DEFAULT_REDIS_HOST: '127.0.0.1', 17 | DEFAULT_MYSQL_PORT: 3306, 18 | DEFAULT_MYSQL_HOST: '127.0.0.1', 19 | DEFAULT_MYSQL_USE_POOL: true, 20 | DEFAULT_MYSQL_CONNECT_CB: function() {}, 21 | DEFAULT_REDIS_CONNECT_CB: function() {}, 22 | 23 | TYPE_LONG: 'long', 24 | TYPE_NUMBER: 'number', 25 | 26 | TRANSACTION_DEFAULT: "", 27 | TRANSACTION_START: "tstart", 28 | 29 | FILE_TYPE_SQL: 'sql', 30 | 31 | COMMENT_LINE_1: /\/\/.*?\n/g, 32 | COMMENT_LINE_2: /\-\-.*?\n/g, 33 | COMMENT_STAR: /\/\*(.|\s)*?\*\//g, 34 | 35 | CONTENT_BLOCK: /sql\s*\w+(.|\s)*?end/g, 36 | CONTENT_BLOCK_SQL: /sql\s*(\w+)((.|\s)*?)end/, 37 | CONTENT_SQL_TRIM: /\n\s*/g, 38 | SQL_REF: /\$\{\w+\}/g, 39 | SQL_REF_ID: /\$\{(\w+)\}/, 40 | 41 | DOLLAR_PREFIX: '$', 42 | 43 | PLAN_QUERY: 'select', 44 | 45 | SQL_SELECT_PART: { 46 | COLUMN: 'column', 47 | SOURCE: 'source', 48 | JOIN: 'joinmap', 49 | WHERE: 'where', 50 | GROUPBY: 'groupby', 51 | ORDERBY: 'orderby', 52 | LIMIT: 'limit' 53 | }, 54 | 55 | ROLE_MASTER: 'master', 56 | ROLE_SLAVE: 'slave', 57 | 58 | LEXTER_TYPE_NUMBER: 2, 59 | 60 | SELECT_CONDITION_EQUAL: "=", 61 | SELECT_CONDITION_IN: "in", 62 | SELECT_CONDITION_NOT_IN: "not in", 63 | SELECT_CONDITION_NOT_NULL: "not null", 64 | SELECT_CONDITION_BETWEEN: "between", 65 | SELECT_CONDITION_VALUE_TYPE_KEYWORD: 1, 66 | SELECT_CONDITION_VALUE_TYPE_STRING: 3, 67 | SELECT_CONDITION_VALUE_TYPE_OPERATOR: 7, 68 | CLUSTER_MAP_PATH: "clusterSharding.json", 69 | MYSQL_CLUSTER_MAP_PATH: "mysqlSharding.json", 70 | REDIS_CLUSTER_MAP_PATH: "redisSharding.json", 71 | DEST_DB_ALL: "*", 72 | 73 | ORDER_ASC: 1, 74 | ORDER_DESC: 2, 75 | 76 | REDIS_RETRY_MAX_DELAY: 30 * 1000, 77 | 78 | ID_FIELD: "id", 79 | 80 | REDIS_CLUSTER_COMMANDS: [ 81 | 'del', 'expire', 'ttl', 82 | 'get', 'set', 'exists', 83 | 'llen', 'lrem', 'lpush', 'lrange', 84 | 'sadd', 'scard', 'smembers', 'srem', 85 | 'zadd', 'zcard', 'zrangebyscore', 86 | 'zrem', 'zrange', 'zremrangebyrank', 87 | 'zscore' 88 | ] 89 | } -------------------------------------------------------------------------------- /lib/util/countDownLatch.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao CountDownLatch 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'CountDownLatch'); 15 | 16 | /** 17 | * CountDownLatch Count down to zero and invoke cb finally. 18 | * 19 | * @param {Number} count count down number 20 | * @param {Function} cb callback function 21 | * @api public 22 | */ 23 | var CountDownLatch = function(count, cb) { 24 | this.count = count; 25 | this.cb = cb; 26 | }; 27 | 28 | /** 29 | * CountDownLatch Call when a task finish to count down, when err latch done to 0. 30 | * 31 | * @param {Object} err 32 | * @api public 33 | */ 34 | CountDownLatch.prototype.done = function(err) { 35 | if (this.count < 0) { 36 | logger.error('illegal state.'); 37 | return; 38 | } 39 | 40 | if (err) { 41 | this.count = 0; 42 | this.cb(err); 43 | return; 44 | } 45 | 46 | this.count--; 47 | if (this.count === 0) { 48 | this.cb(); 49 | } 50 | }; 51 | 52 | /** 53 | * CountDownLatch create a count down latch 54 | * 55 | * @param {Number} count count down number 56 | * @param {Function} cb callback function 57 | * @api public 58 | */ 59 | module.exports.createCountDownLatch = function(count, cb) { 60 | if (!count || count <= 0) { 61 | logger.error('count should be positive.'); 62 | return; 63 | } 64 | if (typeof cb !== 'function') { 65 | logger.error('cb should be a function.'); 66 | return; 67 | } 68 | 69 | return new CountDownLatch(count, cb); 70 | }; -------------------------------------------------------------------------------- /lib/util/domainFactory.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao DomainFactory 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var utils = require('./utils'); 15 | 16 | var DomainFactory = {}; 17 | 18 | module.exports = DomainFactory; 19 | 20 | /** 21 | * DomainFactory get domain object with domainConfig 22 | * 23 | * @param {Object} domainConfig 24 | * @return {Object} domain object 25 | * @api public 26 | */ 27 | DomainFactory.getDomain = function(domainConfig) { 28 | var func = domainConfig['func']; 29 | 30 | if (utils.checkFunction(func)) { 31 | return new func(); 32 | } 33 | 34 | return null; 35 | } -------------------------------------------------------------------------------- /lib/util/fieldUtil.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao FieldConfig 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var FieldConfig = require('../support/fieldConfig'); 15 | 16 | var FieldUtil = {}; 17 | 18 | /** 19 | * FieldUtil build field config from domain 20 | * 21 | * @param {Array} list domain array 22 | * @return {Array} field array 23 | * @api public 24 | */ 25 | FieldUtil.buildFieldConfig = function(list) { 26 | var r = []; 27 | 28 | if (!list || !Array.isArray(list)) { 29 | return r; 30 | } 31 | 32 | for (var i = 0; i < list.length; i++) { 33 | var w = list[i]; 34 | 35 | var fieldConfig = new FieldConfig(); 36 | 37 | if (typeof w === 'object') { 38 | if (w.name) { 39 | fieldConfig.setName(w.name); 40 | } 41 | 42 | if (w.type) { 43 | fieldConfig.setType(w.type); 44 | } 45 | 46 | } 47 | 48 | if (typeof w === 'string') { 49 | fieldConfig.setName(w); 50 | } 51 | 52 | r.push(fieldConfig); 53 | } 54 | 55 | return r; 56 | } 57 | 58 | /** 59 | * FieldUtil field config array to names array 60 | * 61 | * @param {Array} field array 62 | * @return {Array} name array 63 | * @api public 64 | */ 65 | FieldUtil.fieldToNames = function(list) { 66 | var r = []; 67 | 68 | for (var i = 0; i < list.length; i++) { 69 | r.push(list[i].getName()); 70 | } 71 | 72 | return r; 73 | } 74 | 75 | module.exports = FieldUtil; -------------------------------------------------------------------------------- /lib/util/fileUtil.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao FileUtil 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var fs = require('fs'); 15 | 16 | var FileUtil = {}; 17 | 18 | FileUtil.readFileSync = function(path) { 19 | return fs.readFileSync(path).toString(); 20 | } 21 | 22 | /** 23 | * FileUtil readDirSync 24 | 25 | * @param {String} path 26 | * @return {Array} file paths. 27 | */ 28 | FileUtil.readDirSync = function(path) { 29 | var files = fs.readdirSync(path); 30 | return files; 31 | } 32 | 33 | /** 34 | * FileUtil Check isFile 35 | 36 | * @param {String} path 37 | * @return {Boolean} true|false. 38 | */ 39 | FileUtil.isFile = function(path) { 40 | if (fs.existsSync(path)) { 41 | return fs.statSync(path).isFile(); 42 | } 43 | }; 44 | 45 | /** 46 | * FileUtil Check isDir 47 | 48 | * @param {String} path 49 | * @return {Boolean} true|false. 50 | */ 51 | FileUtil.isDir = function(path) { 52 | if (fs.existsSync(path)) { 53 | return fs.statSync(path).isDirectory(); 54 | } 55 | }; 56 | 57 | FileUtil.mkDirSync = function(path) { 58 | return fs.mkdirSync(path); 59 | } 60 | 61 | FileUtil.readDirFiles = function(fpath, results) { 62 | var files = fs.readdirSync(fpath); 63 | 64 | for (var i = 0; i < files.length; i++) { 65 | var filepath = fpath + '/' + files[i]; 66 | 67 | if (this.isDir(filepath)) { 68 | this.readDirFiles(filepath, results); 69 | } 70 | 71 | if (this.isFile(filepath)) { 72 | results.push(filepath); 73 | } 74 | } 75 | } 76 | 77 | /** 78 | * FileUtil Check file suffix 79 | 80 | * @param {String} fn file name 81 | * @param {String} suffix suffix string, such as .js, etc. 82 | */ 83 | FileUtil.checkFileType = function(fn, suffix) { 84 | if (suffix.charAt(0) !== '.') { 85 | suffix = '.' + suffix; 86 | } 87 | 88 | if (fn.length <= suffix.length) { 89 | return false; 90 | } 91 | 92 | var str = fn.substring(fn.length - suffix.length).toLowerCase(); 93 | suffix = suffix.toLowerCase(); 94 | return str === suffix; 95 | }; 96 | 97 | /** 98 | * FileUtil Check file exists 99 | 100 | * @param {String} file path 101 | * @param {Boolean} true|false. 102 | */ 103 | FileUtil.existsSync = function(path) { 104 | return fs.existsSync(path); 105 | } 106 | 107 | module.exports = FileUtil; -------------------------------------------------------------------------------- /lib/util/shardingUtil.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao ShardingUtil 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var logger = require('pomelo-logger').getLogger('bearcat-dao', 'ShardingUtil'); 15 | var Constant = require('./constant'); 16 | var FileUtil = require('./fileUtil'); 17 | var Utils = require('./utils'); 18 | var Path = require('path'); 19 | 20 | var ShardingUtil = function() { 21 | this.clusterMap = null; 22 | this.destDBAll = []; 23 | this.destDBMap = {}; 24 | this.shardingFile = null; 25 | } 26 | 27 | ShardingUtil.prototype.getClusterMap = function() { 28 | var clusterMap = this.clusterMap; 29 | if (!clusterMap) { 30 | var bearcat = Utils.getBearcat(); 31 | var applicationContext = bearcat.getApplicationContext(); 32 | var env = applicationContext.getEnv(); 33 | var configPath = applicationContext.getConfigPath(); 34 | 35 | var shardingFile = this.shardingFile || Constant.CLUSTER_MAP_PATH; 36 | var clusterShardingPath = Path.join(configPath, env, shardingFile); 37 | 38 | if (!FileUtil.existsSync(clusterShardingPath)) { 39 | logger.warn('getClusterMap [type]Sharding.json (type=redis, mysql) file %s is not exist ...', clusterShardingPath); 40 | return; 41 | } 42 | 43 | clusterMap = require(clusterShardingPath); 44 | this.initClusterMap(clusterMap); 45 | this.clusterMap = clusterMap; 46 | } 47 | 48 | return clusterMap; 49 | } 50 | 51 | ShardingUtil.prototype.initClusterMap = function(clusterMap) { 52 | for (var i = 0; i < clusterMap.length; i++) { 53 | var map = clusterMap[i]; 54 | var name = map['name']; 55 | if (!this.destDBMap[name]) { 56 | this.destDBMap[name] = true; 57 | this.destDBAll.push(name); 58 | } 59 | } 60 | } 61 | 62 | ShardingUtil.prototype.getDestDBAll = function() { 63 | if (!this.clusterMap) { 64 | this.getClusterMap(); 65 | } 66 | 67 | return this.destDBAll; 68 | } 69 | 70 | var mysqlSharding = null; 71 | var redisSharding = null; 72 | 73 | module.exports = function(type) { 74 | if (type == 'mysql') { 75 | if (!mysqlSharding) { 76 | mysqlSharding = new ShardingUtil(); 77 | mysqlSharding['shardingFile'] = Constant.MYSQL_CLUSTER_MAP_PATH; 78 | } 79 | 80 | return mysqlSharding; 81 | } 82 | 83 | if (type == 'redis') { 84 | if (!redisSharding) { 85 | redisSharding = new ShardingUtil(); 86 | redisSharding['shardingFile'] = Constant.REDIS_CLUSTER_MAP_PATH; 87 | } 88 | 89 | return redisSharding; 90 | } 91 | } -------------------------------------------------------------------------------- /lib/util/sqlBuilderUtil.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao SqlBuilderUtil 10 | * Copyright(c) 2014 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var BearcatDao = require('../bearcat-dao'); 15 | var Constant = require('./constant'); 16 | var Utils = require('./utils'); 17 | 18 | var SqlBuilderUtil = {}; 19 | 20 | module.exports = SqlBuilderUtil; 21 | 22 | /** 23 | * SqlBuilderUtil build insert sql 24 | * 25 | * @param {String} tableName table name 26 | * @param {Array} columns column names 27 | * @param {String} sql result 28 | * @api public 29 | */ 30 | SqlBuilderUtil.buildInsertSql = function(tableName, columns) { 31 | return SqlBuilderUtil.buildBatchInsertSql(tableName, columns, 1); 32 | } 33 | 34 | /** 35 | * SqlBuilderUtil build batch insert sql 36 | * 37 | * @param {String} tableName table name 38 | * @param {Array} columns column names 39 | * @param {Number} batchSize batch size 40 | * @return {String} sql result 41 | * @api private 42 | */ 43 | SqlBuilderUtil.buildBatchInsertSql = function(tableName, columns, batchSize) { 44 | var result = ""; 45 | 46 | result += "insert into "; 47 | result += tableName; 48 | result += " ("; 49 | result += SqlBuilderUtil.prepareConditionSql(null, null, columns, null, ", "); 50 | result += ") values "; 51 | result += (SqlBuilderUtil.prepareRepeatSql(null, null, 52 | SqlBuilderUtil.prepareRepeatSql("(", ")", "?", ", ", columns.length), ", ", 53 | batchSize)); 54 | 55 | return result; 56 | } 57 | 58 | /** 59 | * SqlBuilderUtil build update sql 60 | * 61 | * @param {String} tableName table name 62 | * @param {Array} normalColumns normal column names 63 | * @param {Array} primaryColumns primary column names 64 | * @return {String} sql result 65 | * @api public 66 | */ 67 | SqlBuilderUtil.buildUpdateSql = function(tableName, normalColumns, primaryColumns) { 68 | var result = ""; 69 | 70 | result += "update "; 71 | result += tableName; 72 | result += " set "; 73 | result += SqlBuilderUtil.prepareConditionSql(null, null, normalColumns, " = ?", ","); 74 | result += " where "; 75 | result += SqlBuilderUtil.prepareConditionSql(null, null, primaryColumns, " = ?", " and "); 76 | 77 | return result; 78 | } 79 | 80 | /** 81 | * SqlBuilderUtil build select prefix 82 | * 83 | * @param {String} tableName table name 84 | * @param {Array} columns column names 85 | * @return {String} select prefix 86 | * @api private 87 | */ 88 | SqlBuilderUtil.buildSelectPrefix = function(tableName, columns) { 89 | var result = ""; 90 | result += "select "; 91 | if (!columns || !columns.length) { 92 | result += "*"; 93 | } else { 94 | result += SqlBuilderUtil.prepareConditionSql(null, null, columns, null, ","); 95 | } 96 | result += " from "; 97 | result += tableName; 98 | result += " where "; 99 | 100 | return result; 101 | } 102 | 103 | /** 104 | * SqlBuilderUtil build select sql 105 | * 106 | * @param {String} tableName table name 107 | * @param {Array} columns column names 108 | * @param {Array} primaryColumns primary column names 109 | * @param {Number} quantity quantity number 110 | * @return {String} sql result 111 | * @api public 112 | */ 113 | SqlBuilderUtil.buildSelectSql = function(tableName, columns, primaryColumns, quantity) { 114 | if (!quantity) { 115 | quantity = 1; 116 | } 117 | 118 | var result = ""; 119 | result += SqlBuilderUtil.buildSelectPrefix(tableName, columns); 120 | 121 | for (var i = 0; i < quantity; i++) { 122 | result += "("; 123 | result += SqlBuilderUtil.prepareConditionSql(null, null, primaryColumns, " = ?", " and "); 124 | result += ")"; 125 | if (i < (quantity - 1)) { 126 | result += " or "; 127 | } 128 | } 129 | 130 | return result; 131 | } 132 | 133 | /** 134 | * SqlBuilderUtil build delete sql 135 | * 136 | * @param {String} tableName table name 137 | * @param {Array} columns column names 138 | * @return {String} sql result 139 | * @api public 140 | */ 141 | SqlBuilderUtil.buildDeleteSql = function(tableName, columns) { 142 | return SqlBuilderUtil.buildBatchDeleteSql(tableName, columns, 1); 143 | } 144 | 145 | /** 146 | * SqlBuilderUtil build insert sql 147 | * 148 | * @param {String} tableName table name 149 | * @param {Array} columns column names 150 | * @param {Number} batchSize batch size 151 | * @return {String} sql result 152 | * @api private 153 | */ 154 | SqlBuilderUtil.buildBatchDeleteSql = function(tableName, columns, batchSize) { 155 | var result = ""; 156 | 157 | result += "delete from "; 158 | result += tableName; 159 | result += " where "; 160 | result += (SqlBuilderUtil.prepareRepeatSql(null, null, 161 | SqlBuilderUtil.prepareConditionSql("(", ")", columns, " = ?", " and "), 162 | " or ", batchSize)); 163 | 164 | return result; 165 | } 166 | 167 | /** 168 | * SqlBuilderUtil append order to sql 169 | * 170 | * @param {String} sql 171 | * @param {String} orderColumn order column 172 | * @return {String} isAsc sql result 173 | * @api private 174 | */ 175 | SqlBuilderUtil.appendOrder = function(sql, orderColumn, isAsc) { 176 | var result = ""; 177 | 178 | if (orderColumn != null) { 179 | result += (" order by "); 180 | result += (orderColumn); 181 | } 182 | if (isAsc != null) { 183 | if (isAsc) { 184 | result += (" asc"); 185 | } else { 186 | result += (" desc"); 187 | } 188 | } 189 | 190 | return sql + result; 191 | } 192 | 193 | /** 194 | * SqlBuilderUtil append limit to sql 195 | * 196 | * @param {String} sql 197 | * @param {Number} limit limit number 198 | * @param {Number} offset offset number 199 | * @return {String} sql result 200 | * @api private 201 | */ 202 | SqlBuilderUtil.appendLimit = function(sql, limit, offset) { 203 | var result = ""; 204 | 205 | if (limit > 0) { 206 | result += (" limit "); 207 | result += (limit); 208 | } 209 | if (offset > 0) { 210 | result += (" offset "); 211 | result += (offset); 212 | } 213 | return sql + result; 214 | } 215 | 216 | /** 217 | * SqlBuilderUtil prepare condition to sql 218 | * 219 | * @param {String} prefix 220 | * @param {String} suffix 221 | * @param {Array} columns 222 | * @param {String} extra 223 | * @param {String} join 224 | * @return {String} condition sql 225 | * @api private 226 | */ 227 | SqlBuilderUtil.prepareConditionSql = function(prefix, suffix, columns, extra, join) { 228 | var result = ""; 229 | if (prefix) { 230 | result += prefix; 231 | } 232 | 233 | for (var i = 0; i < columns.length; i++) { 234 | if (i > 0) { 235 | result += join; 236 | } 237 | result += columns[i]; 238 | if (extra) { 239 | result += extra; 240 | } 241 | } 242 | 243 | if (suffix) { 244 | result += suffix; 245 | } 246 | 247 | return result; 248 | } 249 | 250 | /** 251 | * SqlBuilderUtil prepare repeat to sql 252 | * 253 | * @param {String} prefix 254 | * @param {String} suffix 255 | * @param {Number} repeat repeat number 256 | * @param {String} join 257 | * @param {Number} times times number 258 | * @return {String} repeat sql result 259 | * @api private 260 | */ 261 | SqlBuilderUtil.prepareRepeatSql = function(prefix, suffix, repeat, join, times) { 262 | var result = ""; 263 | if (prefix) { 264 | result += prefix; 265 | } 266 | 267 | for (var i = 0; i < times; i++) { 268 | if (i > 0) { 269 | result += join; 270 | } 271 | result += repeat; 272 | } 273 | 274 | if (suffix) { 275 | result += suffix; 276 | } 277 | 278 | return result; 279 | } 280 | 281 | /** 282 | * SqlBuilderUtil get sql 283 | * 284 | * @param {String} sql with $ prefix or real sql 285 | * @return {String} real sql 286 | * @api private 287 | */ 288 | SqlBuilderUtil.getSql = function(sql) { 289 | if (!Utils.checkString(sql)) { 290 | return; 291 | } 292 | 293 | var prefix = sql[0]; 294 | var r = sql; 295 | 296 | if (prefix === Constant.DOLLAR_PREFIX) { 297 | var sqlId = sql.substr(1); 298 | r = BearcatDao.getSQL(sqlId); 299 | } 300 | 301 | return r; 302 | } -------------------------------------------------------------------------------- /lib/util/sqlUtil.js: -------------------------------------------------------------------------------- 1 | var Mysql = require('mysql'); 2 | var bearcatSQL = require('bearcat-sql'); 3 | 4 | var SqlUtil = {}; 5 | 6 | SqlUtil.format = function(sql, params) { 7 | return Mysql.format(sql, params); 8 | } 9 | 10 | SqlUtil.parse = function(sql) { 11 | return bearcatSQL.parseSQL(sql); 12 | } 13 | 14 | SqlUtil.getRelate = function(relate) { 15 | return bearcatSQL.RELATE_MAP[relate]; 16 | } 17 | 18 | module.exports = SqlUtil; -------------------------------------------------------------------------------- /lib/util/utils.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * .______ _______ ___ .______ ______ ___ .__________. 3 | * ( _ ) ( ____) / \ ( _ ) ( ) / \ ( ) 4 | * | |_) ) | |__ / ^ \ | |_) ) | ,----' / ^ \ `---| |---` 5 | * | _ < | __) / /_\ \ | ) | | / /_\ \ | | 6 | * | |_) ) | |____ / _____ \ | |) ----.| `----./ _____ \ | | 7 | * (______) (_______/__/ \__\ ( _| `.____) (______)__/ \__\ |__| 8 | * 9 | * Bearcat-dao Utils 10 | * Copyright(c) 2015 fantasyni 11 | * MIT Licensed 12 | */ 13 | 14 | var crc = require('redis-crc'); 15 | var Utils = {}; 16 | var bearcat; 17 | 18 | /** 19 | * Utils check type 20 | * 21 | * @param {String} type 22 | * @return {Function} high order function 23 | * @api public 24 | */ 25 | Utils.isType = function(type) { 26 | return function(obj) { 27 | return {}.toString.call(obj) == "[object " + type + "]"; 28 | } 29 | } 30 | 31 | /** 32 | * Utils check array 33 | * 34 | * @param {Array} array 35 | * @return {Boolean} true|false 36 | * @api public 37 | */ 38 | Utils.checkArray = Array.isArray || Utils.isType("Array"); 39 | 40 | /** 41 | * Utils check number 42 | * 43 | * @param {Number} number 44 | * @return {Boolean} true|false 45 | * @api public 46 | */ 47 | Utils.checkNumber = Utils.isType("Number"); 48 | 49 | /** 50 | * Utils check function 51 | * 52 | * @param {Function} func function 53 | * @return {Boolean} true|false 54 | * @api public 55 | */ 56 | Utils.checkFunction = Utils.isType("Function"); 57 | /** 58 | * Utils check object 59 | * 60 | * @param {Object} obj object 61 | * @return {Boolean} true|false 62 | * @api public 63 | */ 64 | Utils.checkObject = Utils.isType("Object"); 65 | 66 | /** 67 | * Utils check string 68 | * 69 | * @param {String} string 70 | * @return {Boolean} true|false 71 | * @api public 72 | */ 73 | Utils.checkString = Utils.isType("String"); 74 | 75 | /** 76 | * Utils check boolean 77 | * 78 | * @param {Object} obj object 79 | * @return {Boolean} true|false 80 | * @api public 81 | */ 82 | Utils.checkBoolean = Utils.isType("Boolean"); 83 | 84 | /** 85 | * Utils args to array 86 | * 87 | * @param {Object} args arguments 88 | * @return {Array} array 89 | * @api public 90 | */ 91 | Utils.to_array = function(args) { 92 | var len = args.length; 93 | var arr = new Array(len); 94 | 95 | for (var i = 0; i < len; i++) { 96 | arr[i] = args[i]; 97 | } 98 | 99 | return arr; 100 | } 101 | 102 | /** 103 | * Utils check is not null 104 | * 105 | * @param {Object} value 106 | * @return {Boolean} true|false 107 | * @api public 108 | */ 109 | Utils.isNotNull = function(value) { 110 | if (value !== null && typeof value !== 'undefined') 111 | return true; 112 | return false; 113 | } 114 | 115 | Utils.getBearcat = function() { 116 | if (bearcat) { 117 | return bearcat; 118 | } 119 | 120 | try { 121 | bearcat = require('bearcat'); 122 | } catch (e) { 123 | console.error(e); 124 | } 125 | return bearcat; 126 | } 127 | 128 | /** 129 | * Utils check model filter error 130 | * 131 | * @return {Boolean} true|false 132 | * @api public 133 | */ 134 | Utils.checkModelFilterError = function(r) { 135 | return r !== true && this.isNotNull(r); 136 | } 137 | 138 | /** 139 | * Utils calculate hash value 140 | * 141 | * @param {String} hash key 142 | * @param {Number} num 143 | * @return {String} hash value 144 | * @api public 145 | */ 146 | Utils.calHashValue = function(key, num) { 147 | var value = crc.keyHashSlot(key, key.length, num); 148 | return value; 149 | } 150 | 151 | module.exports = Utils; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bearcat-dao", 3 | "version": "0.2.12", 4 | "description": "SQL mapping dao framework", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "grunt" 8 | }, 9 | "keywords": [ 10 | "dao", 11 | "framework", 12 | "sql", 13 | "sql mapping", 14 | "transaction" 15 | ], 16 | "dependencies": { 17 | "pomelo-logger": "0.1.x", 18 | "async": "^0.9.0", 19 | "redis": "0.12.x", 20 | "mysql": "2.6.x", 21 | "bearcat-ha": "0.1.x", 22 | "bearcat-sql": "0.1.x", 23 | "redis-crc": "0.1.x" 24 | }, 25 | "author": "fantasyni", 26 | "license": "MIT", 27 | "devDependencies": { 28 | "bearcat": "0.4.x", 29 | "should": ">=0.0.1", 30 | "mocha": ">=0.0.1", 31 | "socket.io-client": ">=0.0.1", 32 | "blanket": "1.1.x", 33 | "jscoverage": ">=0.0.1", 34 | "muk": ">=0.0.1", 35 | "grunt": "~0.4.2", 36 | "grunt-mocha-test": "0.8.x", 37 | "grunt-jscoverage": "0.0.3", 38 | "grunt-contrib-clean": "0.5.x", 39 | "grunt-contrib-jshint": "~0.8.0" 40 | } 41 | } -------------------------------------------------------------------------------- /test-context.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bearcat-dao", 3 | "scan": ["test/mock/model"], 4 | "beans": [{ 5 | "id": "domainDaoSupport", 6 | "func": "lib.core.domainDaoSupport", 7 | "scope": "prototype", 8 | "props": [{ 9 | "name": "sqlTemplate", 10 | "ref": "sqlTemplate" 11 | }, { 12 | "name": "cacheTemplate", 13 | "ref": "cacheTemplate" 14 | }] 15 | }, { 16 | "id": "sqlTemplate", 17 | "func": "lib.template.sql.mysqlTemplate", 18 | "props": [{ 19 | "name": "connectionManager", 20 | "ref": "mysqlConnectionManager" 21 | }, { 22 | "name": "transactionManager", 23 | "ref": "dbTransactionManager" 24 | }] 25 | }, { 26 | "id": "cacheTemplate", 27 | "func": "lib.template.cache.redisTemplate", 28 | "props": [{ 29 | "name": "connectionManager", 30 | "ref": "redisConnectionManager" 31 | }] 32 | }, { 33 | "id": "mysqlConnectionManager", 34 | "func": "lib.connection.sql.mysqlConnectionManager", 35 | "proxy": false, 36 | "props": [{ 37 | "name": "port", 38 | "value": 5331 39 | }, { 40 | "name": "host", 41 | "value": "localhost" 42 | }, { 43 | "name": "user", 44 | "value": "root" 45 | }, { 46 | "name": "password", 47 | "value": "test" 48 | }, { 49 | "name": "database", 50 | "value": "bearcat_dao_test" 51 | }] 52 | }, { 53 | "id": "redisConnectionManager", 54 | "func": "lib.connection.cache.redisConnectionManager" 55 | }, { 56 | "id": "dbTransactionManager", 57 | "func": "lib.transaction.dbTransactionManager", 58 | "props": [{ 59 | "name": "connectionManager", 60 | "ref": "mysqlConnectionManager" 61 | }], 62 | "proxy": false 63 | }, { 64 | "id": "transactionAspect", 65 | "func": "lib.aspect.transactionAspect", 66 | "props": [{ 67 | "name": "dbTransactionManager", 68 | "ref": "dbTransactionManager" 69 | }], 70 | "aop": [{ 71 | "pointcut": "around:.*?Transaction$", 72 | "advice": "doInTransaction" 73 | }] 74 | }, { 75 | "id": "personDao", 76 | "func": "test.transaction.dao.personDao", 77 | "props": [{ 78 | "name": "domainDaoSupport", 79 | "ref": "domainDaoSupport" 80 | }], 81 | "init": "init" 82 | }, { 83 | "id": "personService", 84 | "func": "test.transaction.service.personService", 85 | "props": [{ 86 | "name": "personDao", 87 | "ref": "personDao" 88 | }] 89 | }, { 90 | "id": "person1Dao", 91 | "func": "test.transaction.dao.person1Dao", 92 | "props": [{ 93 | "name": "domainDaoSupport", 94 | "ref": "domainDaoSupport" 95 | }], 96 | "init": "init" 97 | }] 98 | } -------------------------------------------------------------------------------- /test-ddb-context.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bearcat-dao", 3 | "scan": ["test/mock/model/ddb"], 4 | "beans": [{ 5 | "id": "sqlTemplate", 6 | "func": "lib.template.sql.ddbTemplate", 7 | "props": [{ 8 | "name": "planManager", 9 | "ref": "planManager" 10 | }] 11 | }, { 12 | "id": "ddbConnectionManager", 13 | "func": "lib.connection.sql.ddbConnectionManager", 14 | "proxy": false, 15 | "props": [{ 16 | "name": "user", 17 | "value": "san" 18 | }, { 19 | "name": "password", 20 | "value": "bearcat" 21 | }, { 22 | "name": "zkServers", 23 | "value": "${zk.servers}" 24 | }, { 25 | "name": "zkChroot", 26 | "value": "${zk.chroot}" 27 | }] 28 | }, { 29 | "id": "planManager", 30 | "func": "lib.plan.planManager", 31 | "props": [{ 32 | "name": "connectionManager", 33 | "ref": "ddbConnectionManager" 34 | }] 35 | }, { 36 | "id": "redisConnectionManager", 37 | "func": "lib.connection.cache.redisClusterConnectionManager", 38 | "proxy": false, 39 | "props": [{ 40 | "name": "zkServers", 41 | "value": "${zk.servers}" 42 | }, { 43 | "name": "zkChroot", 44 | "value": "${zk.chroot}" 45 | }] 46 | }, { 47 | "id": "redisTemplate", 48 | "func": "lib.template.cache.redisClusterTemplate", 49 | "props": [{ 50 | "name": "connectionManager", 51 | "ref": "redisConnectionManager" 52 | }], 53 | "init": "init" 54 | }] 55 | } -------------------------------------------------------------------------------- /test/aspect/transactionAspect.js: -------------------------------------------------------------------------------- 1 | var TransactionAspect = require('../../lib/aspect/transactionAspect'); 2 | var should = require('should'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('TransactionAspect right', function() { 6 | it('should do transactionAspect right', function(done) { 7 | var transactionAspect = new TransactionAspect(); 8 | transactionAspect.setDbTransactionManager(); 9 | transactionAspect.getDbTransactionManager(); 10 | 11 | done(); 12 | }); 13 | }); 14 | }); -------------------------------------------------------------------------------- /test/bearcat-dao.js: -------------------------------------------------------------------------------- 1 | var bearcatDao = require('../../bearcat-dao'); 2 | var should = require('should'); 3 | var path = require('path'); 4 | 5 | describe('bearcat-dao', function() { 6 | describe('getSQL loadSQL addConfiglocations', function() { 7 | it('should getSQL loadSQL addConfiglocations right', function(done) { 8 | var sqlPath = require.resolve('./mock/schema.sql'); 9 | var sqlDirPath = path.dirname(sqlPath); 10 | 11 | bearcatDao.loadSQL(); 12 | bearcatDao.loadSQL([sqlDirPath]); 13 | var blogResultTable = bearcatDao.getSQL('blogResultTable'); 14 | blogResultTable = blogResultTable.trim(); 15 | blogResultTable.should.eql('blog, author'); 16 | 17 | var blogResultList1 = bearcatDao.getSQL('blogResultList1'); 18 | blogResultList1 = blogResultList1.trim(); 19 | console.log(blogResultList1); 20 | 21 | var blogResultList2 = bearcatDao.getSQL('blogResultList2'); 22 | blogResultList2 = blogResultList2.trim(); 23 | console.log(blogResultList2); 24 | 25 | done(); 26 | }); 27 | 28 | it('should getSQL error right', function(done) { 29 | bearcatDao.getSQL(); 30 | bearcatDao.getSQL('xxx'); 31 | bearcatDao.getSQL('authorResult'); 32 | bearcatDao.getSQL('authorResultLaw'); 33 | 34 | done(); 35 | }); 36 | }); 37 | }); -------------------------------------------------------------------------------- /test/connection/cache/redisConnectionManager.js: -------------------------------------------------------------------------------- 1 | var RedisConnectionManager = require('../../../lib/connection/cache/redisConnectionManager'); 2 | var should = require('should'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('redisConnectionManager', function() { 6 | it('should getConnection right', function(done) { 7 | var redisConnectionManager = new RedisConnectionManager(); 8 | 9 | var connection = redisConnectionManager.getConnection(); 10 | 11 | should.exist(connection); 12 | redisConnectionManager.on('ready', function() { 13 | redisConnectionManager.release(connection); 14 | done(); 15 | }); 16 | }); 17 | }); 18 | }); -------------------------------------------------------------------------------- /test/connection/sql/mysqlConnectionManager.js: -------------------------------------------------------------------------------- 1 | var MysqlConnectionManager = require('../../../lib/connection/sql/mysqlConnectionManager'); 2 | var should = require('should'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('mysqlConnectionManager', function() { 6 | it('should getConnection right', function(done) { 7 | var mysqlConnectionManager = new MysqlConnectionManager(); 8 | mysqlConnectionManager.setPort(5331); 9 | mysqlConnectionManager.setUser('root'); 10 | mysqlConnectionManager.setPassword('test'); 11 | mysqlConnectionManager.setDatabase('test'); 12 | 13 | mysqlConnectionManager.getConnection(function(err, connection) { 14 | should.not.exist(err); 15 | should.exist(connection); 16 | mysqlConnectionManager.destroy(connection); 17 | done(); 18 | }); 19 | }); 20 | 21 | it('should getConnection not right', function(done) { 22 | var mysqlConnectionManager = new MysqlConnectionManager(); 23 | mysqlConnectionManager.setUser('root'); 24 | mysqlConnectionManager.setPassword('tst'); 25 | mysqlConnectionManager.setDatabase('test'); 26 | 27 | mysqlConnectionManager.getConnection(function(err, connection) { 28 | console.error(err); 29 | should.exist(err); 30 | should.not.exist(connection); 31 | done(); 32 | }); 33 | }); 34 | 35 | it('should do not use pool', function(done) { 36 | var mysqlConnectionManager = new MysqlConnectionManager(); 37 | mysqlConnectionManager.setPort(5331); 38 | mysqlConnectionManager.setUsePool(false); 39 | mysqlConnectionManager.setUser('root'); 40 | mysqlConnectionManager.setPassword('test'); 41 | mysqlConnectionManager.setDatabase('test'); 42 | 43 | mysqlConnectionManager.getConnection(function(err, connection) { 44 | should.not.exist(err); 45 | should.exist(connection); 46 | mysqlConnectionManager.release(connection); 47 | done(); 48 | }); 49 | }); 50 | 51 | it('should set get right', function(done) { 52 | var mysqlConnectionManager = new MysqlConnectionManager(); 53 | mysqlConnectionManager.setPort(5331); 54 | mysqlConnectionManager.getPort(); 55 | mysqlConnectionManager.setHost('localhost'); 56 | mysqlConnectionManager.getHost(); 57 | mysqlConnectionManager.setUser('root'); 58 | mysqlConnectionManager.getUser(); 59 | mysqlConnectionManager.setPassword('test'); 60 | mysqlConnectionManager.getPassword(); 61 | mysqlConnectionManager.setDatabase('test'); 62 | mysqlConnectionManager.getDatabase(); 63 | mysqlConnectionManager.getUsePool(); 64 | mysqlConnectionManager.getPool(); 65 | mysqlConnectionManager.setOptions(); 66 | mysqlConnectionManager.getOptions(); 67 | 68 | mysqlConnectionManager.getConnection(function(err, connection) { 69 | should.not.exist(err); 70 | should.exist(connection); 71 | mysqlConnectionManager.fetchConnector(); 72 | mysqlConnectionManager.end(connection); 73 | done(); 74 | }); 75 | }); 76 | }) 77 | }); -------------------------------------------------------------------------------- /test/core/debug.js: -------------------------------------------------------------------------------- 1 | var Bearcat = require('bearcat'); 2 | var personDomain = require('../mock/domain/person'); 3 | var joinPersonDomain = require('../mock/domain/joinPerson'); 4 | var domainFactory = require('../../lib/util/domainFactory'); 5 | var simplepath = require.resolve('../../test-context.json'); 6 | var path = require('path'); 7 | var paths = [simplepath]; 8 | var bearcatDao = require('../../lib/bearcat-dao'); 9 | var bearcat = Bearcat.createApp(paths); 10 | var tableName = "bearcat_dao_test"; 11 | var sqlPath = require.resolve('../mock/schema.sql'); 12 | var sqlDirPath = path.dirname(sqlPath); 13 | 14 | bearcatDao.loadSQL([sqlDirPath]); 15 | 16 | process.env.LOGGER_LINE = true; 17 | process.env.BEARCAT_DEBUG = true; 18 | bearcat.start(function() { 19 | var domainDaoSupport = bearcat.getBean('domainDaoSupport'); 20 | domainDaoSupport.initConfig("person"); 21 | 22 | var id = 1; 23 | // domainDaoSupport.getList("$blogResultSql", id, "blogResult", function(err, results) { 24 | // err = err || true; 25 | // console.log(err.stack); 26 | 27 | // // console.log(results); 28 | // var blogResult = results; 29 | // blogResult.run(); 30 | // // console.log(blogResult); 31 | // }) 32 | var domainDaoSupport = bearcat.getBean('domainDaoSupport'); 33 | domainDaoSupport.initConfig(personDomain); 34 | var person1 = domainFactory.getDomain(personDomain); 35 | person1.setName('yyy'); 36 | person1.setNum(100); 37 | person1.setCreateAt(Date.now()); 38 | 39 | var list = []; 40 | list.push(person1); 41 | 42 | var person2 = domainFactory.getDomain(personDomain); 43 | person2.setName('bbb'); 44 | person2.setNum(200); 45 | person2.setCreateAt(Date.now()); 46 | 47 | list.push(person2); 48 | 49 | var person3 = domainFactory.getDomain(personDomain); 50 | person3.setId(Date.now() / 1000); 51 | person3.setName('ccc'); 52 | person3.setNum(300); 53 | person3.setCreateAt(Date.now()); 54 | 55 | list.push(person3); 56 | 57 | domainDaoSupport.batchAdd(list, function(err, results) { 58 | console.log(err); 59 | }); 60 | }); -------------------------------------------------------------------------------- /test/debug.js: -------------------------------------------------------------------------------- 1 | var bearcatDao = require('../../bearcat-dao'); 2 | var path = require('path'); 3 | 4 | var sqlPath = require.resolve('./mock/schema.sql'); 5 | var sqlDirPath = path.dirname(sqlPath); 6 | 7 | bearcatDao.loadSQL([sqlDirPath]); 8 | var blogResultTable = bearcatDao.getSQL('blogResultTable'); 9 | console.log(blogResultTable) -------------------------------------------------------------------------------- /test/loader/debug.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bearcatjs/bearcat-dao/5affc25fd2705e3aeaca5e82ad6ac21fdaa4c0af/test/loader/debug.js -------------------------------------------------------------------------------- /test/loader/sqlLoader.js: -------------------------------------------------------------------------------- 1 | var SqlLoader = require('../../lib/loader/sqlLoader'); 2 | var should = require('should'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('sqlLoader', function() { 6 | it('should do sqlLoader right', function(done) { 7 | var sqlLoader = new SqlLoader(); 8 | sqlLoader.loadContent(); 9 | 10 | done(); 11 | }); 12 | }); 13 | }); -------------------------------------------------------------------------------- /test/mock/domain/joinPerson.js: -------------------------------------------------------------------------------- 1 | var joinPerson = function() { 2 | this.id = null; 3 | this.num = null; 4 | } 5 | 6 | joinPerson.prototype.getId = function() { 7 | return this.id; 8 | } 9 | 10 | joinPerson.prototype.setId = function(id) { 11 | this.id = id; 12 | } 13 | 14 | joinPerson.prototype.getNum = function() { 15 | return this.num; 16 | } 17 | 18 | joinPerson.prototype.setNum = function(num) { 19 | this.num = num; 20 | } 21 | 22 | module.exports = { 23 | func: joinPerson, 24 | key: "joinPerson", 25 | primary: [{ 26 | name: "id", 27 | type: "Long" 28 | }], 29 | fields: ["num"] 30 | } -------------------------------------------------------------------------------- /test/mock/domain/person.js: -------------------------------------------------------------------------------- 1 | var person = function() { 2 | this.id = null; 3 | this.num = null; 4 | this.name = null; 5 | this.create_at = 0; 6 | } 7 | 8 | person.prototype.getId = function() { 9 | return this.id; 10 | } 11 | 12 | person.prototype.setId = function(id) { 13 | this.id = id; 14 | } 15 | 16 | person.prototype.getNum = function() { 17 | return this.num; 18 | } 19 | 20 | person.prototype.setNum = function(num) { 21 | this.num = num; 22 | } 23 | 24 | person.prototype.getName = function() { 25 | return this.name; 26 | } 27 | 28 | person.prototype.setName = function(name) { 29 | this.name = name; 30 | } 31 | 32 | person.prototype.getCreateAt = function() { 33 | return this.create_at; 34 | } 35 | 36 | person.prototype.setCreateAt = function(create_at) { 37 | this.create_at = create_at; 38 | } 39 | 40 | module.exports = { 41 | func: person, 42 | primary: [{ 43 | name: "id", 44 | type: "Long" 45 | }], 46 | fields: ["num", "name", "create_at"], 47 | tableName: "bearcat_dao_test" 48 | } -------------------------------------------------------------------------------- /test/mock/domain/person1.js: -------------------------------------------------------------------------------- 1 | var person1 = function() { 2 | this.id = null; 3 | this.name = null; 4 | this.create_at = 0; 5 | } 6 | 7 | person1.prototype.getId = function() { 8 | return this.id; 9 | } 10 | 11 | person1.prototype.setId = function(id) { 12 | this.id = id; 13 | } 14 | 15 | person1.prototype.getName = function() { 16 | return this.name; 17 | } 18 | 19 | person1.prototype.setName = function(name) { 20 | this.name = name; 21 | } 22 | 23 | person1.prototype.getCreateAt = function() { 24 | return this.create_at; 25 | } 26 | 27 | person1.prototype.setCreateAt = function(create_at) { 28 | this.create_at = create_at; 29 | } 30 | 31 | module.exports = { 32 | func: person1, 33 | primary: [{ 34 | name: "id", 35 | type: "Long" 36 | }, { 37 | name: "name", 38 | type: "String" 39 | }], 40 | fields: ["create_at"], 41 | tableName: "bearcat_dao_test1" 42 | } -------------------------------------------------------------------------------- /test/mock/domain/person2.js: -------------------------------------------------------------------------------- 1 | var person2 = function() { 2 | this.id = null; 3 | this.name = null; 4 | this.create_at = 0; 5 | } 6 | 7 | person2.prototype.getId = function() { 8 | return this.id; 9 | } 10 | 11 | person2.prototype.setId = function(id) { 12 | this.id = id; 13 | } 14 | 15 | person2.prototype.getName = function() { 16 | return this.name; 17 | } 18 | 19 | person2.prototype.setName = function(name) { 20 | this.name = name; 21 | } 22 | 23 | person2.prototype.getCreateAt = function() { 24 | return this.create_at; 25 | } 26 | 27 | person2.prototype.setCreateAt = function(create_at) { 28 | this.create_at = create_at; 29 | } 30 | 31 | module.exports = { 32 | func: person2, 33 | fields: ["create_at"], 34 | tableName: "bearcat_dao_test1" 35 | } -------------------------------------------------------------------------------- /test/mock/mock-redis.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bearcatjs/bearcat-dao/5affc25fd2705e3aeaca5e82ad6ac21fdaa4c0af/test/mock/mock-redis.js -------------------------------------------------------------------------------- /test/mock/model/authorModel.js: -------------------------------------------------------------------------------- 1 | var AuthorModel = function() { 2 | this.$mid = "author"; 3 | this.$table = "ba_author"; 4 | this.$prefix = "author_"; 5 | this.id = "$primary;type:Number"; 6 | this.name = "$type:String"; 7 | this.create_at = "$type:Number"; 8 | this.update_at = "$type:Number"; 9 | } 10 | 11 | module.exports = AuthorModel; -------------------------------------------------------------------------------- /test/mock/model/blogModel.js: -------------------------------------------------------------------------------- 1 | var BlogModel = function() { 2 | this.$mid = "blog"; 3 | this.$table = "ba_blog"; 4 | this.$prefix = "blog_"; 5 | this.id = "$primary;type:Number"; 6 | this.aid = "$type:Number"; 7 | this.title = "$type:String"; 8 | this.content = "$type:String"; 9 | this.create_at = "$type:Number"; 10 | this.update_at = "$type:Number"; 11 | } 12 | 13 | module.exports = BlogModel; -------------------------------------------------------------------------------- /test/mock/model/blogResultModel.js: -------------------------------------------------------------------------------- 1 | var BlogResultModel = function() { 2 | this.$mid = "blogResult"; 3 | // this.$prefix = "blog_"; 4 | this.blog = "$type:Object;ref:blog"; 5 | this.author = "$type:Object;ref:author"; 6 | this.comments = "$type:Array;ref:comment"; 7 | // this.commentResults = "$type:Array;ref:commentResult"; 8 | } 9 | 10 | BlogResultModel.prototype.run = function() { 11 | console.log("%j", this.blog); 12 | console.log("%j", this.author); 13 | console.log("%j", this.comments); 14 | // console.log("%j", this.commentResults); 15 | // console.log(this.comments) 16 | } 17 | 18 | module.exports = BlogResultModel; -------------------------------------------------------------------------------- /test/mock/model/commentModel.js: -------------------------------------------------------------------------------- 1 | var CommentModel = function() { 2 | this.$mid = "comment"; 3 | this.$table = "ba_comment"; 4 | this.$prefix = "comment_"; 5 | this.id = "$primary;type:Number"; 6 | this.aid = "$type:Number"; 7 | this.bid = "$type:Number"; 8 | this.content = "$type:String"; 9 | this.create_at = "$type:Number"; 10 | this.update_at = "$type:Number"; 11 | } 12 | 13 | module.exports = CommentModel; -------------------------------------------------------------------------------- /test/mock/model/ddb/blogModel.js: -------------------------------------------------------------------------------- 1 | var BlogModel = function() { 2 | this.$mid = "blog"; 3 | this.$table = "blog"; 4 | this.id = "$primary;balance;type:Number"; 5 | this.aid = "$type:Number"; 6 | this.title = "$type:String"; 7 | this.content = "$type:String"; 8 | this.create_at = "$type:Number"; 9 | this.update_at = "$type:Number"; 10 | } 11 | 12 | module.exports = BlogModel; -------------------------------------------------------------------------------- /test/mock/model/person.js: -------------------------------------------------------------------------------- 1 | var Person = function() { 2 | this.$mid = "person"; 3 | this.$table = "bearcat_dao_test"; 4 | this.id = "$primary;type:Number"; 5 | this.num = "$type:Number"; 6 | this.name = "$type:String"; 7 | this.create_at = "$type:Number"; 8 | } 9 | 10 | Person.prototype.getId = function() { 11 | return this.id; 12 | } 13 | 14 | Person.prototype.getName = function() { 15 | return this.name; 16 | } 17 | 18 | Person.prototype.getNum = function() { 19 | return this.num; 20 | } 21 | 22 | module.exports = Person; -------------------------------------------------------------------------------- /test/mock/model/person1.js: -------------------------------------------------------------------------------- 1 | var Person1 = function() { 2 | this.$mid = "person1"; 3 | this.$table = "bearcat_dao_test1"; 4 | this.id = "$primary;type:Number"; 5 | this.name = "$primary;type:String"; 6 | this.create_at = "$type:Number"; 7 | } 8 | 9 | module.exports = Person1; -------------------------------------------------------------------------------- /test/mock/model/person2.js: -------------------------------------------------------------------------------- 1 | var Person2 = function() { 2 | this.$mid = "person2"; 3 | this.$table = "bearcat_dao_test1"; 4 | this.create_at = "$type:Number"; 5 | } 6 | 7 | module.exports = { 8 | func: Person2, 9 | fields: ["create_at"], 10 | tableName: "bearcat_dao_test1" 11 | } -------------------------------------------------------------------------------- /test/mock/schema.sql: -------------------------------------------------------------------------------- 1 | /* bearcat_dao_test table */ 2 | DROP TABLE IF EXISTS bearcat_dao_test; 3 | create table bearcat_dao_test ( 4 | id bigint(20) NOT NULL COMMENT 'id', 5 | name varchar(100) NOT NULL COMMENT '姓名', 6 | num int(20) NOT NULL COMMENT 'num', 7 | create_at bigint(20) NOT NULL COMMENT '创建时间', 8 | 9 | primary key(id) 10 | )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='bearcat_dao_test'; 11 | 12 | DROP TABLE IF EXISTS bearcat_dao_test1; 13 | create table bearcat_dao_test1 ( 14 | id bigint(20) NOT NULL COMMENT 'id', 15 | name varchar(100) NOT NULL COMMENT '姓名', 16 | create_at bigint(20) NOT NULL COMMENT '创建时间', 17 | 18 | primary key(id, name) 19 | )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='bearcat_dao_test1'; 20 | 21 | DROP TABLE IF EXISTS ba_blog; 22 | create table ba_blog( 23 | id bigint(20) NOT NULL COMMENT 'blog id', 24 | aid bigint(20) NOT NULL COMMENT 'author id', 25 | title varchar(1024) NOT NULL COMMENT 'blog title', 26 | content varchar(65535) COMMENT 'blog content', 27 | 28 | create_at bigint(20) NOT NULL COMMENT '创建时间', 29 | update_at bigint(20) NOT NULL COMMENT '更新时间', 30 | 31 | PRIMARY KEY (id) 32 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 33 | 34 | DROP TABLE IF EXISTS ba_comment; 35 | create table ba_comment( 36 | id bigint(20) NOT NULL COMMENT 'comment id', 37 | aid bigint(20) NOT NULL COMMENT 'author id', 38 | bid bigint(20) NOT NULL COMMENT 'blog id', 39 | content varchar(1024) NOT NULL COMMENT 'comment', 40 | 41 | create_at bigint(20) NOT NULL COMMENT '创建时间', 42 | update_at bigint(20) NOT NULL COMMENT '更新时间', 43 | PRIMARY KEY (id) 44 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 45 | 46 | DROP TABLE IF EXISTS ba_author; 47 | create table ba_author( 48 | id bigint(20) NOT NULL COMMENT 'comment id', 49 | name varchar(255) NOT NULL COMMENT 'author', 50 | 51 | create_at bigint(20) NOT NULL COMMENT '创建时间', 52 | update_at bigint(20) NOT NULL COMMENT '更新时间', 53 | PRIMARY KEY (id) 54 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 55 | 56 | DROP TABLE IF EXISTS IDGenerator; 57 | create table IDGenerator( 58 | name varchar(50) NOT NULL, 59 | id bigint(20) unsigned NOT NULL DEFAULT 0, 60 | 61 | PRIMARY KEY (name) 62 | )ENGINE=InnoDB DEFAULT CHARSET=utf8; 63 | 64 | insert into IDGenerator (name, id) values ('bearcat_dao_test', 1); 65 | insert into IDGenerator (name, id) values ('bearcat_dao_test1', 1); 66 | insert into IDGenerator (name, id) values ('ba_blog', 1); 67 | insert into IDGenerator (name, id) values ('ba_comment', 1); 68 | insert into IDGenerator (name, id) values ('ba_author', 1); 69 | 70 | insert into ba_blog (id, aid, title, content, create_at, update_at) values (1, 1, 'test_title', 'test_content', 1423188291391, 1423188291391); 71 | insert into ba_author (id, name, create_at, update_at) values(1, 'test_author', 1423188291391, 1423188291391); 72 | insert into ba_comment (id, aid, bid, content, create_at, update_at) values(1, 1, 1, 'test_comment_1', 1423188291391, 1423188291391); 73 | insert into ba_comment (id, aid, bid, content, create_at, update_at) values(2, 1, 1, 'test_comment_2', 1423188291391, 1423188291391); 74 | insert into ba_comment (id, aid, bid, content, create_at, update_at) values(3, 1, 1, 'test_comment_3', 1423188291391, 1423188291391); 75 | 76 | insert into ba_blog (id, aid, title, content, create_at, update_at) values (2, 2, 'test_title_2', 'test_content_2', 1423188291391, 1423188291391); 77 | insert into ba_author (id, name, create_at, update_at) values(2, 'test_author_2', 1423188291391, 1423188291391); -------------------------------------------------------------------------------- /test/mock/sql/query1.sql: -------------------------------------------------------------------------------- 1 | sql blogResultList1 2 | select 3 | ba_blog.id as blog_id, 4 | title as blog_title, 5 | content as blog_content, 6 | ba_author.name as author_name 7 | from ${blogResultTable} 8 | where ba_blog.id = ba_author.id 9 | order by ba_blog.create_at desc limit ? , ? 10 | end 11 | 12 | sql blogResultList2 13 | select 14 | ba_blog.id as blog_id, 15 | title as blog_title, 16 | content as blog_content, 17 | ba_author.name as author_name 18 | from ${blogResultTable} 19 | where ba_blog.id = ba_author.id 20 | order by ba_blog.create_at desc limit ? , ? 21 | end 22 | 23 | sql blogResultTable 24 | blog, author 25 | end -------------------------------------------------------------------------------- /test/mock/sql/query2.sql: -------------------------------------------------------------------------------- 1 | sql authorResult 2 | select * from author ${authorWhere} 3 | end 4 | 5 | sql authorResultLaw 6 | select * from author 7 | end -------------------------------------------------------------------------------- /test/mock/sql/query3.sql: -------------------------------------------------------------------------------- 1 | sql queryPersonList 2 | select * from bearcat_dao_test where id = ? 3 | end -------------------------------------------------------------------------------- /test/mock/sql/queryBlog.sql: -------------------------------------------------------------------------------- 1 | sql blogResultSql 2 | select 3 | ba_blog.id as blog_id, 4 | ba_blog.aid as blog_aid, 5 | ba_blog.title as blog_title, 6 | ba_blog.content as blog_content, 7 | ba_author.name as author_name, 8 | ba_comment.content as comment_content 9 | from ba_blog, ba_author, ba_comment 10 | where ba_blog.id = ? and ba_blog.aid = ba_author.id and ba_comment.bid = ba_blog.id 11 | end -------------------------------------------------------------------------------- /test/template/cache/redisClusterTemplate.js: -------------------------------------------------------------------------------- 1 | var simplepath = require.resolve('../../../test-ddb-context.json'); 2 | var bearcat = require('bearcat'); 3 | var path = require('path'); 4 | var paths = [simplepath]; 5 | bearcat.createApp(paths); 6 | 7 | process.env.LOGGER_LINE = true; 8 | bearcat.start(function() { 9 | var redisTemplate = bearcat.getBean('redisTemplate'); 10 | var num = 1; 11 | var setAndGet = function(num) { 12 | var key = 'aaa_' + num; 13 | redisTemplate.set(key, 'bearcat', function(err, reply) { 14 | if (err) { 15 | console.log('redis error %s', err.stack); 16 | redisTemplate.restartHaClient(); 17 | } 18 | 19 | if (reply !== 'OK') { 20 | console.log('reply %s', reply); 21 | } 22 | 23 | redisTemplate.get(key, function(err, reply) { 24 | if (err) { 25 | console.log('redis error %s', err.stack); 26 | } 27 | 28 | if (reply !== 'bearcat') { 29 | console.log('reply %s', reply); 30 | } 31 | }); 32 | }); 33 | } 34 | 35 | // setTimeout(function() { 36 | setInterval(function() { 37 | for (var i = 0; i < 100; i++) { 38 | (function(num) { 39 | setAndGet(num); 40 | })(i) 41 | } 42 | }, 3000); 43 | }); 44 | 45 | process.on('uncaughtException', function(err) { 46 | console.error('Caught exception: ', err.stack); 47 | }); -------------------------------------------------------------------------------- /test/template/cache/redisTemplate.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | var bearcat = require('bearcat'); 3 | 4 | describe('redisTemplate', function() { 5 | var simplepath = require.resolve('../../../test-context.json'); 6 | var paths = [simplepath]; 7 | bearcat.createApp(paths); 8 | 9 | before(function(done) { 10 | bearcat.start(function() { 11 | done(); 12 | }); 13 | }); 14 | 15 | describe('redisTemplate set get right', function() { 16 | it('should redisTemplate set get right', function(done) { 17 | var domainDaoSupport = bearcat.getBean('domainDaoSupport'); 18 | var cacheTemplate = domainDaoSupport.getCacheTemplate(); 19 | domainDaoSupport.should.exist; 20 | cacheTemplate.should.exist; 21 | 22 | cacheTemplate.setConnectionManager(); 23 | cacheTemplate.getConnectionManager(); 24 | cacheTemplate.setExpireDay(100); 25 | cacheTemplate.getExpireDay(); 26 | 27 | cacheTemplate.addToCache(); 28 | cacheTemplate.addToList(); 29 | cacheTemplate.setStringToList(); 30 | cacheTemplate.deleteStringFromList(); 31 | cacheTemplate.deleteStringsFromList(); 32 | cacheTemplate.delFromCache(); 33 | cacheTemplate.expire(); 34 | 35 | done(); 36 | }); 37 | }); 38 | 39 | describe('redisTemplate do list right', function() { 40 | it('should do list right', function(done) { 41 | var domainDaoSupport = bearcat.getBean('domainDaoSupport'); 42 | var cacheTemplate = domainDaoSupport.getCacheTemplate(); 43 | 44 | var key = 'bearcat_list'; 45 | var value = 100; 46 | cacheTemplate.addToList(key, value); 47 | 48 | cacheTemplate.setExpireDay(100); 49 | cacheTemplate.expire(key); 50 | cacheTemplate.getStringFromList(key, 0, function(err, r) { 51 | r.should.eql(value); 52 | 53 | cacheTemplate.getListLength(key, function(err, r) { 54 | r.should.eql(1); 55 | 56 | cacheTemplate.getStringListRange(key, 0, 0, function(err, r) { 57 | r.length.should.eql(1); 58 | r[0].should.eql(value); 59 | 60 | cacheTemplate.keyExists(key, function(err, r) { 61 | r.should.eql(1); 62 | 63 | value += 100; 64 | cacheTemplate.setStringToList(key, 0, value); 65 | 66 | cacheTemplate.getStringFromList(key, 0, function(err, r) { 67 | r.should.eql(value); 68 | 69 | cacheTemplate.deleteStringFromList(key, value); 70 | 71 | cacheTemplate.keyExists(key, function(err, r) { 72 | r.should.eql(0); 73 | 74 | done(); 75 | }); 76 | }); 77 | }); 78 | }); 79 | }); 80 | }); 81 | }); 82 | }); 83 | }); -------------------------------------------------------------------------------- /test/template/sql/DDBTemplate.js: -------------------------------------------------------------------------------- 1 | var simplepath = require.resolve('../../../test-ddb-context.json'); 2 | var bearcatDao = require('../../../lib/bearcat-dao'); 3 | var bearcat = require('bearcat'); 4 | var path = require('path'); 5 | var paths = [simplepath]; 6 | bearcat.createApp(paths); 7 | 8 | process.env.LOGGER_LINE = true; 9 | bearcat.start(function() { 10 | // directQuery(); 11 | // for (var i = 0; i < 10; i++) { 12 | // query(); 13 | // } 14 | // add(); 15 | update(); 16 | }); 17 | 18 | function query() { 19 | var sqlTemplate = bearcat.getBean('sqlTemplate'); 20 | // var sql = "select blog.id blog_id, title, content, name from blog, author where blog.aid = author.id"; 21 | // var sql = "select id as idd, title from blog group by idd"; 22 | // var sql = "select title from blog where id > 1 group by title, create_at"; 23 | // var sql = "select title from blog where id > 1 order by title asc, create_at"; 24 | var sql = "select id, title from blog where id = 1 or id = 5"; 25 | // var sql = "select id, title from blog where id between 1 and 5"; 26 | // var sql = "select id, title from blog where id between (1 and 5)"; 27 | // var sql = "select id, title from blog where title is null"; 28 | // var sql = "select id, title from blog where id not in (1, 2)"; 29 | // var sql = "select id, title from blog where id > 1"; 30 | // var sql = "select 1"; 31 | sqlTemplate.executeQuery(sql, [], function(err, results) { 32 | if (err) { 33 | console.log(err); 34 | } 35 | 36 | // console.log(results); 37 | }); 38 | } 39 | 40 | function directQuery() { 41 | var sqlTemplate = bearcat.getBean('sqlTemplate'); 42 | // var sql = "select blog.id blog_id, title, content, name from blog, author where blog.aid = author.id"; 43 | // var sql = "select id as idd, title from blog group by idd"; 44 | // var sql = "select title from blog where id > 1 group by title, create_at"; 45 | // var sql = "select title from blog where id > 1 order by title asc, create_at"; 46 | // var sql = "select id, title from blog where id = 1 or id = 5"; 47 | // var sql = "select id, title from blog where id between 1 and 5"; 48 | // var sql = "select id, title from blog where id between (1 and 5)"; 49 | // var sql = "select id, title from blog where title is null"; 50 | // var sql = "select id, title from blog where id not in (1, 2)"; 51 | // var sql = "select id, title from blog where id > 1"; 52 | // var sql = "select 1"; 53 | var sql = "insert into blog (id, aid, title, content, create_at, update_at) values (10, 10, 'test_title_10', 'test_content_10', 1424659231463, 1424659231463)"; 54 | // var sql = "insert into author (id, name ,create_at, update_at) values (10, 'test_author_10', 123456, 123456)"; 55 | 56 | var options = { 57 | destDB: '*', 58 | role: 'master' 59 | } 60 | 61 | options['destDB'] = bearcatDao.calDestDBs('blog', 'id', [10]); 62 | 63 | sqlTemplate.directQuery(sql, [], options, function(err, results) { 64 | if (err) { 65 | console.log(err.stack); 66 | } 67 | 68 | var sql = "select * from blog where id = 10"; 69 | console.log(results); 70 | 71 | sqlTemplate.directQuery(sql, [], options, function(err, results) { 72 | console.log(results); 73 | }); 74 | }); 75 | } 76 | 77 | function add() { 78 | var sqlTemplate = bearcat.getBean('sqlTemplate'); 79 | 80 | var options = { 81 | destDB: '*', 82 | role: 'master', 83 | table: 'author' 84 | } 85 | 86 | var object = null; 87 | options['destDB'] = bearcatDao.calDestDBs('blog', 'id', [11]); 88 | 89 | var author = { 90 | id: 11, 91 | name: 'test_author_11', 92 | create_at: 123456, 93 | update_at: 123456 94 | } 95 | 96 | sqlTemplate.directAdd(author, options, function(err, results) { 97 | if (err) { 98 | console.log(err.stack); 99 | } 100 | 101 | console.log(results); 102 | }); 103 | } 104 | 105 | function update() { 106 | var sqlTemplate = bearcat.getBean('sqlTemplate'); 107 | 108 | var options = { 109 | destDB: '*', 110 | role: 'master', 111 | table: 'author' 112 | } 113 | 114 | var object = null; 115 | options['destDB'] = bearcatDao.calDestDBs('blog', 'id', [11]); 116 | 117 | var author = { 118 | id: 11, 119 | name: 'test_author_11_update', 120 | create_at: 123456, 121 | update_at: 123456 122 | } 123 | 124 | sqlTemplate.directUpdateById(author, options, function(err, results) { 125 | if (err) { 126 | console.log(err.stack); 127 | } 128 | 129 | console.log(results); 130 | }); 131 | } -------------------------------------------------------------------------------- /test/transaction/dao/person1Dao.js: -------------------------------------------------------------------------------- 1 | var PersonDomain = require('../../mock/domain/person1'); 2 | var PersonDao = function() { 3 | this.domainDaoSupport = null; 4 | } 5 | 6 | module.exports = PersonDao; 7 | 8 | PersonDao.prototype.setDomainDaoSupport = function(domainDaoSupport) { 9 | this.domainDaoSupport = domainDaoSupport; 10 | } 11 | 12 | PersonDao.prototype.getDomainDaoSupport = function() { 13 | return this.domainDaoSupport; 14 | } 15 | 16 | PersonDao.prototype.init = function() { 17 | this.domainDaoSupport.initConfig(PersonDomain); 18 | } 19 | 20 | PersonDao.prototype.transaction = function(transactionStatus) { 21 | this.domainDaoSupport.transaction(transactionStatus); 22 | return this; 23 | } 24 | 25 | PersonDao.prototype.getList = function(params, cb) { 26 | var sql = ' id in (?, ?)'; 27 | this.domainDaoSupport.getListByWhere(sql, params, null, function(err, results) { 28 | cb(err, results); 29 | }); 30 | } 31 | 32 | PersonDao.prototype.add = function(obj, cb) { 33 | this.domainDaoSupport.add(obj, cb); 34 | } -------------------------------------------------------------------------------- /test/transaction/dao/personDao.js: -------------------------------------------------------------------------------- 1 | var PersonDomain = require('../../mock/domain/person'); 2 | var PersonDao = function() { 3 | this.domainDaoSupport = null; 4 | } 5 | 6 | module.exports = PersonDao; 7 | 8 | PersonDao.prototype.setDomainDaoSupport = function(domainDaoSupport) { 9 | this.domainDaoSupport = domainDaoSupport; 10 | } 11 | 12 | PersonDao.prototype.getDomainDaoSupport = function() { 13 | return this.domainDaoSupport; 14 | } 15 | 16 | PersonDao.prototype.init = function() { 17 | this.domainDaoSupport.initConfig(PersonDomain); 18 | } 19 | 20 | PersonDao.prototype.transaction = function(transactionStatus) { 21 | this.domainDaoSupport.transaction(transactionStatus); 22 | return this; 23 | } 24 | 25 | PersonDao.prototype.getAList = function(params, cb) { 26 | var sql = ' aid in (?, ?)'; 27 | this.domainDaoSupport.getListByWhere(sql, params, null, function(err, results) { 28 | cb(err, results); 29 | }); 30 | } 31 | 32 | PersonDao.prototype.getList = function(params, cb) { 33 | var sql = ' id in (?, ?)'; 34 | this.domainDaoSupport.getListByWhere(sql, params, null, function(err, results) { 35 | cb(err, results); 36 | }); 37 | } 38 | 39 | PersonDao.prototype.addPerson = function(params, cb) { 40 | var sql = 'insert into ' + this.domainDaoSupport.getTableConfig().getTableName() + ' set id = ?, num = ?, name = ?, create_at = ?'; 41 | this.domainDaoSupport.add(sql, params, cb); 42 | } 43 | 44 | PersonDao.prototype.add = function(obj, cb) { 45 | this.domainDaoSupport.add(obj, cb); 46 | } -------------------------------------------------------------------------------- /test/transaction/service/personService.js: -------------------------------------------------------------------------------- 1 | var PersonDomain = require('../../mock/domain/person'); 2 | 3 | var PersonService = function() { 4 | this.personDao = null; 5 | } 6 | 7 | module.exports = PersonService; 8 | 9 | PersonService.prototype.testMethodTransaction = function(cb, txStatus) { 10 | var params = [108, 100, 'fni', Date.now()]; 11 | var self = this; 12 | this.personDao.transaction(txStatus).addPerson(params, function(err, results) { 13 | if (err) { 14 | cb(err); 15 | return; 16 | } 17 | self.personDao.transaction(txStatus).getAList([1, 2], function(err, results) { 18 | if (err) { 19 | cb(err); 20 | return; 21 | } 22 | cb(null, results); 23 | }); 24 | }); 25 | } 26 | 27 | PersonService.prototype.testMethodRTransaction = function(cb, txStatus) { 28 | var person = new PersonDomain['func'](); 29 | person.setNum(100); 30 | person.setName('yy'); 31 | person.setCreateAt(Date.now()); 32 | 33 | var self = this; 34 | this.personDao.transaction(txStatus).add(person, function(err, results) { 35 | if (err) { 36 | cb(err); 37 | return; 38 | } 39 | self.personDao.transaction(txStatus).getList([1, 2], function(err, results) { 40 | if (err) { 41 | cb(err); 42 | return; 43 | } 44 | cb(null, results); 45 | }); 46 | }); 47 | } -------------------------------------------------------------------------------- /test/util/countDownLatch.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | 3 | var CountDownLatch = require('../../lib/util/countDownLatch'); 4 | 5 | describe('countDownLatch', function() { 6 | describe('countDownLatch', function() { 7 | it('should do countDownLatch error right', function(done) { 8 | CountDownLatch.createCountDownLatch(); 9 | CountDownLatch.createCountDownLatch(100); 10 | 11 | var latch = CountDownLatch.createCountDownLatch(100, function() {}); 12 | latch.count = -1; 13 | latch.done(); 14 | 15 | latch.count = 100; 16 | latch.done(new Error('error')); 17 | done(); 18 | }); 19 | }); 20 | }); -------------------------------------------------------------------------------- /test/util/sqlBuilderUtil.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | var SqlBuilderUtil = require('../../lib/util/sqlBuilderUtil'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('sqlBuilderUtil', function() { 6 | it('should testInsertSql build sql right', function(done) { 7 | var expected = "insert into User (id, name, age) values (?, ?, ?)"; 8 | 9 | var tableName = "User"; 10 | 11 | var columns = []; 12 | columns.push("id"); 13 | columns.push("name"); 14 | columns.push("age"); 15 | 16 | var actual = SqlBuilderUtil.buildInsertSql(tableName, columns); 17 | 18 | expected.should.eql(actual); 19 | done(); 20 | }); 21 | 22 | it('should testBatchInsertSql build sql right', function(done) { 23 | var expected = "insert into User (id, name, age) values (?, ?, ?), (?, ?, ?)"; 24 | 25 | var tableName = "User"; 26 | 27 | var columns = []; 28 | columns.push("id"); 29 | columns.push("name"); 30 | columns.push("age"); 31 | 32 | var actual = SqlBuilderUtil.buildBatchInsertSql(tableName, columns, 2); 33 | 34 | expected.should.eql(actual); 35 | done(); 36 | }); 37 | 38 | it('should testDeleteSql build sql right', function(done) { 39 | var expected = "delete from User where (id = ? and name = ? and age = ?)"; 40 | 41 | var tableName = "User"; 42 | 43 | var columns = []; 44 | columns.push("id"); 45 | columns.push("name"); 46 | columns.push("age"); 47 | 48 | var actual = SqlBuilderUtil.buildDeleteSql(tableName, columns); 49 | 50 | expected.should.eql(actual); 51 | done(); 52 | }); 53 | 54 | it('should testBatchDeleteSql build sql right', function(done) { 55 | var expected = "delete from User where (id = ? and name = ? and age = ?) or (id = ? and name = ? and age = ?)"; 56 | 57 | var tableName = "User"; 58 | 59 | var columns = []; 60 | columns.push("id"); 61 | columns.push("name"); 62 | columns.push("age"); 63 | 64 | var actual = SqlBuilderUtil.buildBatchDeleteSql(tableName, columns, 2); 65 | 66 | expected.should.eql(actual); 67 | done(); 68 | }); 69 | 70 | it('should getSql right', function(done) { 71 | SqlBuilderUtil.getSql(); 72 | 73 | done(); 74 | }); 75 | }); 76 | }); -------------------------------------------------------------------------------- /test/util/utils.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | var Utils = require('../../lib/util/utils'); 3 | 4 | describe('bearcat-dao', function() { 5 | describe('utils', function() { 6 | it('should utils right', function(done) { 7 | var r = Utils.checkArray([]); 8 | r.should.be.true; 9 | 10 | done(); 11 | }); 12 | }); 13 | }); --------------------------------------------------------------------------------