index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. var Promise = require('bluebird');
  2. var async = require('async');
  3. var _ = require('underscore');
  4. /*
  5. idea:
  6. systems can register to be run whenever certain components are created, modified, or deleted
  7. they would be run normally, as for all entities/components
  8. perhaps another way is to have a system be able to run at certain intervals or threshholds
  9. with just the changed components/entities
  10. alternately, systems could specify to run only for components that match some sql conditions,
  11. perhaps just a basic set of </>/= conditions
  12. */
  13. // TODO TODO TODO
  14. // run a create system retroactively to fill in empty components
  15. // getEntityWithComponentValue(compType, value, cb);
  16. function nt(cb, err) {
  17. console.log(err);
  18. process.nextTick(function() { cb(err) });
  19. }
  20. module.exports = function(config, db, modCB) {
  21. var types = {};
  22. var typeNames = {};
  23. var typeInternal = {};
  24. var typeExternal = {};
  25. var validActionList = ['create', 'delete', 'presave', 'postsave', 'fetch'];
  26. function prefillActionArrays() {
  27. var o = {};
  28. validActionList.map(function(k) { o[k] = []; });
  29. return o;
  30. }
  31. var actionHooks = {
  32. series: prefillActionArrays(),
  33. parallel: prefillActionArrays(),
  34. };
  35. function refreshTypes(cb) {
  36. db.query('SELECT * from `types`;', function(err, data) {
  37. if(err) return cb(err);
  38. types = Object.create(null); // ids keyed by name
  39. typeNames = Object.create(null); // names keyed by id
  40. typeInternal = Object.create(null); // data types keyed by id
  41. typeExternal = Object.create(null); // external coerced types keyed by id
  42. for(var i = 0; i < data.length; i++) {
  43. types[data[i].name] = parseInt(data[i].typeID);
  44. typeNames[parseInt(data[i].typeID)] = data[i].name;
  45. typeExternal[parseInt(data[i].typeID)] = data[i].externalType;
  46. var dtype;
  47. if(data[i].is_double) dtype = 'double';
  48. else if(data[i].is_int) dtype = 'int';
  49. else if(data[i].is_string) dtype = 'string';
  50. else if(data[i].is_date) dtype = 'date';
  51. typeInternal[parseInt(data[i].typeID)] = dtype;
  52. }
  53. cb(null);
  54. });
  55. };
  56. function colForCompID(id) {
  57. return typeToDataCol(typeInternal[id]);
  58. }
  59. function typeToBoolCol(str) {
  60. return {
  61. 'double': 'is_double',
  62. 'string': 'is_string',
  63. 'int': 'is_int',
  64. 'date': 'is_date',
  65. }[str];
  66. }
  67. function typeToDataCol(str) {
  68. return {
  69. 'double': 'data_double',
  70. 'string': 'data_string',
  71. 'int': 'data_int',
  72. 'date': 'data_date',
  73. }[str];
  74. }
  75. var CES = {};
  76. // return a copy of the type list
  77. CES.listTypes = function(cb) {
  78. var list = {};
  79. _.map(types, function(id, name) {
  80. list[id] = {
  81. name: name,
  82. id: id,
  83. dataType: typeInternal[id],
  84. externalType: typeExternal[id],
  85. };
  86. });
  87. cb(null, list);
  88. };
  89. // returns new type id
  90. CES.createType = function(name, type, externalType, cb) {
  91. name = name.replace(/^\s+/, '').replace(/\s+$/, '');
  92. if(name == '') {
  93. return nt(cb, "no type name given");
  94. }
  95. // neutered to test the db version of this
  96. if(types[name]) {
  97. return nt(cb, "Type name already exists.")
  98. }
  99. var tcol = {
  100. 'double': 'is_double',
  101. 'string': 'is_string',
  102. 'int': 'is_int',
  103. 'date': 'is_date',
  104. }[type];
  105. var q = 'INSERT INTO `types` (`name`, `'+tcol+'`, `externalType`) VALUES (?, true, ?);';
  106. db.query(q, [name, externalType], function(err, res) {
  107. if(err) {
  108. if(err.code == 'ER_DUP_ENTRY') {
  109. return nt(cb, "type name already exists.");
  110. }
  111. return nt(cb, err);
  112. }
  113. var id = parseInt(res.insertId);
  114. // update the local type lookups
  115. types[name] = id;
  116. typeNames[id] = name;
  117. typeInternal[id] = type;
  118. cb(null, id);
  119. });
  120. }
  121. // used to make sure a schema of sorts exists and is valid
  122. // does not depend on data caches or application state
  123. CES.ensureTypes = function(typeInfo, cb) {
  124. // format of type info
  125. // typeInfo = [
  126. // '<componentName>': {
  127. // internalType: 'int'|'double'|'string'|'date',
  128. // externalType: ''|'int'|'double'|'string'|'date'|'bool'|'json',
  129. // }
  130. db.query('SELECT * from `types`;', function(err, data) {
  131. var cur = _.indexBy(data, 'name');
  132. var missing = {};
  133. var wrong = {};
  134. var wonky = {};
  135. _.map(typeInfo, function(ti, name) {
  136. if(!cur[name]) {
  137. missing[name] = ti;
  138. return;
  139. }
  140. var c = cur[name];
  141. var internalType;
  142. if(c.is_double) internalType = 'double';
  143. else if(c.is_int) internalType = 'int';
  144. else if(c.is_string) internalType = 'string';
  145. else if(c.is_date) internalType = 'date';
  146. if(internalType != ti.internalType) {
  147. wrong[name] = {cur: c, wanted: ti};
  148. return;
  149. }
  150. if(c.externalType != ti.externalType) {
  151. wonky[name] = {cur: c, wanted: ti};
  152. return;
  153. }
  154. });
  155. // insert the missing ones
  156. async.parallel(_.map(missing, function(ti, name) {
  157. return function(acb) {
  158. CES.createType(name, ti.internalType, ti.externalType || '', acb);
  159. }
  160. }), function(err) {
  161. if(err) return nt(cb, err);
  162. if(Object.keys(wrong).length) err = "wrong data";
  163. cb(err, wrong, wonky);
  164. });
  165. });
  166. }
  167. // returns the new entity id
  168. CES.listEntities = function(cb) {
  169. var q = '' +
  170. 'SELECT ' +
  171. ' e.*, '+
  172. ' c1.data_string as `name`, ' +
  173. ' c2.data_string as `type` ' +
  174. 'from `entities` e ' +
  175. 'left join components c1 on e.eid = c1.eid ' +
  176. 'inner join types t1 on c1.typeID = t1.typeID ' +
  177. 'left join components c2 on e.eid = c2.eid ' +
  178. 'inner join types t2 on c2.typeID = t2.typeID ' +
  179. 'WHERE ' +
  180. ' e.deleted = false ' +
  181. ' AND t1.name = \'name\' ' +
  182. ' AND t2.name = \'type\' ' +
  183. ';'
  184. db.query(q, function(err, res) {
  185. if(err) return nt(cb, err);
  186. //console.log(res);
  187. cb(err, res);
  188. });
  189. };
  190. // returns the new entity id
  191. CES.createEntity = function(cb) {
  192. //console.log(name, type);
  193. var q = 'INSERT INTO `entities` (`eid`) VALUES (NULL);';
  194. db.query(q, function(err, res) {
  195. //console.log('entity created', err)
  196. if(err) return nt(cb, err);
  197. // TODO: how does this work again?
  198. cb(null, res.insertId);
  199. });
  200. };
  201. // returns the new entity id
  202. CES.createEntityWithComps = function(compList, cb) {
  203. var eid = CES.createEntity( function(err, eid) {
  204. if(err) return nt(cb, err);
  205. //console.log('created entity ' + eid)
  206. compList.eid = eid;
  207. CES.runSystem('create', compList, function(err) {
  208. CES.setComponentList(eid, compList, function(err2) {
  209. cb(err, eid);
  210. });
  211. });
  212. });
  213. };
  214. CES.deleteEntity = function(eid, cb) {
  215. var q = 'UPDATE `entities` SET `deleted` = true WHERE `eid` = ?;';
  216. db.query(q, [eid], function(err, res) {
  217. cb(err);
  218. });
  219. };
  220. CES.getComponent = function(eid, compName, cb) {
  221. var q = '' +
  222. ' SELECT ' +
  223. ' t.`name`, ' +
  224. ' c.`data_double`, ' +
  225. ' c.`data_int`, ' +
  226. ' c.`data_date`, ' +
  227. ' c.`data_string`, ' +
  228. ' t.`is_double`, ' +
  229. ' t.`is_int`, ' +
  230. ' t.`is_date`, ' +
  231. ' t.`is_string` ' +
  232. ' FROM `types` t ' +
  233. ' LEFT JOIN `components` c ON c.`typeID` = t.`typeID` ' +
  234. ' WHERE ' +
  235. ' c.`eid` = ? ' +
  236. ' AND t.`name` = ?;';
  237. var typeId = types[compName];
  238. if(!typeId) {
  239. return nt(cb, "no such component");
  240. }
  241. db.query(q, [eid, compName], function(err, res) {
  242. if(err) return nt(cb, err);
  243. var list = Object.create(null);
  244. list.eid = eid;
  245. for(var i = 0; i < res.rows.length; i++) {
  246. var data;
  247. var row = res.rows[i];
  248. if(row.is_double) data = data_double;
  249. else if(row.is_int) data = data_int;
  250. else if(row.is_date) data = data_date;
  251. else if(row.is_string) data = data_string;
  252. list[row.name] = data;
  253. }
  254. cb(null, list);
  255. });
  256. };
  257. CES.getAllComponents = function(eid, cb) {
  258. //console.log("fetching components")
  259. var q = '' +
  260. ' SELECT ' +
  261. ' t.`name`, ' +
  262. ' c.`data_double`, ' +
  263. ' c.`data_int`, ' +
  264. ' c.`data_date`, ' +
  265. ' c.`data_string`, ' +
  266. ' t.`is_double`, ' +
  267. ' t.`is_int`, ' +
  268. ' t.`is_date`, ' +
  269. ' t.`is_string` ' +
  270. ' FROM `components` c ' +
  271. ' LEFT JOIN `types` t ON c.`typeID` = t.`typeID` ' +
  272. ' WHERE c.`eid` = ?;';
  273. db.query(q, [eid], function(err, res) {
  274. if(err) return nt(cb, err);
  275. if(!res) {
  276. console.log('no components found');
  277. return cb(null, {});
  278. }
  279. var list = Object.create(null);
  280. list.eid = eid;
  281. for(var i = 0; i < res.length; i++) {
  282. var data;
  283. var row = res[i];
  284. if(row.is_double) data = row.data_double;
  285. else if(row.is_int) data = row.data_int;
  286. else if(row.is_date) data = row.data_date;
  287. else if(row.is_string) data = row.data_string;
  288. list[row.name] = data;
  289. }
  290. cb(null, list);
  291. });
  292. };
  293. CES.fetchEntitesByID = function(eids, cb) {
  294. var q = '' +
  295. ' SELECT ' +
  296. ' c.`eid`, ' +
  297. ' t.`name`, ' +
  298. ' c.`data_double`, ' +
  299. ' c.`data_int`, ' +
  300. ' c.`data_date`, ' +
  301. ' c.`data_string`, ' +
  302. ' t.`is_double`, ' +
  303. ' t.`is_int`, ' +
  304. ' t.`is_date`, ' +
  305. ' t.`is_string` ' +
  306. ' FROM `components` c ' +
  307. ' LEFT JOIN `types` t ON c.`typeID` = t.`typeID` ' +
  308. ' WHERE c.`eid` IN ? AND NOT e.`deleted`;';
  309. db.query(q, [eids], function(err, res) {
  310. if(err) return nt(cb, err);
  311. if(!res) {
  312. console.log('no components found');
  313. return cb(null, {});
  314. }
  315. var entities = {};
  316. var list = Object.create(null);
  317. list.eid = eid;
  318. for(var i = 0; i < res.length; i++) {
  319. var data;
  320. var row = res[i];
  321. if(row.is_double) data = row.data_double;
  322. else if(row.is_int) data = row.data_int;
  323. else if(row.is_date) data = row.data_date;
  324. else if(row.is_string) data = row.data_string;
  325. list[row.name] = data;
  326. }
  327. cb(null, list);
  328. });
  329. };
  330. CES.setComponent = function(eid, comp, value, cb) {
  331. var typeID = types[comp];
  332. var dcol = typeToDataCol(typeInternal[typeID]);
  333. var ins = 'REPLACE INTO `components` (`eid`, `typeID`, `'+dcol+'`) VALUES (?, ?, ?);';
  334. db.query(ins, [eid, typeID, value], cb);
  335. };
  336. // HACK not exactly efficient...
  337. CES.setComponentList = function(eid, compList, cb) {
  338. async.parallel(_.map(compList, function(value, comp) {
  339. return function(acb) {
  340. CES.setComponent(eid, comp, value, acb);
  341. }
  342. }), cb);
  343. };
  344. // expects eid to be in the entity object
  345. CES.updateEntity = function(ent, cb) {
  346. var eid = ent.eid;
  347. if(!eid) return cb(new Error('eid not found'));
  348. var u = _.reduce(ent, function(acc, v, k) {
  349. if(k == 'eid') return acc;
  350. acc.push(function(acb) {
  351. CES.setComponent(eid, k, v, acb);
  352. });
  353. return acc;
  354. }, []);
  355. async.parallel(u, cb);
  356. };
  357. CES.removeComponent = function(eid, comps, cb) {
  358. var del = 'DELETE FROM `components` WHERE `eid` = ? AND `typeID` = ?;';
  359. var typeID = types[comp];
  360. db.query(del, [eid, typeID], function(err, res) {
  361. if(err) return nt(cb, err);
  362. cb(null);
  363. });
  364. };
  365. CES.fetchEntitiesWithAllComps = function(compNames, cb) {
  366. var compIDs = [];
  367. var joins = [];
  368. _.map(types, function(v, k) {
  369. if(-1 === compNames.indexOf(k)) return;
  370. compIDs.push(v);
  371. });
  372. joins = compIDs.map(function(id, index) {
  373. var alias = '`c' + index + '`';
  374. return 'INNER JOIN `components` '+alias+' ON ' +
  375. '`e`.`eid` = '+alias+'.`eid` AND ' +
  376. alias+'.`typeID` = ' + Number(id);
  377. });
  378. var q = '' +
  379. 'SELECT ' +
  380. ' e.* ' +
  381. 'FROM `entities` e ' +
  382. joins.join('\n') +
  383. 'WHERE NOT e.`deleted`' +
  384. ';';
  385. db.query(q, [compIDs], function(err, res) {
  386. if(err) return nt(cb, err);
  387. //console.log(res);
  388. cb(err, res);
  389. });
  390. }
  391. CES.fetchEntitiesWithAnyComps = function(compNames, cb) {
  392. var sub = '' +
  393. 'SELECT ' +
  394. ' e.eid ' +
  395. 'FROM `entities` e ' +
  396. 'INNER JOIN `components` c ON e.eid = c.eid ' +
  397. 'WHERE ' +
  398. ' c.`typeID` IN (?) ' +
  399. ' AND NOT e.`deleted` ' +
  400. '';
  401. var q = '' +
  402. 'SELECT ' +
  403. ' c.* ' +
  404. 'FROM components c '+
  405. 'WHERE c.eid IN ('+sub+');'
  406. var compIDs = [];
  407. _.map(types, function(v, k) {
  408. if(-1 !== compNames.indexOf(k)) compIDs.push(v);
  409. });
  410. db.query(q, [compIDs], function(err, res) {
  411. if(err) return nt(cb, err);
  412. //console.log(res);
  413. cb(err, rowsToEntities(res));
  414. });
  415. };
  416. CES.findEntity = function(searchFields, _opts, _cb) {
  417. var cb = _cb;
  418. var opts = _opts;
  419. if(typeof(_opts) == 'function') {
  420. cb = _opts;
  421. opts = {};
  422. }
  423. var limit = _opts.limit || 0;
  424. var offset = _opts.offset || -1;
  425. var compIDs = [];
  426. var joins = [];
  427. var wheres = [];
  428. var args = [];
  429. var index = 0;
  430. _.map(searchFields, function(v, k) {
  431. var id = types[k];
  432. if(!id) return;
  433. var alias = '`c' + index + '`';
  434. joins.push('INNER JOIN `components` '+alias+' ON ' +
  435. '`e`.`eid` = '+alias+'.`eid` AND ' +
  436. alias+'.`typeID` = ' + Number(id));
  437. var col = typeToDataCol(typeInternal[id]);
  438. wheres.push(' '+alias+'.'+col+ ' = ? ');
  439. args.push(v);
  440. index++;
  441. });
  442. var sub = '' +
  443. 'SELECT ' +
  444. ' e.eid ' +
  445. 'FROM `entities` e ' +
  446. ' ' + joins.join('\n') + ' ' +
  447. 'WHERE ' +
  448. ' e.`deleted` = false ' +
  449. ' AND ' + wheres.join(' AND ') +
  450. '';
  451. if(limit > 0) {
  452. sub += ' LIMIT ' + parseInt(limit) + ' ';
  453. if(offset > 0) {
  454. sub += ' OFFSET ' + parseInt(offset) + ' ';
  455. }
  456. }
  457. var q = '' +
  458. 'SELECT ' +
  459. ' c.* ' +
  460. 'FROM components c '+
  461. 'WHERE c.eid IN ('+sub+');'
  462. db.query(q, args, function(err, res) {
  463. if(err) return nt(cb, err);
  464. cb(null, rowsToEntities(res));
  465. });
  466. };
  467. function rowsToEntities(res) {
  468. var entities = {};
  469. for(var i = 0; i < res.length; i++) {
  470. var eid = res[i].eid | 0;
  471. var val = res[i][colForCompID(res[i].typeID)];
  472. if(typeof entities[eid] != 'object') entities[eid] = {eid: eid};
  473. entities[eid][typeNames[res[i].typeID]] = val;
  474. }
  475. return entities;
  476. }
  477. // empty/null comp list means any
  478. CES.registerSystem = function(action, compList, _options, _fn) {
  479. var fn = _fn,
  480. options = _options;
  481. if(typeof options == 'function') {
  482. options = {}
  483. fn = _options;
  484. }
  485. var defaults = {
  486. filterMode: 'all',
  487. prefetch: false,
  488. series: false,
  489. }
  490. options = Object.assign({}, defaults, options);
  491. var syncMode = options.series ? 'series' : 'parallel';
  492. if(-1 === validActionList.indexOf(action)) {
  493. console.log('invalid action: ' + action);
  494. return false;
  495. }
  496. if(!(actionHooks[syncMode][action] instanceof Array))
  497. actionHooks[syncMode][action] = [];
  498. var cl = null;
  499. if(compList instanceof Array && compList.length) cl = compList.slice();
  500. actionHooks[syncMode][action].push({
  501. comps: cl,
  502. mode: options.filterMode,
  503. fn: fn,
  504. });
  505. };
  506. function hasAllComps(entity, compList) {
  507. for(var i = 0; i < compList.length; i++) {
  508. if(!Object.prototype.hasOwnProperty.call(entity, compList[i]))
  509. return false;
  510. }
  511. return true;
  512. }
  513. function hasAnyComps(entity, compList) {
  514. for(var i = 0; i < compList.length; i++) {
  515. if(Object.prototype.hasOwnProperty.call(entity, compList[i]))
  516. return true;
  517. }
  518. return false;
  519. }
  520. function hasComps(mode, entity, compList) {
  521. return {
  522. any: hasAnyComps,
  523. all: hasAllComps,
  524. }[mode](entity, compList);
  525. }
  526. // mutates entity
  527. CES.runSystem = function(action, entity, cb) {
  528. var hooksSeries = actionHooks.series[action];
  529. var hooksParallel = actionHooks.parallel[action];
  530. var dirty = false;
  531. async.mapSeries(hooksSeries, function(h, acb) {
  532. if(h.comps !== null && !hasComps(h.mode, entity, h.comps)) {
  533. return acb(null);
  534. }
  535. // TODO: pass in db transaction rather than raw db
  536. h.fn(entity, CES, db, function(err, d) {
  537. dirty = dirty || d;
  538. acb(err);
  539. });
  540. }, function(err) {
  541. if(err) return cb(err);
  542. async.map(hooksParallel, function(h, acb) {
  543. if(h.comps !== null && !hasComps(h.mode, entity, h.comps)) {
  544. return acb(null);
  545. }
  546. h.fn(entity, CES, db, function(err, d) {
  547. dirty = dirty || d;
  548. acb(err);
  549. });
  550. }, function(err) {
  551. cb(err, dirty);
  552. });
  553. });
  554. };
  555. // user auth info is stroed independently so it isn't accidentally leaked
  556. // don't store passwords or sesitive credentials in normal components
  557. CES.createUser = function(status, cb) {
  558. var q = 'INSERT INTO `users` (`status`, `joinedAt`, `lastLoginAt`) VALUES (?, NOW(), NULL);';
  559. db.query(q, [status], function(err, res) {
  560. cb(err, res ? parseInt(res.insertId) : null);
  561. });
  562. };
  563. CES.getUser = function(uid, cb) {
  564. var q = 'SELECT * FROM `users` WHERE `uid` = ?;';
  565. db.query(q, [uid], cb);
  566. };
  567. CES.setUserStatus = function(uid, status, cb) {
  568. var q = 'UPDATE `users` SET `status` = ? WHERE uid = ?;'
  569. db.query(q, [status, uid], cb);
  570. };
  571. CES.updateUserLogin = function(uid, cb) {
  572. var q = 'UPDATE `users` SET `lastLoginAt` = NOW() WHERE uid = ?;'
  573. db.query(q, [uid], cb);
  574. };
  575. CES.addUserClaim = function(claim, cb) {
  576. var q = 'INSERT INTO `user_claims` ( '+
  577. ' `uid`, '+
  578. ' `type`, '+
  579. ' `status`, '+
  580. ' `providerID`, '+
  581. ' `authData`, ' +
  582. ' `activatedAt`, ' +
  583. ' `lastLoginAt` ' +
  584. ') VALUES (?,?,?,?,?, NOW(), NULL);';
  585. db.query(q, [
  586. claim.uid,
  587. claim.type,
  588. claim.status,
  589. claim.providerID,
  590. claim.authData,
  591. ], cb);
  592. };
  593. CES.updateUserClaimLogin = function(uid, claimType, cb) {
  594. var q = 'UPDATE `user_claims` SET `lastLoginAt` = NOW() WHERE `uid` = ? AND `type` = ?;'
  595. db.query(q, [uid, claimType], cb);
  596. };
  597. CES.updateUserClaimStatus = function(uid, claimType, status, cb) {
  598. var q = 'UPDATE `user_claims` SET `status` = ? WHERE `uid` = ? AND `type` = ?;'
  599. db.query(q, [status, uid, claimType], cb);
  600. };
  601. CES.updateUserClaimData = function(uid, claimType, authData, cb) {
  602. var q = 'UPDATE `user_claims` SET `authData` = ? WHERE `uid` = ? AND `type` = ?;'
  603. db.query(q, [authData, uid, claimType], cb);
  604. };
  605. CES.getUserClaims = function(uid, cb) {
  606. var q = 'SELECT * FROM `user_claims` WHERE `uid` = ?;'
  607. db.query(q, [uid], cb);
  608. };
  609. CES.getUserClaimByProvider = function(providerID, claimType, cb) {
  610. var q = 'SELECT * FROM `user_claims` WHERE `providerID` = ? AND `type` = ?;'
  611. db.query(q, [providerID, claimType], function(err, row) {
  612. if(err) return cb(err);
  613. if(!row.length) return cb(new Error("claim '"+claimType+"' not found for providerID '"+providerID+"'"));
  614. cb(null, row[0]);
  615. });
  616. };
  617. // CES.runSystem = function(comp, sysFn) {
  618. // var comps = components[comp];
  619. // if(!comps) return 0;
  620. //
  621. // var cnt = 0;
  622. // for(var eid in comps) {
  623. // var ent = CES.getAllComponents(eid);
  624. // sysFn(ent, eid);
  625. //
  626. // cnt++;
  627. // }
  628. // return cnt;
  629. // }
  630. refreshTypes(modCB);
  631. return CES;
  632. };