├── .gitignore
├── README.md
├── bower.json
├── dist
├── ngdb.js
└── ngdb.min.js
├── package.json
└── src
├── ngdb.js
├── ngdbCache.service.js
├── ngdbDataConverter.service.js
├── ngdbQuery.service.js
├── ngdbQueryBuilder.service.js
├── ngdbRepository.service.js
└── ngdbUtils.service.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Depreciation notice : this repository is no longer maintained.
2 | You can find other good lib such as :
3 | - localForage : https://github.com/localForage/localForage
4 | - angular localForage : https://github.com/ocombe/angular-localForage
5 | - pouch db : https://pouchdb.com/ (with sync capatibilities)
6 |
7 | # ngDatabase
8 | ngDatabase is a light, very easy to use and powerful __storage__ solution for your __[Ionic](http://ionicframework.com/)__ apps. Take advantage of unlimited storage size, data binding, very flexible data management and more.
9 |
10 | # Quick links
11 |
12 | * __Get started__
13 | * [Quick guide] (#quick-guide)
14 | * [Installation] (#installation)
15 | * __Repositories__
16 | * [Create Repositories] (#create)
17 | * [Get Repositories] (#get)
18 | * __Data operation__
19 | * [Add data] (#add)
20 | * [Get data] (#get)
21 | * [Update data] (#update)
22 | * [Delete data] (#delete)
23 | * __Data selection__
24 | * [Set order](#order)
25 | * [Set standards](#standards)
26 | * [Set limit](#limit)
27 | * __Data binding__
28 | * [How it works]()
29 | * [Watch updates]()
30 | * __Low level usage__
31 | * [Native SQLite syntax] (#native-sqlite-syntax)
32 |
33 | ### Get started
34 | #### Quick guide
35 | Get started in 4 steps by following this guideline.
36 |
37 | * The very first thing you have to do is install ngDatabase : [ngDatabase installation] (#installation)
38 |
39 | * At this point you must launch ngDatabase inside your app and tell him what kind of 'repository' you will used. In ngDatabase a repository is a place where your data will be stored. For exemple if you have to store some user and customer data you will have two repositories severally called 'users' and 'customers'. Check how to create repositories : [Create Repositories] (#create)
40 |
41 | * Now you've got some repositories ready to work. Each time you make operations on your repositories you have to use the _getRepository()_ method to be able to do anything. -> [Get Repositories] (#get)
42 |
43 | * The previous method give you an new instance of a working repository. Now you can make what you want thanks to the 4 methods : [Data operation] (#data-operation)
44 |
45 | * As you can observe we can't do a lot only with these 4 methods. It's the combination between them and 3 others which make the magic. These 3 others are _setBy(), setOrder()_ and _setLimit()_ which define by what criterion the data will be get, add, delete, ... Check it : [Data selection] (#data-selection)
46 |
47 | ### Installation
48 | #### ngCordova and cordovaSQLite
49 | First, install ndCordova to your project (http://ngcordova.com/docs/install/) :
50 | ```shell
51 | bower install ngCordova
52 | ```
53 | Don't forget to include the ng-cordova.js file and add ngCordova in your app dependencies :
54 | ```html
55 |
56 | ```
57 | ```javascript
58 | angular.module('myApp', ['ngCordova']);
59 | ```
60 |
61 | Then, add the cordovaSQLite plugin :
62 | ```shell
63 | cordova plugin add https://github.com/litehelpers/Cordova-sqlite-storage.git
64 | ```
65 | #### ngDatabase
66 | ```shell
67 | bower install ng-database #bower
68 | npm install ng-database #NPM
69 | ```
70 |
71 | Include the ng-database js file in your project :
72 | ```html
73 |
74 | ```
75 | Then include ngDatabase dependency :
76 | ```javascript
77 | angular.module('myApp', ['ngCordova', 'ngDatabase']);
78 | ```
79 |
80 | # API
81 |
82 | ##### Important note : all of ngDatabase method must be used when the _deviceready_ event fired.
83 |
84 | ### Repositories
85 | #### Create
86 | ##### Prototype
87 | ```javascript
88 | ngdbProvider setRepository(string repositoryName, object repositorySchema)
89 | ```
90 | ##### Description
91 | A repository is a kind of bag which define your data schema. It's typically an object where each key-value pair correspond respectively to the name of your data and his type (see bellow). This operation is done in the config step of your app.
92 | For exemple, if you have to manage users and pictures in your app your repositories could look like that :
93 | ```javascript
94 | app.config(function(ngdbProvider) {
95 | var usersRepository = {
96 | id: 'ID',
97 | pictures_id:'NUMBER'
98 | name: 'STRING',
99 | born: 'DATE'
100 | };
101 |
102 | var pictures = {
103 | id: 'ID',
104 | pictures: 'OBJECT'
105 | };
106 |
107 | ngdbProvider
108 | .setRepository('users', usersRepository)
109 | .setRepository('pictures', picturesRepository);
110 | });
111 | ```
112 |
113 | * __ID__ : special integer type which is incremented at each insertion
114 | * __STRING__ : can store string such as text
115 | * __NUMBER__ : an integer or floating number
116 | * __BOOLEAN__ : _true_ or _false_ values
117 | * __OBJECT__ : a javascript object
118 | * __ARRAY__ : a javascript array
119 | * __DATE__ : a date (must be an instance of Date())
120 |
121 | #### Get
122 | ##### Prototype
123 | ```javascript
124 | ngdb getRepository(string repositoryName)
125 | ```
126 | ##### Description
127 | This method allow you to make operations in the specified _repositoryName_.
128 | Use it to add, delete, update...
129 | ```javascript
130 | myApp.controller('myCtrl', function(ngdb) {
131 |
132 | var usersRepository = ngdb.getRepository('users');
133 | var picturesRepository = ngdb.getRepository('pictures');
134 |
135 | //Make all your operations.
136 |
137 | });
138 | ```
139 |
140 | ### Data operation
141 | #### Add
142 | ##### Prototype
143 | ```javascript
144 | promise add(object data)
145 | ```
146 | ##### Description
147 | This method add some data in a repository. Only the keys that correspond to the mapping defined in the config step will be added. Note that you do not have to convert your data. Just let objects as objects, numbers as numbers, strings as strings, ...
148 |
149 | __Return__ a promise containing an object with the insertion informations (the ID particularly).
150 |
151 | ```javascript
152 | myApp.controller('myCtrl', function(ngdb) {
153 |
154 | var usersRepository = ngdb.getRepository('users');
155 | var picturesRepository = ngdb.getRepository('pictures');
156 |
157 | var userToAdd = {
158 | pictures_id: 5,
159 | name: 'Jack',
160 | born: new Date()
161 | };
162 | var pictureToAdd = {
163 | pictures: {'path1', 'path2'}
164 | };
165 |
166 | var user = usersRepository.add(userToAdd);
167 | var picture = picturesRepository.add(pictureToAdd);
168 |
169 | user.then(function(result) {
170 | //The insered id
171 | console.log(result.insertId);
172 | });
173 |
174 | });
175 | ```
176 | ### Get
177 | ##### Prototypes
178 | ```javascript
179 | promise get()
180 | promise getOne()
181 | ```
182 | ##### Description
183 | Get data from repository.
184 | All your data are gived back to the correct type (objects as objects, numbers as numbers, ...)
185 |
186 | __Return__ promise containing an object with the requested data.
187 |
188 | ```javascript
189 | myApp.controller('myCtrl', function(ngdb) {
190 |
191 | var usersRepository = ngdb.getRepository('users');
192 | var picturesRepository = ngdb.getRepository('pictures');
193 |
194 | //Get all users and pictures data
195 | var usersData = usersRepository.get();
196 | var picturesData = picturesRepository.get();
197 |
198 | //Get the first user and picture data
199 | var firstUserData = usersRepository.getOne();
200 | var firstPictureData = pictureRepository.getOne();
201 |
202 | usersData.then(function(result) {
203 | //Your data is here !
204 | console.log(result);
205 | });
206 |
207 | });
208 | ```
209 |
210 | #### Update
211 | ##### Prototype
212 | ```javascript
213 | promise update(object data)
214 | ```
215 | ##### Description
216 | Update the specified _data_.
217 |
218 | __Return__ promise containing an object with informations about the update.
219 |
220 | ```javascript
221 | myApp.controller('myCtrl', function(ngdb) {
222 |
223 | var usersRepository = ngdb.getRepository('users');
224 | var picturesRepository = ngdb.getRepository('pictures');
225 |
226 | var usersToUpdate = {
227 | name: 'John Doe',
228 | };
229 | var picturesToUpdate = {
230 | pictures: {'newPath'}
231 | };
232 |
233 | //Update all users and pictures data
234 | usersRepository.update(usersToUpdate);
235 | picturesRepository.update(picturesToUpdate);
236 |
237 | });
238 | ```
239 |
240 | #### Delete
241 | ##### Prototype
242 | ```javascript
243 | promise delete()
244 | ```
245 | ##### Description
246 | Delete entries in the repository.
247 |
248 | __Return__ promise containing an object with the informations about the deletion.
249 |
250 | ```javascript
251 | myApp.controller('myCtrl', function(ngdb) {
252 |
253 | var usersRepository = ngdb.getRepository('users');
254 | var picturesRepository = ngdb.getRepository('pictures');
255 |
256 | //Delete all users and pictures data
257 | usersRepository.delete();
258 | picturesRepository.delete();
259 |
260 | });
261 | ```
262 |
263 | ### Data selection
264 | These methods can be chained and must be called before the data operation methods (get, update, ...).
265 | These methods have an influence on the way the data are going to be treated. All of them take an object where the key correspond to the data name previously defined (in the app config step).
266 |
267 | #### Order
268 | ##### Prototype
269 | ```javascript
270 | ngdb setOrder(object order)
271 | ```
272 |
273 | ##### Description
274 | Order your data by something in ascendent ('ASC' keyword) or descendent ('DESC' keyword) order.
275 |
276 | __Return__ promise containing an object with the requested data.
277 |
278 | ```javascript
279 | myApp.controller('myCtrl', function(ngdb) {
280 |
281 | var usersRepository = ngdb.getRepository('users');
282 |
283 | //Get all users sorted by name in ascendent order
284 | usersRepository.setOrder({'name': 'ASC'}).get();
285 | //Get all users sorted by id in descendent order
286 | usersRepository.setOrder({'id': 'DESC'}).get();
287 |
288 | });
289 | ```
290 |
291 | #### Standards
292 | ##### Prototype
293 | ```javascript
294 | ngdb setBy(object conditions)
295 | ```
296 |
297 | ##### Description
298 | Get, update or delete data according to the equality of the key-value object.
299 |
300 | __Return__ promise containing an object with the requested data.
301 |
302 | ```javascript
303 | myApp.controller('myCtrl', function(ngdb) {
304 |
305 | var usersRepository = ngdb.getRepository('users');
306 |
307 | //Get all users named 'John'
308 | usersRepository.setBy({'name': 'John'}).get();
309 | //Get the user with id equal to 1
310 | usersRepository.setOrder({'id': 1}).getOne();
311 | //Get the user named John with id equal to 1
312 | usersRepository.setBy({'id': 1, 'name': 'John'}).getOne();
313 |
314 | });
315 | ```
316 |
317 | #### Limit
318 | ##### Prototype
319 | ```javascript
320 | ngdb setLimit(int from, int to)
321 | ```
322 | Take two integer which represent the interval.
323 |
324 | __Return__ promise containing an object with the requested data.
325 |
326 | ```javascript
327 | myApp.controller('myCtrl', function(ngdb) {
328 |
329 | var usersRepository = ngdb.getRepository('users');
330 |
331 | //Get 0 to 10 first results
332 | usersRepository.setLimit(0, 10).get();
333 | //Get 10 to 20 first results
334 | usersRepository.setLimit(10, 20).get();
335 |
336 | });
337 | ```
338 |
339 | ### Data binding
340 |
341 | _CURRENT WRITING, VERY SOON AVAILABLE_
342 |
343 | ### Low level usage
344 | #### Native SQLite syntax
345 | ##### Prototypes
346 | ```javascript
347 | promise query(string query, array bindings)
348 | object fetchAll(object SQLiteResult)
349 | object fetch(object SQLiteResult)
350 | ```
351 | ##### Description
352 | NGDatabase also allow you to use SQLite as native syntax.
353 | * make() : make an SQL Query
354 | * fetchAll() : fetch all SQLite Query result
355 | * fetch() : fetch one SQLite Query result
356 |
357 | ##### Exemple
358 |
359 | ```javascript
360 | myApp.controller('myCtrl', function(ngdb) {
361 |
362 | var qm = ngdb.getQueryMaker();
363 | var result = qm.make("SELECT * FROM users WEHRE name = ?", ['John Doe']);
364 |
365 | result.then(function(result) {
366 | result = qm.fetchAll(result);
367 | });
368 | });
369 | ```
370 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-database",
3 | "version": "1.3.5",
4 | "description": "A simple and powerful local storage solution for your Ionic apps.",
5 | "main": "dist/ngdb.js",
6 | "keywords": [
7 | "ionic",
8 | "sqlite",
9 | "ngDatabase"
10 | ],
11 | "authors": [
12 | "Antoine Bellion"
13 | ],
14 | "license": "MIT",
15 | "ignore": [
16 | ".gitignore"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/dist/ngdb.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase', ['ngCordova'])
3 | .constant('NGDB_TYPES', {
4 | ID: 'integer',
5 | STRING: 'text',
6 | NUMBER: 'integer',
7 | BOOLEAN: 'text',
8 | OBJECT: 'text',
9 | ARRAY: 'text',
10 | DATE: 'datetime'
11 | });
12 |
13 | angular
14 | .module('ngDatabase')
15 | .provider('ngdb', ngdbProvider);
16 |
17 | ngdbProvider.$inject = ['NGDB_TYPES'];
18 | function ngdbProvider(NGDB_TYPES) {
19 | var self = this;
20 | self.repositoriesSchema = {};
21 |
22 | var _validRepository = function(repositorySchema) {
23 | var isValid = true;
24 |
25 | ngdbUtils().browseObject(repositorySchema, function(type, name) {
26 | isValid = (NGDB_TYPES[type]) ? isValid : false;
27 | });
28 |
29 | return (isValid)
30 | };
31 |
32 | self.setRepository = function(repositoryName, repositorySchema) {
33 | if (_validRepository(repositorySchema)) {
34 | repositorySchema['id'] = 'ID';
35 |
36 | self.repositoriesSchema[repositoryName] = repositorySchema;
37 | }
38 | else {
39 | ngdbUtils().errorHandler("Unable to create '"+repositoryName+"' due to unknown datatype.");
40 | }
41 |
42 | return (self);
43 | };
44 |
45 | self.$get = ngdbFactory;
46 |
47 | return (self);
48 | }
49 |
50 | ngdbFactory.$inject = ['$q', '$injector', 'ngdbUtils', 'ngdbQuery', 'ngdbCache', 'NGDB_TYPES'];
51 | function ngdbFactory($q, $injector, ngdbUtils, ngdbQuery, ngdbCache, NGDB_TYPES) {
52 | var self = this;
53 | var ngdb = {};
54 |
55 | /*
56 | ** REPOSITORIES
57 | */
58 | var _formatRepository = function(repositorySchema) {
59 | var ret = {};
60 |
61 | ngdbUtils.browseObject(repositorySchema, function(columnType, columnName) {
62 | ret[columnName] = (columnName !== "id") ? NGDB_TYPES[columnType] : 'integer primary key';
63 | });
64 |
65 | return (ret);
66 | };
67 |
68 | ngdb.createRepositories = function() {
69 | var queries = [];
70 | var schema = self.repositoriesSchema;
71 |
72 | ngdbUtils.browseObject(schema, function(table, tableName) {
73 | var columns = [];
74 | table = _formatRepository(table);
75 |
76 | ngdbUtils.browseObject(table, function(columnType, columnName) {
77 | columns.push('`' + columnName + '` ' + columnType);
78 | });
79 |
80 | queries.push(ngdbQuery.make('CREATE TABLE IF NOT EXISTS `' + tableName + '` (' + columns.join(', ') + ')'));
81 | });
82 |
83 | return ($q.all(queries));
84 | };
85 |
86 | ngdb.getRepository = function(repositoryName, binding) {
87 | var repository = $injector.instantiate(ngdbRepository, { 'ngdbQueryBuilder': $injector.instantiate(ngdbQueryBuilder) });
88 | var repositorySchema = ngdb.getRepositorySchema(repositoryName);
89 |
90 | repository.ngdbRepositorySetRepository(repositoryName, repositorySchema, binding);
91 |
92 | return (repository);
93 | };
94 |
95 | ngdb.getRepositorySchema = function(repositoryName) {
96 | return (self.repositoriesSchema[repositoryName] || null);
97 | };
98 |
99 | ngdb.getQueryMaker = function() {
100 | return (ngdbQuery);
101 | };
102 |
103 | /*
104 | ** WATCHERS
105 | */
106 | ngdb.putWatcher = function(value, callback, call) {
107 | var watcherId = ngdbCache.putWatcher(value, callback);
108 |
109 | if (call === true || typeof call === "undefined") {
110 | ngdbCache.callWatcher(value, value);
111 | }
112 |
113 | return (watcherId);
114 | };
115 |
116 | ngdb.popWatcher = function(watcherId) {
117 | return (ngdbCache.popWatcher(watcherId));
118 | };
119 |
120 | return (ngdb.createRepositories(), ngdb);
121 | };
122 | angular
123 | .module('ngDatabase')
124 | .factory('ngdbQuery', ngdbQuery);
125 |
126 | ngdbQuery.$inject = ['$q', '$cordovaSQLite'];
127 | function ngdbQuery($q, $cordovaSQLite) {
128 | var self = this;
129 | var _db = null;
130 |
131 | var _dbConnexion = function() {
132 |
133 | _db = (window.cordova) ?
134 | $cordovaSQLite.openDB('ngdb.db') :
135 | window.openDatabase('ngdb.db', '1', 'ngdb.db', -1);
136 |
137 | return (_db);
138 | };
139 |
140 |
141 | self.make = function(query, bindings) {
142 | var deferred = $q.defer();
143 | bindings = (bindings !== undefined && bindings !== null) ? bindings : [];
144 |
145 | _db.transaction(function(transaction) {
146 | transaction.executeSql(query, bindings, function(transaction, result) {
147 | deferred.resolve(result);
148 | }, function(transaction, error) {
149 | deferred.reject(error);
150 | });
151 | });
152 |
153 | return (deferred.promise);
154 | };
155 |
156 | self.fetchAll = function(result) {
157 | var output = [];
158 | var rows = result.rows.length;
159 |
160 | for (var i = 0; i < rows; i++) {
161 | output.push(result.rows.item(i));
162 | }
163 |
164 | return (output);
165 | };
166 |
167 | self.fetch = function(result) {
168 | return ((result.rows.length > 0) ? result.rows.item(0) : null);
169 | };
170 |
171 | return (_dbConnexion(), self);
172 | }
173 | angular
174 | .module('ngDatabase')
175 | .service('ngdbRepository', ngdbRepository);
176 |
177 | ngdbRepository.$inject = ['$q', '$injector', 'ngdbUtils', 'ngdbQuery', 'ngdbQueryBuilder', 'ngdbCache', 'ngdbDataConverter'];
178 | function ngdbRepository($q, $injector, ngdbUtils, ngdbQuery, ngdbQueryBuilder, ngdbCache, ngdbDataConverter) {
179 | var self = this;
180 | var _binding = true;
181 | var _repositoryName = null;
182 | var _repositorySchema = null;
183 |
184 | /*
185 | ** UTILS METHODS
186 | */
187 | self.ngdbRepositorySetRepository = function(repositoryName, repositorySchema, binding) {
188 | _repositoryName = repositoryName;
189 | _repositorySchema = repositorySchema;
190 | _binding = (binding === false) ? false : true;
191 |
192 | ngdbQueryBuilder.ngdbQueryBuilderSetRepository(repositoryName);
193 |
194 | return (self);
195 | };
196 |
197 | var _formatGet = function(result) {
198 | var fetched = ngdbQuery.fetchAll(result);
199 |
200 | fetched && fetched.forEach(function(val, index) {
201 | fetched[index] = ngdbDataConverter.convertDataToGet(val, _repositorySchema);
202 | });
203 |
204 | return (fetched);
205 | };
206 |
207 | var _formatGetOne = function(result) {
208 | var fetched = ngdbDataConverter.convertDataToGet(ngdbQuery.fetch(result), _repositorySchema);
209 |
210 | return ((fetched) ? fetched : null);
211 | };
212 |
213 | var _updateCache = function(promise) {
214 | if (!_binding) {
215 | return (0);
216 | }
217 |
218 | promise.then(function() {
219 | ngdbCache.updateCache(_repositoryName);
220 | });
221 | };
222 |
223 | /*
224 | ** USER METHODS
225 | */
226 | self.get = function() {
227 | var deferred = $q.defer();
228 | var query = this.buildQuery('SELECT');
229 | var cache = ngdbCache.getCache(_repositoryName, query, _formatGet);
230 |
231 | if (cache === false) {
232 | var result = ngdbQuery.make(query['query'], query['binds']);
233 |
234 | result.then(function(result) {
235 | var formated = _formatGet(result);
236 |
237 | deferred.resolve(formated);
238 | ngdbCache.putCache(_repositoryName, query, _formatGet, formated);
239 | }, deferred.reject);
240 | }
241 | else {
242 | deferred.resolve(cache);
243 | }
244 |
245 | return (this.resetBuilder(), deferred.promise);
246 | };
247 |
248 | self.getOne = function() {
249 | var deferred = $q.defer();
250 | var query = this.setLimit(0, 1).buildQuery('SELECT');
251 | var cache = ngdbCache.getCache(_repositoryName, query, _formatGetOne);
252 |
253 | if (cache === false) {
254 | var result = ngdbQuery.make(query['query'], query['binds']);
255 |
256 | result.then(function(result) {
257 | var formated = _formatGetOne(result);
258 |
259 | deferred.resolve(formated);
260 | ngdbCache.putCache(_repositoryName, query, _formatGetOne, formated);
261 | }, deferred.reject);
262 | }
263 | else {
264 | deferred.resolve(cache);
265 | }
266 |
267 | return (this.resetBuilder(), deferred.promise);
268 | };
269 |
270 | self.add = function(data) {
271 | data = ngdbDataConverter.convertDataToAdd(data, _repositorySchema);
272 | var query = this.buildQuery('INSERT', data);
273 | var result = ngdbQuery.make(query['query'], query['binds']);
274 |
275 | _updateCache(result);
276 | return (this.resetBuilder(), result);
277 | };
278 |
279 | self.update = function(data) {
280 | data = ngdbDataConverter.convertDataToAdd(data, _repositorySchema);
281 | var query = this.buildQuery('UPDATE', data);
282 | var result = ngdbQuery.make(query['query'], query['binds']);
283 |
284 | _updateCache(result);
285 | return (this.resetBuilder(), result);
286 | };
287 |
288 | self.delete = function() {
289 | var query = this.buildQuery('DELETE');
290 | var result = ngdbQuery.make(query['query'], query['binds']);
291 |
292 | _updateCache(result);
293 | return (this.resetBuilder(), result);
294 | };
295 |
296 | angular.extend(self, ngdbQueryBuilder);
297 |
298 | return (self);
299 | }
300 | angular
301 | .module('ngDatabase')
302 | .factory('ngdbCache', ngdbCache);
303 |
304 | ngdbCache.$inject = ['ngdbQuery', 'ngdbUtils'];
305 | function ngdbCache(ngdbQuery, ngdbUtils) {
306 | var self = this;
307 | var _cache = {};
308 | var _watchers = [];
309 |
310 | /*
311 | ** CACHE UTILS METHODS
312 | */
313 | var _mergeArray = function(dst, src) {
314 | src && src.forEach(function(val, key) {
315 | dst[key] = src[key];
316 | });
317 | dst && dst.forEach(function(val, key) {
318 | if (!src[key]) {
319 | dst.pop();
320 | }
321 | });
322 |
323 | return (dst);
324 | };
325 |
326 | var _mergeObject = function(dst, src) {
327 | src && ngdbUtils.browseObject(src, function(val, key) {
328 | dst[key] = val;
329 | });
330 | dst && ngdbUtils.browseObject(dst, function(val, key) {
331 | if (!src || !src[key]) {
332 | delete dst[key];
333 | }
334 | });
335 |
336 | return (dst);
337 | };
338 |
339 | var _mergeData = function(dst, src) {
340 | if (src instanceof Array) {
341 | return (_mergeArray(dst, src));
342 | }
343 | else if (src instanceof Object) {
344 | return (_mergeObject(dst, src));
345 | }
346 |
347 | return (_mergeObject(dst, src));
348 | };
349 |
350 | /*
351 | ** WATCH UTILS METHODS
352 | */
353 | var _getWatcher = function(value) {
354 | var ret = false;
355 |
356 | _watchers.some(function(watcher) {
357 | return (watcher['value'] === value && (ret = watcher));
358 | });
359 |
360 | return ((ret === false) ? false : ret);
361 | };
362 |
363 | /*
364 | ** CACHE METHODS
365 | */
366 | self.getCache = function(repositoryName, query, dataFormater) {
367 | var repositoryCache = _cache[repositoryName];
368 | var tmpDataFormater = dataFormater.toString();
369 | var tmpQuery = JSON.stringify(query);
370 | var ret = false;
371 |
372 | repositoryCache && repositoryCache.some(function(bind) {
373 | var bindDataFormater = bind['dataFormater'].toString();
374 | var bindQuery = JSON.stringify(bind['query']);
375 |
376 | return (bindQuery === tmpQuery && bindDataFormater === tmpDataFormater && (ret = bind));
377 | });
378 |
379 | return ((ret === false) ? false : ret['value']);
380 | };
381 |
382 | self.putCache = function(repositoryName, query, dataFormater, value) {
383 | if (!repositoryName || !query || !dataFormater || !value) {
384 | return (0);
385 | }
386 | _cache[repositoryName] = (_cache[repositoryName]) ? _cache[repositoryName] : [];
387 |
388 | _cache[repositoryName].push({
389 | 'query': query,
390 | 'value': value,
391 | 'dataFormater': dataFormater
392 | });
393 | };
394 |
395 | self.updateCache = function(repositoryName) {
396 | var repositoryCache = _cache[repositoryName];
397 |
398 | repositoryCache && repositoryCache.forEach(function(bind) {
399 | var query = ngdbQuery.make(bind['query']['query'], bind['query']['binds']);
400 |
401 | query.then(function(result) {
402 | var newValue = bind['dataFormater'].call(null, result);
403 | var oldValue = angular.copy(bind['value']);
404 |
405 | if (!angular.equals(newValue, oldValue)) {
406 | _mergeData(bind['value'], newValue);
407 | self.callWatcher(bind['value'], oldValue);
408 | }
409 | });
410 | });
411 | };
412 |
413 | /*
414 | ** WATCH METHODS
415 | */
416 | self.putWatcher = function(value, callback) {
417 | var watcher = _getWatcher(value);
418 | this.watcherId = this.watcherId || 0;
419 |
420 | if (watcher) {
421 | watcher['callbacks'].push({
422 | 'id': ++this.watcherId,
423 | 'callback': callback
424 | });
425 |
426 | return (this.watcherId);
427 | }
428 | else {
429 | _watchers.push({
430 | 'value': value,
431 | 'callbacks': []
432 | });
433 |
434 | return (self.putWatcher(value, callback));
435 | }
436 |
437 | return (0);
438 | };
439 |
440 | self.popWatcher = function(watcherId) {
441 | var ret = false;
442 |
443 | _watchers.some(function(watcher, index) {
444 | var tmp = watcher['callbacks'].some(function(callback, index) {
445 | return (callback['id'] === watcherId && (ret = index));
446 | });
447 |
448 | return (tmp && delete _watchers[index]['callbacks'][ret]);
449 | });
450 |
451 | return (!(ret === false));
452 | };
453 |
454 | self.callWatcher = function(newValue, oldValue) {
455 | var watcher = _getWatcher(newValue);
456 |
457 | if (watcher) {
458 | watcher['callbacks'].forEach(function(callback) {
459 | callback['callback'](newValue, oldValue);
460 | });
461 | }
462 | };
463 |
464 | return (self);
465 | }
466 | angular
467 | .module('ngDatabase')
468 | .factory('ngdbDataConverter', ngdbDataConverter);
469 |
470 | ngdbDataConverter.$inject = ['ngdbUtils'];
471 | function ngdbDataConverter(ngdbUtils) {
472 | var self = this;
473 |
474 | /*
475 | ** PRIVATE METHODS
476 | */
477 | var _isJson = function(val) {
478 | var ret = null;
479 |
480 | try {
481 | ret = angular.fromJson(val);
482 | } catch(e) {
483 | return (false);
484 | }
485 |
486 | return (ret);
487 | };
488 |
489 | var _convertObjectToAdd = function(val) {
490 | return (angular.isObject(val) && Object.keys(val).length && angular.toJson(val) || undefined);
491 | };
492 | var _convertArrayToAdd = function(val) {
493 | return (angular.isObject(val) && val.length && angular.toJson(val) || undefined);
494 | };
495 | var _convertObjectToGet = function(val) {
496 | return (_isJson(val) || undefined);
497 | };
498 |
499 | var _convertDateToAdd = function(val) {
500 | return (val instanceof Date && val.getTime() || undefined);
501 | };
502 | var _convertDateToGet = function(val) {
503 | return (isFinite(val) && new Date(val) || undefined);
504 | };
505 |
506 | var _convertNumberToAdd = function(val) {
507 | return (isFinite(val) && parseInt(val, 10) || undefined);
508 | };
509 | var _convertNumberToGet = function(val) {
510 | return (isFinite(val) && parseInt(val, 10) || undefined);
511 | };
512 |
513 | var _convertBoolToAdd = function(val) {
514 | return ((val === true || val === false) ? val.toString() : undefined);
515 | };
516 | var _convertBoolToGet = function(val) {
517 | return ((val === "true") ? true : false);
518 | };
519 |
520 | var _convertDataToAdd = function(data, dataType) {
521 | var converter = {
522 | 'OBJECT': _convertObjectToAdd,
523 | 'ARRAY': _convertArrayToAdd,
524 | 'DATE': _convertDateToAdd,
525 | 'BOOLEAN': _convertBoolToAdd,
526 | 'NUMBER': _convertNumberToAdd
527 | };
528 |
529 | return ((converter[dataType]) ? converter[dataType].call(null, data) : data);
530 | };
531 | var _convertDataToGet = function(data, dataType) {
532 | var converter = {
533 | 'OBJECT': _convertObjectToGet,
534 | 'ARRAY': _convertObjectToGet,
535 | 'DATE': _convertDateToGet,
536 | 'BOOLEAN': _convertBoolToGet,
537 | 'NUMBER': _convertNumberToGet
538 | };
539 |
540 | return ((converter[dataType]) ? converter[dataType].call(null, data) : data);
541 | };
542 | var _convertData = function(data, repositorySchema, fun) {
543 | var formated = (data) ? {} : null;
544 |
545 | ngdbUtils.browseObject(data, function(fieldValue, fieldName) {
546 | if (repositorySchema && repositorySchema[fieldName]) {
547 | var ret = fun(fieldValue, repositorySchema[fieldName]);
548 |
549 | if (ret !== undefined) {
550 | formated[fieldName] = ret;
551 | }
552 | }
553 | });
554 |
555 | return (formated);
556 | };
557 |
558 | /*
559 | ** PUBLIC METHODS
560 | */
561 | self.convertDataToAdd = function(data, repositorySchema) {
562 | return (_convertData(data, repositorySchema, _convertDataToAdd));
563 | };
564 |
565 | self.convertDataToGet = function(data, repositorySchema) {
566 | return (_convertData(data, repositorySchema, _convertDataToGet));
567 | };
568 |
569 | return (self);
570 | }
571 | angular
572 | .module('ngDatabase')
573 | .service('ngdbQueryBuilder', ngdbQueryBuilder);
574 |
575 | ngdbQueryBuilder.$inject = ['ngdbUtils'];
576 | function ngdbQueryBuilder(ngdbUtils) {
577 | var self = this;
578 | /* PRIVATE ATTRIBUTS */
579 | var _queryParams = {
580 | 'data': {'matching': [], 'binds': []},
581 | 'where': {'matching': [], 'binds': []},
582 | 'order': {'matching': [], 'binds': []},
583 | 'limit': {'matching': []},
584 | 'table': null
585 | };
586 |
587 | /*
588 | ** BUILD QUERY METHODS
589 | */
590 | var _buildSelectQuery = function() {
591 | return ("SELECT * FROM `" + _queryParams['table']+ "`");
592 | };
593 |
594 | var _buildUpdateQuery = function() {
595 | var matching = _queryParams['data']['matching'].map(function(val) {
596 | return ("`" + val + "` = ?");
597 | });
598 |
599 | return ("UPDATE `" + _queryParams['table'] + "` SET " + matching.join(","));
600 | };
601 |
602 | var _buildInsertQuery = function() {
603 | var matching = _queryParams['data']['matching'].map(function(val) {
604 | return ("?");
605 | });
606 |
607 | return ("INSERT INTO `" + _queryParams['table'] + "` (`" + _queryParams['data']['matching'].join("`, `") + "`) VALUES (" + matching.join(",") + ")");
608 | };
609 |
610 | var _buildDeleteQuery = function() {
611 | return ("DELETE FROM `" + _queryParams['table'] + "`");
612 | };
613 |
614 | /*
615 | ** BUILD PARAMS METHODS
616 | */
617 | var _buildWhereParam = function() {
618 | var matching = _queryParams['where']['matching'].map(function(val) {
619 | return ("`" + val + "` = ?");
620 | });
621 |
622 | return ("WHERE " + matching.join(" and "));
623 | };
624 |
625 | var _buildOrderParam = function() {
626 | return ("ORDER BY " + _queryParams['order']['matching'].join(","));
627 | };
628 |
629 | var _buildLimitParam = function() {
630 | return ("LIMIT " + _queryParams['limit']['matching'][0] + "," + _queryParams['limit']['matching'][1]);
631 | };
632 |
633 | var _buildQueryParams = function() {
634 | var subParams = [];
635 | var paramsTemplate = {
636 | "where": _buildWhereParam,
637 | "order": _buildOrderParam,
638 | "limit": _buildLimitParam
639 | };
640 |
641 | ngdbUtils.browseObject(_queryParams, function(val, key) {
642 | if (val['matching'] && val['matching'].length && key !== "data") {
643 | subParams.push(paramsTemplate[key].call());
644 | }
645 | });
646 |
647 | return (subParams.join(" "));
648 | };
649 |
650 | /*
651 | ** PROTECTED METHODS
652 | */
653 | self.ngdbQueryBuilderSetRepository = function(repositoryName) {
654 | _queryParams['table'] = repositoryName;
655 |
656 | return (this);
657 | };
658 |
659 | self.setData = function(data) {
660 | ngdbUtils.browseObject(data, function(val, key) {
661 | _queryParams['data']['matching'].push(key);
662 | _queryParams['data']['binds'].push(val);
663 | });
664 | };
665 |
666 | self.buildQuery = function(queryType, data) {
667 | var queryTemplate = {
668 | 'SELECT': _buildSelectQuery,
669 | 'UPDATE': _buildUpdateQuery,
670 | 'INSERT': _buildInsertQuery,
671 | 'DELETE': _buildDeleteQuery
672 | };
673 |
674 | self.setData(data);
675 | var query = queryTemplate[queryType].call() + " " + _buildQueryParams();
676 | var queryBinds = [];
677 |
678 | ngdbUtils.browseObject(_queryParams, function(val) {
679 | if (val['binds'] && val['binds'].length) {
680 | queryBinds = queryBinds.concat(val['binds']);
681 | }
682 | });
683 |
684 | return ({'query': query, 'binds': queryBinds});
685 | };
686 |
687 | self.resetBuilder = function() {
688 | _queryParams = {
689 | 'data': {'matching': [], 'binds': []},
690 | 'where': {'matching': [], 'binds': []},
691 | 'order': {'matching': [], 'binds': []},
692 | 'limit': {'matching': []},
693 | 'table': _queryParams['table']
694 | };
695 | };
696 |
697 | /*
698 | ** SETTERS
699 | */
700 | self.setBy = function(where) {
701 | ngdbUtils.browseObject(where, function(val, key) {
702 | _queryParams['where']['matching'].push(key);
703 | _queryParams['where']['binds'].push(val);
704 | });
705 |
706 | return (this);
707 | };
708 |
709 | self.setOrder = function(order) {
710 | ngdbUtils.browseObject(order, function(val, key) {
711 | _queryParams['order']['matching'].push(key + " " + val);
712 | });
713 |
714 | return (this);
715 | };
716 |
717 | self.setLimit = function(from, to) {
718 | _queryParams['limit']['matching'][0] = parseInt(from, 10);
719 | _queryParams['limit']['matching'][1] = parseInt(to, 10);
720 |
721 | return (this);
722 | };
723 |
724 | return (self);
725 | }
726 | angular
727 | .module('ngDatabase')
728 | .factory('ngdbUtils', ngdbUtils);
729 |
730 | ngdbUtils.$inject = [];
731 | function ngdbUtils() {
732 | var self = this;
733 |
734 | self.browseObject = function(obj, callback) {
735 | for (var key in obj) {
736 | var val = obj[key];
737 |
738 | if (val !== undefined && val !== null) {
739 | callback(val, key);
740 | }
741 | }
742 | };
743 |
744 | self.errorHandler = function(message) {
745 | throw(new Error("NGDB : " + message, "", ""));
746 | };
747 |
748 | return (self);
749 | }
--------------------------------------------------------------------------------
/dist/ngdb.min.js:
--------------------------------------------------------------------------------
1 | function ngdbProvider(n){var t=this;t.repositoriesSchema={};var e=function(t){var e=!0;return ngdbUtils().browseObject(t,function(t){e=n[t]?e:!1}),e};return t.setRepository=function(n,r){return e(r)?(r.id="ID",t.repositoriesSchema[n]=r):ngdbUtils().errorHandler("Unable to create '"+n+"' due to unknown datatype."),t},t.$get=ngdbFactory,t}function ngdbFactory(n,t,e,r,i,a){var u=this,o={},c=function(n){var t={};return e.browseObject(n,function(n,e){t[e]="id"!==e?a[n]:"integer primary key"}),t};return o.createRepositories=function(){var t=[],i=u.repositoriesSchema;return e.browseObject(i,function(n,i){var a=[];n=c(n),e.browseObject(n,function(n,t){a.push("`"+t+"` "+n)}),t.push(r.make("CREATE TABLE IF NOT EXISTS `"+i+"` ("+a.join(", ")+")"))}),n.all(t)},o.getRepository=function(n,e){var r=t.instantiate(ngdbRepository,{ngdbQueryBuilder:t.instantiate(ngdbQueryBuilder)}),i=o.getRepositorySchema(n);return r.ngdbRepositorySetRepository(n,i,e),r},o.getRepositorySchema=function(n){return u.repositoriesSchema[n]||null},o.getQueryMaker=function(){return r},o.putWatcher=function(n,t,e){var r=i.putWatcher(n,t);return(e===!0||"undefined"==typeof e)&&i.callWatcher(n,n),r},o.popWatcher=function(n){return i.popWatcher(n)},o.createRepositories(),o}function ngdbQuery(n,t){var e=this,r=null,i=function(){return r=window.cordova?t.openDB("ngdb.db"):window.openDatabase("ngdb.db","1","ngdb.db",-1)};return e.make=function(t,e){var i=n.defer();return e=void 0!==e&&null!==e?e:[],r.transaction(function(n){n.executeSql(t,e,function(n,t){i.resolve(t)},function(n,t){i.reject(t)})}),i.promise},e.fetchAll=function(n){for(var t=[],e=n.rows.length,r=0;e>r;r++)t.push(n.rows.item(r));return t},e.fetch=function(n){return n.rows.length>0?n.rows.item(0):null},i(),e}function ngdbRepository(n,t,e,r,i,a,u){var o=this,c=!0,d=null,s=null;o.ngdbRepositorySetRepository=function(n,t,e){return d=n,s=t,c=e===!1?!1:!0,i.ngdbQueryBuilderSetRepository(n),o};var l=function(n){var t=r.fetchAll(n);return t&&t.forEach(function(n,e){t[e]=u.convertDataToGet(n,s)}),t},b=function(n){var t=u.convertDataToGet(r.fetch(n),s);return t?t:null},f=function(n){return c?void n.then(function(){a.updateCache(d)}):0};return o.get=function(){var t=n.defer(),e=this.buildQuery("SELECT"),i=a.getCache(d,e,l);if(i===!1){var u=r.make(e.query,e.binds);u.then(function(n){var r=l(n);t.resolve(r),a.putCache(d,e,l,r)},t.reject)}else t.resolve(i);return this.resetBuilder(),t.promise},o.getOne=function(){var t=n.defer(),e=this.setLimit(0,1).buildQuery("SELECT"),i=a.getCache(d,e,b);if(i===!1){var u=r.make(e.query,e.binds);u.then(function(n){var r=b(n);t.resolve(r),a.putCache(d,e,b,r)},t.reject)}else t.resolve(i);return this.resetBuilder(),t.promise},o.add=function(n){n=u.convertDataToAdd(n,s);var t=this.buildQuery("INSERT",n),e=r.make(t.query,t.binds);return f(e),this.resetBuilder(),e},o.update=function(n){n=u.convertDataToAdd(n,s);var t=this.buildQuery("UPDATE",n),e=r.make(t.query,t.binds);return f(e),this.resetBuilder(),e},o.delete=function(){var n=this.buildQuery("DELETE"),t=r.make(n.query,n.binds);return f(t),this.resetBuilder(),t},angular.extend(o,i),o}function ngdbCache(n,t){var e=this,r={},i=[],a=function(n,t){return t&&t.forEach(function(e,r){n[r]=t[r]}),n&&n.forEach(function(e,r){t[r]||n.pop()}),n},u=function(n,e){return e&&t.browseObject(e,function(t,e){n[e]=t}),n&&t.browseObject(n,function(t,r){e&&e[r]||delete n[r]}),n},o=function(n,t){return t instanceof Array?a(n,t):t instanceof Object?u(n,t):u(n,t)},c=function(n){var t=!1;return i.some(function(e){return e.value===n&&(t=e)}),t===!1?!1:t};return e.getCache=function(n,t,e){var i=r[n],a=e.toString(),u=JSON.stringify(t),o=!1;return i&&i.some(function(n){var t=n.dataFormater.toString(),e=JSON.stringify(n.query);return e===u&&t===a&&(o=n)}),o===!1?!1:o.value},e.putCache=function(n,t,e,i){return n&&t&&e&&i?(r[n]=r[n]?r[n]:[],void r[n].push({query:t,value:i,dataFormater:e})):0},e.updateCache=function(t){var i=r[t];i&&i.forEach(function(t){var r=n.make(t.query.query,t.query.binds);r.then(function(n){var r=t.dataFormater.call(null,n),i=angular.copy(t.value);angular.equals(r,i)||(o(t.value,r),e.callWatcher(t.value,i))})})},e.putWatcher=function(n,t){var r=c(n);return this.watcherId=this.watcherId||0,r?(r.callbacks.push({id:++this.watcherId,callback:t}),this.watcherId):(i.push({value:n,callbacks:[]}),e.putWatcher(n,t))},e.popWatcher=function(n){var t=!1;return i.some(function(e,r){var a=e.callbacks.some(function(e,r){return e.id===n&&(t=r)});return a&&delete i[r].callbacks[t]}),!(t===!1)},e.callWatcher=function(n,t){var e=c(n);e&&e.callbacks.forEach(function(e){e.callback(n,t)})},e}function ngdbDataConverter(n){var t=this,e=function(n){var t=null;try{t=angular.fromJson(n)}catch(e){return!1}return t},r=function(n){return angular.isObject(n)&&Object.keys(n).length&&angular.toJson(n)||void 0},i=function(n){return angular.isObject(n)&&n.length&&angular.toJson(n)||void 0},a=function(n){return e(n)||void 0},u=function(n){return n instanceof Date&&n.getTime()||void 0},o=function(n){return isFinite(n)&&new Date(n)||void 0},c=function(n){return isFinite(n)&&parseInt(n,10)||void 0},d=function(n){return isFinite(n)&&parseInt(n,10)||void 0},s=function(n){return n===!0||n===!1?n.toString():void 0},l=function(n){return"true"===n?!0:!1},b=function(n,t){var e={OBJECT:r,ARRAY:i,DATE:u,BOOLEAN:s,NUMBER:c};return e[t]?e[t].call(null,n):n},f=function(n,t){var e={OBJECT:a,ARRAY:a,DATE:o,BOOLEAN:l,NUMBER:d};return e[t]?e[t].call(null,n):n},g=function(t,e,r){var i=t?{}:null;return n.browseObject(t,function(n,t){if(e&&e[t]){var a=r(n,e[t]);void 0!==a&&(i[t]=a)}}),i};return t.convertDataToAdd=function(n,t){return g(n,t,b)},t.convertDataToGet=function(n,t){return g(n,t,f)},t}function ngdbQueryBuilder(n){var t=this,e={data:{matching:[],binds:[]},where:{matching:[],binds:[]},order:{matching:[],binds:[]},limit:{matching:[]},table:null},r=function(){return"SELECT * FROM `"+e.table+"`"},i=function(){var n=e.data.matching.map(function(n){return"`"+n+"` = ?"});return"UPDATE `"+e.table+"` SET "+n.join(",")},a=function(){var n=e.data.matching.map(function(){return"?"});return"INSERT INTO `"+e.table+"` (`"+e.data.matching.join("`, `")+"`) VALUES ("+n.join(",")+")"},u=function(){return"DELETE FROM `"+e.table+"`"},o=function(){var n=e.where.matching.map(function(n){return"`"+n+"` = ?"});return"WHERE "+n.join(" and ")},c=function(){return"ORDER BY "+e.order.matching.join(",")},d=function(){return"LIMIT "+e.limit.matching[0]+","+e.limit.matching[1]},s=function(){var t=[],r={where:o,order:c,limit:d};return n.browseObject(e,function(n,e){n.matching&&n.matching.length&&"data"!==e&&t.push(r[e].call())}),t.join(" ")};return t.ngdbQueryBuilderSetRepository=function(n){return e.table=n,this},t.setData=function(t){n.browseObject(t,function(n,t){e.data.matching.push(t),e.data.binds.push(n)})},t.buildQuery=function(o,c){var d={SELECT:r,UPDATE:i,INSERT:a,DELETE:u};t.setData(c);var l=d[o].call()+" "+s(),b=[];return n.browseObject(e,function(n){n.binds&&n.binds.length&&(b=b.concat(n.binds))}),{query:l,binds:b}},t.resetBuilder=function(){e={data:{matching:[],binds:[]},where:{matching:[],binds:[]},order:{matching:[],binds:[]},limit:{matching:[]},table:e.table}},t.setBy=function(t){return n.browseObject(t,function(n,t){e.where.matching.push(t),e.where.binds.push(n)}),this},t.setOrder=function(t){return n.browseObject(t,function(n,t){e.order.matching.push(t+" "+n)}),this},t.setLimit=function(n,t){return e.limit.matching[0]=parseInt(n,10),e.limit.matching[1]=parseInt(t,10),this},t}function ngdbUtils(){var n=this;return n.browseObject=function(n,t){for(var e in n){var r=n[e];void 0!==r&&null!==r&&t(r,e)}},n.errorHandler=function(n){throw new Error("NGDB : "+n,"","")},n}angular.module("ngDatabase",["ngCordova"]).constant("NGDB_TYPES",{ID:"integer",STRING:"text",NUMBER:"integer",BOOLEAN:"text",OBJECT:"text",ARRAY:"text",DATE:"datetime"}),angular.module("ngDatabase").provider("ngdb",ngdbProvider),ngdbProvider.$inject=["NGDB_TYPES"],ngdbFactory.$inject=["$q","$injector","ngdbUtils","ngdbQuery","ngdbCache","NGDB_TYPES"],angular.module("ngDatabase").factory("ngdbQuery",ngdbQuery),ngdbQuery.$inject=["$q","$cordovaSQLite"],angular.module("ngDatabase").service("ngdbRepository",ngdbRepository),ngdbRepository.$inject=["$q","$injector","ngdbUtils","ngdbQuery","ngdbQueryBuilder","ngdbCache","ngdbDataConverter"],angular.module("ngDatabase").factory("ngdbCache",ngdbCache),ngdbCache.$inject=["ngdbQuery","ngdbUtils"],angular.module("ngDatabase").factory("ngdbDataConverter",ngdbDataConverter),ngdbDataConverter.$inject=["ngdbUtils"],angular.module("ngDatabase").service("ngdbQueryBuilder",ngdbQueryBuilder),ngdbQueryBuilder.$inject=["ngdbUtils"],angular.module("ngDatabase").factory("ngdbUtils",ngdbUtils),ngdbUtils.$inject=[];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-database",
3 | "version": "1.3.5",
4 | "description": "ngDatabase is a very simple and powerful local storage solution for your Ionic hybrid apps.",
5 | "main": "ngdb.min.js",
6 | "keywords": [
7 | "ionic",
8 | "storage",
9 | "sqlite"
10 | ],
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/abellion/ngDatabase.git"
14 | },
15 | "author": "Antoine Bellion (http://antoinebellion.com)",
16 | "license": "ISC"
17 | }
18 |
--------------------------------------------------------------------------------
/src/ngdb.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase', ['ngCordova'])
3 | .constant('NGDB_TYPES', {
4 | ID: 'integer',
5 | STRING: 'text',
6 | NUMBER: 'integer',
7 | BOOLEAN: 'text',
8 | OBJECT: 'text',
9 | ARRAY: 'text',
10 | DATE: 'datetime'
11 | });
12 |
13 | angular
14 | .module('ngDatabase')
15 | .provider('ngdb', ngdbProvider);
16 |
17 | ngdbProvider.$inject = ['NGDB_TYPES'];
18 | function ngdbProvider(NGDB_TYPES) {
19 | var self = this;
20 | self.repositoriesSchema = {};
21 |
22 | var _validRepository = function(repositorySchema) {
23 | var isValid = true;
24 |
25 | ngdbUtils().browseObject(repositorySchema, function(type, name) {
26 | isValid = (NGDB_TYPES[type]) ? isValid : false;
27 | });
28 |
29 | return (isValid)
30 | };
31 |
32 | self.setRepository = function(repositoryName, repositorySchema) {
33 | if (_validRepository(repositorySchema)) {
34 | repositorySchema['id'] = 'ID';
35 |
36 | self.repositoriesSchema[repositoryName] = repositorySchema;
37 | }
38 | else {
39 | ngdbUtils().errorHandler("Unable to create '"+repositoryName+"' due to unknown datatype.");
40 | }
41 |
42 | return (self);
43 | };
44 |
45 | self.$get = ngdbFactory;
46 |
47 | return (self);
48 | }
49 |
50 | ngdbFactory.$inject = ['$q', '$injector', 'ngdbUtils', 'ngdbQuery', 'ngdbCache', 'NGDB_TYPES'];
51 | function ngdbFactory($q, $injector, ngdbUtils, ngdbQuery, ngdbCache, NGDB_TYPES) {
52 | var self = this;
53 | var ngdb = {};
54 |
55 | /*
56 | ** REPOSITORIES
57 | */
58 | var _formatRepository = function(repositorySchema) {
59 | var ret = {};
60 |
61 | ngdbUtils.browseObject(repositorySchema, function(columnType, columnName) {
62 | ret[columnName] = (columnName !== "id") ? NGDB_TYPES[columnType] : 'integer primary key';
63 | });
64 |
65 | return (ret);
66 | };
67 |
68 | ngdb.createRepositories = function() {
69 | var queries = [];
70 | var schema = self.repositoriesSchema;
71 |
72 | ngdbUtils.browseObject(schema, function(table, tableName) {
73 | var columns = [];
74 | table = _formatRepository(table);
75 |
76 | ngdbUtils.browseObject(table, function(columnType, columnName) {
77 | columns.push('`' + columnName + '` ' + columnType);
78 | });
79 |
80 | queries.push(ngdbQuery.make('CREATE TABLE IF NOT EXISTS `' + tableName + '` (' + columns.join(', ') + ')'));
81 | });
82 |
83 | return ($q.all(queries));
84 | };
85 |
86 | ngdb.getRepository = function(repositoryName, binding) {
87 | var repository = $injector.instantiate(ngdbRepository, { 'ngdbQueryBuilder': $injector.instantiate(ngdbQueryBuilder) });
88 | var repositorySchema = ngdb.getRepositorySchema(repositoryName);
89 |
90 | repository.ngdbRepositorySetRepository(repositoryName, repositorySchema, binding);
91 |
92 | return (repository);
93 | };
94 |
95 | ngdb.getRepositorySchema = function(repositoryName) {
96 | return (self.repositoriesSchema[repositoryName] || null);
97 | };
98 |
99 | ngdb.getQueryMaker = function() {
100 | return (ngdbQuery);
101 | };
102 |
103 | /*
104 | ** WATCHERS
105 | */
106 | ngdb.putWatcher = function(value, callback, call) {
107 | var watcherId = ngdbCache.putWatcher(value, callback);
108 |
109 | if (call === true || typeof call === "undefined") {
110 | ngdbCache.callWatcher(value, value);
111 | }
112 |
113 | return (watcherId);
114 | };
115 |
116 | ngdb.popWatcher = function(watcherId) {
117 | return (ngdbCache.popWatcher(watcherId));
118 | };
119 |
120 | return (ngdb.createRepositories(), ngdb);
121 | };
--------------------------------------------------------------------------------
/src/ngdbCache.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .factory('ngdbCache', ngdbCache);
4 |
5 | ngdbCache.$inject = ['ngdbQuery', 'ngdbUtils'];
6 | function ngdbCache(ngdbQuery, ngdbUtils) {
7 | var self = this;
8 | var _cache = {};
9 | var _watchers = [];
10 |
11 | /*
12 | ** CACHE UTILS METHODS
13 | */
14 | var _mergeArray = function(dst, src) {
15 | src && src.forEach(function(val, key) {
16 | dst[key] = src[key];
17 | });
18 | dst && dst.forEach(function(val, key) {
19 | if (!src[key]) {
20 | dst.pop();
21 | }
22 | });
23 |
24 | return (dst);
25 | };
26 |
27 | var _mergeObject = function(dst, src) {
28 | src && ngdbUtils.browseObject(src, function(val, key) {
29 | dst[key] = val;
30 | });
31 | dst && ngdbUtils.browseObject(dst, function(val, key) {
32 | if (!src || !src[key]) {
33 | delete dst[key];
34 | }
35 | });
36 |
37 | return (dst);
38 | };
39 |
40 | var _mergeData = function(dst, src) {
41 | if (src instanceof Array) {
42 | return (_mergeArray(dst, src));
43 | }
44 | else if (src instanceof Object) {
45 | return (_mergeObject(dst, src));
46 | }
47 |
48 | return (_mergeObject(dst, src));
49 | };
50 |
51 | /*
52 | ** WATCH UTILS METHODS
53 | */
54 | var _getWatcher = function(value) {
55 | var ret = false;
56 |
57 | _watchers.some(function(watcher) {
58 | return (watcher['value'] === value && (ret = watcher));
59 | });
60 |
61 | return ((ret === false) ? false : ret);
62 | };
63 |
64 | /*
65 | ** CACHE METHODS
66 | */
67 | self.getCache = function(repositoryName, query, dataFormater) {
68 | var repositoryCache = _cache[repositoryName];
69 | var tmpDataFormater = dataFormater.toString();
70 | var tmpQuery = JSON.stringify(query);
71 | var ret = false;
72 |
73 | repositoryCache && repositoryCache.some(function(bind) {
74 | var bindDataFormater = bind['dataFormater'].toString();
75 | var bindQuery = JSON.stringify(bind['query']);
76 |
77 | return (bindQuery === tmpQuery && bindDataFormater === tmpDataFormater && (ret = bind));
78 | });
79 |
80 | return ((ret === false) ? false : ret['value']);
81 | };
82 |
83 | self.putCache = function(repositoryName, query, dataFormater, value) {
84 | if (!repositoryName || !query || !dataFormater || !value) {
85 | return (0);
86 | }
87 | _cache[repositoryName] = (_cache[repositoryName]) ? _cache[repositoryName] : [];
88 |
89 | _cache[repositoryName].push({
90 | 'query': query,
91 | 'value': value,
92 | 'dataFormater': dataFormater
93 | });
94 | };
95 |
96 | self.updateCache = function(repositoryName) {
97 | var repositoryCache = _cache[repositoryName];
98 |
99 | repositoryCache && repositoryCache.forEach(function(bind) {
100 | var query = ngdbQuery.make(bind['query']['query'], bind['query']['binds']);
101 |
102 | query.then(function(result) {
103 | var newValue = bind['dataFormater'].call(null, result);
104 | var oldValue = angular.copy(bind['value']);
105 |
106 | if (!angular.equals(newValue, oldValue)) {
107 | _mergeData(bind['value'], newValue);
108 | self.callWatcher(bind['value'], oldValue);
109 | }
110 | });
111 | });
112 | };
113 |
114 | /*
115 | ** WATCH METHODS
116 | */
117 | self.putWatcher = function(value, callback) {
118 | var watcher = _getWatcher(value);
119 | this.watcherId = this.watcherId || 0;
120 |
121 | if (watcher) {
122 | watcher['callbacks'].push({
123 | 'id': ++this.watcherId,
124 | 'callback': callback
125 | });
126 |
127 | return (this.watcherId);
128 | }
129 | else {
130 | _watchers.push({
131 | 'value': value,
132 | 'callbacks': []
133 | });
134 |
135 | return (self.putWatcher(value, callback));
136 | }
137 |
138 | return (0);
139 | };
140 |
141 | self.popWatcher = function(watcherId) {
142 | var ret = false;
143 |
144 | _watchers.some(function(watcher, index) {
145 | var tmp = watcher['callbacks'].some(function(callback, index) {
146 | return (callback['id'] === watcherId && (ret = index));
147 | });
148 |
149 | return (tmp && delete _watchers[index]['callbacks'][ret]);
150 | });
151 |
152 | return (!(ret === false));
153 | };
154 |
155 | self.callWatcher = function(newValue, oldValue) {
156 | var watcher = _getWatcher(newValue);
157 |
158 | if (watcher) {
159 | watcher['callbacks'].forEach(function(callback) {
160 | callback['callback'](newValue, oldValue);
161 | });
162 | }
163 | };
164 |
165 | return (self);
166 | }
--------------------------------------------------------------------------------
/src/ngdbDataConverter.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .factory('ngdbDataConverter', ngdbDataConverter);
4 |
5 | ngdbDataConverter.$inject = ['ngdbUtils'];
6 | function ngdbDataConverter(ngdbUtils) {
7 | var self = this;
8 |
9 | /*
10 | ** PRIVATE METHODS
11 | */
12 | var _isJson = function(val) {
13 | var ret = null;
14 |
15 | try {
16 | ret = angular.fromJson(val);
17 | } catch(e) {
18 | return (false);
19 | }
20 |
21 | return (ret);
22 | };
23 |
24 | var _convertObjectToAdd = function(val) {
25 | return (angular.isObject(val) && Object.keys(val).length && angular.toJson(val) || undefined);
26 | };
27 | var _convertArrayToAdd = function(val) {
28 | return (angular.isObject(val) && val.length && angular.toJson(val) || undefined);
29 | };
30 | var _convertObjectToGet = function(val) {
31 | return (_isJson(val) || undefined);
32 | };
33 |
34 | var _convertDateToAdd = function(val) {
35 | return (val instanceof Date && val.getTime() || undefined);
36 | };
37 | var _convertDateToGet = function(val) {
38 | return (isFinite(val) && new Date(val) || undefined);
39 | };
40 |
41 | var _convertNumberToAdd = function(val) {
42 | var isNumber = (!isNaN(parseFloat(val)) && isFinite(val) || undefined);
43 |
44 | return ((isNumber) ? parseInt(val, 10) : undefined);
45 | };
46 | var _convertNumberToGet = function(val) {
47 | var isNumber = (!isNaN(parseFloat(val)) && isFinite(val) || undefined);
48 |
49 | return ((isNumber) ? parseInt(val, 10) : undefined);
50 | };
51 |
52 | var _convertBoolToAdd = function(val) {
53 | return ((val === true || val === false) ? val.toString() : undefined);
54 | };
55 | var _convertBoolToGet = function(val) {
56 | return ((val === "true") ? true : false);
57 | };
58 |
59 | var _convertDataToAdd = function(data, dataType) {
60 | var converter = {
61 | 'OBJECT': _convertObjectToAdd,
62 | 'ARRAY': _convertArrayToAdd,
63 | 'DATE': _convertDateToAdd,
64 | 'BOOLEAN': _convertBoolToAdd,
65 | 'NUMBER': _convertNumberToAdd
66 | };
67 |
68 | return ((converter[dataType]) ? converter[dataType].call(null, data) : data);
69 | };
70 | var _convertDataToGet = function(data, dataType) {
71 | var converter = {
72 | 'OBJECT': _convertObjectToGet,
73 | 'ARRAY': _convertObjectToGet,
74 | 'DATE': _convertDateToGet,
75 | 'BOOLEAN': _convertBoolToGet,
76 | 'NUMBER': _convertNumberToGet
77 | };
78 |
79 | return ((converter[dataType]) ? converter[dataType].call(null, data) : data);
80 | };
81 | var _convertData = function(data, repositorySchema, fun) {
82 | var formated = (data) ? {} : null;
83 |
84 | ngdbUtils.browseObject(data, function(fieldValue, fieldName) {
85 | if (repositorySchema && repositorySchema[fieldName]) {
86 | var ret = fun(fieldValue, repositorySchema[fieldName]);
87 |
88 | if (ret !== undefined) {
89 | formated[fieldName] = ret;
90 | }
91 | }
92 | });
93 |
94 | return (formated);
95 | };
96 |
97 | /*
98 | ** PUBLIC METHODS
99 | */
100 | self.convertDataToAdd = function(data, repositorySchema) {
101 | return (_convertData(data, repositorySchema, _convertDataToAdd));
102 | };
103 |
104 | self.convertDataToGet = function(data, repositorySchema) {
105 | return (_convertData(data, repositorySchema, _convertDataToGet));
106 | };
107 |
108 | return (self);
109 | }
110 |
--------------------------------------------------------------------------------
/src/ngdbQuery.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .factory('ngdbQuery', ngdbQuery);
4 |
5 | ngdbQuery.$inject = ['$q', '$cordovaSQLite'];
6 | function ngdbQuery($q, $cordovaSQLite) {
7 | var self = this;
8 | var _db = null;
9 |
10 | var _dbConnexion = function() {
11 |
12 | _db = (window.cordova) ?
13 | $cordovaSQLite.openDB('ngdb.db') :
14 | window.openDatabase('ngdb.db', '1', 'ngdb.db', -1);
15 |
16 | return (_db);
17 | };
18 |
19 |
20 | self.make = function(query, bindings) {
21 | var deferred = $q.defer();
22 | bindings = (bindings !== undefined && bindings !== null) ? bindings : [];
23 |
24 | _db.transaction(function(transaction) {
25 | transaction.executeSql(query, bindings, function(transaction, result) {
26 | deferred.resolve(result);
27 | }, function(transaction, error) {
28 | deferred.reject(error);
29 | });
30 | });
31 |
32 | return (deferred.promise);
33 | };
34 |
35 | self.fetchAll = function(result) {
36 | var output = [];
37 | var rows = result.rows.length;
38 |
39 | for (var i = 0; i < rows; i++) {
40 | output.push(result.rows.item(i));
41 | }
42 |
43 | return (output);
44 | };
45 |
46 | self.fetch = function(result) {
47 | return ((result.rows.length > 0) ? result.rows.item(0) : null);
48 | };
49 |
50 | return (_dbConnexion(), self);
51 | }
--------------------------------------------------------------------------------
/src/ngdbQueryBuilder.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .service('ngdbQueryBuilder', ngdbQueryBuilder);
4 |
5 | ngdbQueryBuilder.$inject = ['ngdbUtils'];
6 | function ngdbQueryBuilder(ngdbUtils) {
7 | var self = this;
8 | /* PRIVATE ATTRIBUTS */
9 | var _queryParams = {
10 | 'data': {'matching': [], 'binds': []},
11 | 'where': {'matching': [], 'binds': []},
12 | 'order': {'matching': [], 'binds': []},
13 | 'limit': {'matching': []},
14 | 'table': null
15 | };
16 |
17 | /*
18 | ** BUILD QUERY METHODS
19 | */
20 | var _buildSelectQuery = function() {
21 | return ("SELECT * FROM `" + _queryParams['table']+ "`");
22 | };
23 |
24 | var _buildUpdateQuery = function() {
25 | var matching = _queryParams['data']['matching'].map(function(val) {
26 | return ("`" + val + "` = ?");
27 | });
28 |
29 | return ("UPDATE `" + _queryParams['table'] + "` SET " + matching.join(","));
30 | };
31 |
32 | var _buildInsertQuery = function() {
33 | var matching = _queryParams['data']['matching'].map(function(val) {
34 | return ("?");
35 | });
36 |
37 | return ("INSERT INTO `" + _queryParams['table'] + "` (`" + _queryParams['data']['matching'].join("`, `") + "`) VALUES (" + matching.join(",") + ")");
38 | };
39 |
40 | var _buildDeleteQuery = function() {
41 | return ("DELETE FROM `" + _queryParams['table'] + "`");
42 | };
43 |
44 | /*
45 | ** BUILD PARAMS METHODS
46 | */
47 | var _buildWhereParam = function() {
48 | var matching = _queryParams['where']['matching'].map(function(val) {
49 | return ("`" + val + "` = ?");
50 | });
51 |
52 | return ("WHERE " + matching.join(" and "));
53 | };
54 |
55 | var _buildOrderParam = function() {
56 | return ("ORDER BY " + _queryParams['order']['matching'].join(","));
57 | };
58 |
59 | var _buildLimitParam = function() {
60 | return ("LIMIT " + _queryParams['limit']['matching'][0] + "," + _queryParams['limit']['matching'][1]);
61 | };
62 |
63 | var _buildQueryParams = function() {
64 | var subParams = [];
65 | var paramsTemplate = {
66 | "where": _buildWhereParam,
67 | "order": _buildOrderParam,
68 | "limit": _buildLimitParam
69 | };
70 |
71 | ngdbUtils.browseObject(_queryParams, function(val, key) {
72 | if (val['matching'] && val['matching'].length && key !== "data") {
73 | subParams.push(paramsTemplate[key].call());
74 | }
75 | });
76 |
77 | return (subParams.join(" "));
78 | };
79 |
80 | /*
81 | ** PROTECTED METHODS
82 | */
83 | self.ngdbQueryBuilderSetRepository = function(repositoryName) {
84 | _queryParams['table'] = repositoryName;
85 |
86 | return (this);
87 | };
88 |
89 | self.setData = function(data) {
90 | ngdbUtils.browseObject(data, function(val, key) {
91 | _queryParams['data']['matching'].push(key);
92 | _queryParams['data']['binds'].push(val);
93 | });
94 | };
95 |
96 | self.buildQuery = function(queryType, data) {
97 | var queryTemplate = {
98 | 'SELECT': _buildSelectQuery,
99 | 'UPDATE': _buildUpdateQuery,
100 | 'INSERT': _buildInsertQuery,
101 | 'DELETE': _buildDeleteQuery
102 | };
103 |
104 | self.setData(data);
105 | var query = queryTemplate[queryType].call() + " " + _buildQueryParams();
106 | var queryBinds = [];
107 |
108 | ngdbUtils.browseObject(_queryParams, function(val) {
109 | if (val['binds'] && val['binds'].length) {
110 | queryBinds = queryBinds.concat(val['binds']);
111 | }
112 | });
113 |
114 | return ({'query': query, 'binds': queryBinds});
115 | };
116 |
117 | self.resetBuilder = function() {
118 | _queryParams = {
119 | 'data': {'matching': [], 'binds': []},
120 | 'where': {'matching': [], 'binds': []},
121 | 'order': {'matching': [], 'binds': []},
122 | 'limit': {'matching': []},
123 | 'table': _queryParams['table']
124 | };
125 | };
126 |
127 | /*
128 | ** SETTERS
129 | */
130 | self.setBy = function(where) {
131 | ngdbUtils.browseObject(where, function(val, key) {
132 | _queryParams['where']['matching'].push(key);
133 | _queryParams['where']['binds'].push(val);
134 | });
135 |
136 | return (this);
137 | };
138 |
139 | self.setOrder = function(order) {
140 | ngdbUtils.browseObject(order, function(val, key) {
141 | _queryParams['order']['matching'].push(key + " " + val);
142 | });
143 |
144 | return (this);
145 | };
146 |
147 | self.setLimit = function(from, to) {
148 | _queryParams['limit']['matching'][0] = parseInt(from, 10);
149 | _queryParams['limit']['matching'][1] = parseInt(to, 10);
150 |
151 | return (this);
152 | };
153 |
154 | return (self);
155 | }
--------------------------------------------------------------------------------
/src/ngdbRepository.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .service('ngdbRepository', ngdbRepository);
4 |
5 | ngdbRepository.$inject = ['$q', '$injector', 'ngdbUtils', 'ngdbQuery', 'ngdbQueryBuilder', 'ngdbCache', 'ngdbDataConverter'];
6 | function ngdbRepository($q, $injector, ngdbUtils, ngdbQuery, ngdbQueryBuilder, ngdbCache, ngdbDataConverter) {
7 | var self = this;
8 | var _binding = true;
9 | var _repositoryName = null;
10 | var _repositorySchema = null;
11 |
12 | /*
13 | ** UTILS METHODS
14 | */
15 | self.ngdbRepositorySetRepository = function(repositoryName, repositorySchema, binding) {
16 | _repositoryName = repositoryName;
17 | _repositorySchema = repositorySchema;
18 | _binding = (binding === false) ? false : true;
19 |
20 | ngdbQueryBuilder.ngdbQueryBuilderSetRepository(repositoryName);
21 |
22 | return (self);
23 | };
24 |
25 | var _formatGet = function(result) {
26 | var fetched = ngdbQuery.fetchAll(result);
27 |
28 | fetched && fetched.forEach(function(val, index) {
29 | fetched[index] = ngdbDataConverter.convertDataToGet(val, _repositorySchema);
30 | });
31 |
32 | return (fetched);
33 | };
34 |
35 | var _formatGetOne = function(result) {
36 | var fetched = ngdbDataConverter.convertDataToGet(ngdbQuery.fetch(result), _repositorySchema);
37 |
38 | return ((fetched) ? fetched : null);
39 | };
40 |
41 | var _updateCache = function(promise) {
42 | if (!_binding) {
43 | return (0);
44 | }
45 |
46 | promise.then(function() {
47 | ngdbCache.updateCache(_repositoryName);
48 | });
49 | };
50 |
51 | /*
52 | ** USER METHODS
53 | */
54 | self.get = function() {
55 | var deferred = $q.defer();
56 | var query = this.buildQuery('SELECT');
57 | var cache = ngdbCache.getCache(_repositoryName, query, _formatGet);
58 |
59 | if (cache === false) {
60 | var result = ngdbQuery.make(query['query'], query['binds']);
61 |
62 | result.then(function(result) {
63 | var formated = _formatGet(result);
64 |
65 | deferred.resolve(formated);
66 | ngdbCache.putCache(_repositoryName, query, _formatGet, formated);
67 | }, deferred.reject);
68 | }
69 | else {
70 | deferred.resolve(cache);
71 | }
72 |
73 | return (this.resetBuilder(), deferred.promise);
74 | };
75 |
76 | self.getOne = function() {
77 | var deferred = $q.defer();
78 | var query = this.setLimit(0, 1).buildQuery('SELECT');
79 | var cache = ngdbCache.getCache(_repositoryName, query, _formatGetOne);
80 |
81 | if (cache === false) {
82 | var result = ngdbQuery.make(query['query'], query['binds']);
83 |
84 | result.then(function(result) {
85 | var formated = _formatGetOne(result);
86 |
87 | deferred.resolve(formated);
88 | ngdbCache.putCache(_repositoryName, query, _formatGetOne, formated);
89 | }, deferred.reject);
90 | }
91 | else {
92 | deferred.resolve(cache);
93 | }
94 |
95 | return (this.resetBuilder(), deferred.promise);
96 | };
97 |
98 | self.add = function(data) {
99 | data = ngdbDataConverter.convertDataToAdd(data, _repositorySchema);
100 | var query = this.buildQuery('INSERT', data);
101 | var result = ngdbQuery.make(query['query'], query['binds']);
102 |
103 | _updateCache(result);
104 | return (this.resetBuilder(), result);
105 | };
106 |
107 | self.update = function(data) {
108 | data = ngdbDataConverter.convertDataToAdd(data, _repositorySchema);
109 | var query = this.buildQuery('UPDATE', data);
110 | var result = ngdbQuery.make(query['query'], query['binds']);
111 |
112 | _updateCache(result);
113 | return (this.resetBuilder(), result);
114 | };
115 |
116 | self.delete = function() {
117 | var query = this.buildQuery('DELETE');
118 | var result = ngdbQuery.make(query['query'], query['binds']);
119 |
120 | _updateCache(result);
121 | return (this.resetBuilder(), result);
122 | };
123 |
124 | angular.extend(self, ngdbQueryBuilder);
125 |
126 | return (self);
127 | }
--------------------------------------------------------------------------------
/src/ngdbUtils.service.js:
--------------------------------------------------------------------------------
1 | angular
2 | .module('ngDatabase')
3 | .factory('ngdbUtils', ngdbUtils);
4 |
5 | ngdbUtils.$inject = [];
6 | function ngdbUtils() {
7 | var self = this;
8 |
9 | self.browseObject = function(obj, callback) {
10 | for (var key in obj) {
11 | var val = obj[key];
12 |
13 | if (val !== undefined && val !== null) {
14 | callback(val, key);
15 | }
16 | }
17 | };
18 |
19 | self.errorHandler = function(message) {
20 | throw(new Error("NGDB : " + message, "", ""));
21 | };
22 |
23 | return (self);
24 | }
--------------------------------------------------------------------------------