/lodis.js

http://github.com/elcuervo/lodis · JavaScript · 672 lines · 672 code · 0 blank · 0 comment · 108 complexity · 0c8c3cf84ca3a1431ffe1826b0cb1adf MD5 · raw file

  1. (function() {
  2. var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __slice = Array.prototype.slice, __indexOf = Array.prototype.indexOf || function(item) {
  3. for (var i = 0, l = this.length; i < l; i++) {
  4. if (this[i] === item) return i;
  5. }
  6. return -1;
  7. };
  8. this.Lodis = (function() {
  9. function Lodis() {
  10. this._expire_key = __bind(this._expire_key, this); this.storage = window.localStorage;
  11. }
  12. Lodis.prototype._pack = function(value) {
  13. return JSON.stringify(value);
  14. };
  15. Lodis.prototype._unpack = function(value) {
  16. return JSON.parse(value);
  17. };
  18. Lodis.prototype._expire_key = function(key) {
  19. this.del(key);
  20. return delete this._expiration_hash[key];
  21. };
  22. Lodis.prototype._get_set_or_default = function(key, default_value) {
  23. return this._unpack(this.get(key)) || default_value;
  24. };
  25. Lodis.prototype._get_set = function(key) {
  26. return this._get_set_or_default(key, []);
  27. };
  28. Lodis.prototype._extract_from_set = function() {
  29. var item, member, members, result, source, _i, _j, _len, _len2, _ref;
  30. source = arguments[0], members = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  31. result = [];
  32. for (_i = 0, _len = members.length; _i < _len; _i++) {
  33. member = members[_i];
  34. if (__indexOf.call(this.smembers(source), member) >= 0) {
  35. _ref = this._get_set(source);
  36. for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
  37. item = _ref[_j];
  38. if (item !== member) {
  39. result.push(item);
  40. }
  41. }
  42. }
  43. }
  44. return result;
  45. };
  46. Lodis.prototype._get_unpacked = function(key) {
  47. try {
  48. return this._unpack(this.get(key));
  49. } catch (error) {
  50. return this.get(key);
  51. }
  52. };
  53. Lodis.prototype._get_hash = function(key) {
  54. return this._get_set_or_default(key, {});
  55. };
  56. Lodis.prototype._set_packed = function(key, value) {
  57. value = this._pack(value);
  58. return this.set(key, value);
  59. };
  60. Lodis.prototype._get_difference_or_intersection_for_sets = function() {
  61. var action, condition, head, key, keys, other_set, result, set, tail, value, _i, _j, _len, _len2;
  62. action = arguments[0], keys = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  63. if (action == null) {
  64. action = 'DIFF';
  65. }
  66. head = keys[0], tail = 2 <= keys.length ? __slice.call(keys, 1) : [];
  67. set = this._get_set(head);
  68. other_set = result = [];
  69. for (_i = 0, _len = tail.length; _i < _len; _i++) {
  70. key = tail[_i];
  71. other_set = other_set.concat(this._get_set(key));
  72. }
  73. for (_j = 0, _len2 = set.length; _j < _len2; _j++) {
  74. value = set[_j];
  75. condition = (function() {
  76. switch (action.toUpperCase()) {
  77. case 'DIFF':
  78. return __indexOf.call(other_set, value) < 0;
  79. case 'INTER':
  80. return __indexOf.call(other_set, value) >= 0;
  81. }
  82. })();
  83. if (condition) {
  84. result.push(value);
  85. }
  86. }
  87. return result.reverse();
  88. };
  89. Lodis.prototype._get_from_hash = function(key, options) {
  90. var hash, result, value;
  91. if (options == null) {
  92. options = {
  93. with_keys: true,
  94. with_values: true,
  95. only: []
  96. };
  97. }
  98. hash = this._get_hash(key);
  99. result = [];
  100. for (key in hash) {
  101. value = hash[key];
  102. if (options["with_keys"]) {
  103. result.push(key);
  104. }
  105. if (options["with_values"] || (options["only"] && __indexOf.call(options["only"], key) >= 0)) {
  106. result.push(value);
  107. }
  108. }
  109. return result;
  110. };
  111. Lodis.prototype._alter_int_value = function(key, quantity) {
  112. var value;
  113. if (this.exists(key)) {
  114. value = parseInt(this.get(key));
  115. if (typeof value === "number") {
  116. value = value + quantity;
  117. this.set(key, value);
  118. return value;
  119. } else {
  120. throw new Error;
  121. }
  122. }
  123. };
  124. Lodis.prototype._expiration_hash = {};
  125. Lodis.prototype.del = function() {
  126. var key, keys, _i, _len;
  127. keys = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  128. for (_i = 0, _len = keys.length; _i < _len; _i++) {
  129. key = keys[_i];
  130. this.storage.removeItem(key);
  131. }
  132. return true;
  133. };
  134. Lodis.prototype.set = function(key, value) {
  135. this.storage.setItem(key, value);
  136. return true;
  137. };
  138. Lodis.prototype.get = function(key) {
  139. return this.storage.getItem(key);
  140. };
  141. Lodis.prototype.exists = function(key) {
  142. return this.get(key) != null;
  143. };
  144. Lodis.prototype.dbsize = function() {
  145. return this.storage.length;
  146. };
  147. Lodis.prototype.keys = function(regexp) {
  148. var found_keys, i, key, _ref;
  149. found_keys = [];
  150. for (i = 0, _ref = this.dbsize() - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
  151. key = this.storage.key(i);
  152. if (key.match(regexp)) {
  153. found_keys.push(key);
  154. }
  155. }
  156. return found_keys;
  157. };
  158. Lodis.prototype.expire = function(key, seconds) {
  159. var miliseconds, timeout_id;
  160. miliseconds = seconds * 1000;
  161. timeout_id = setTimeout(this._expire_key, miliseconds, key);
  162. this._expiration_hash[key] = {
  163. id: timeout_id,
  164. timeout: new Date().getTime() + miliseconds
  165. };
  166. return true;
  167. };
  168. Lodis.prototype.expireat = function(key, miliseconds) {
  169. var seconds;
  170. if ((miliseconds < new Date().getTime()) || !this.exists(key)) {
  171. return false;
  172. }
  173. seconds = (miliseconds - new Date().getTime()) / 1000;
  174. this.expire(key, seconds);
  175. return true;
  176. };
  177. Lodis.prototype.ttl = function(key) {
  178. if (this.exists(key)) {
  179. if (this._expiration_hash[key]) {
  180. return Math.floor((this._expiration_hash[key].timeout - new Date().getTime()) / 1000);
  181. } else {
  182. return -1;
  183. }
  184. }
  185. };
  186. Lodis.prototype.append = function(key, value) {
  187. if (this.exists(key)) {
  188. return this.set(key, "" + (this.get(key)) + value);
  189. }
  190. };
  191. Lodis.prototype.auth = function(password) {
  192. return true;
  193. };
  194. Lodis.prototype.bgrewriteaof = function() {
  195. return true;
  196. };
  197. Lodis.prototype.bgsave = function() {
  198. return true;
  199. };
  200. Lodis.prototype.blpop = function() {};
  201. Lodis.prototype.lrange = function(key, start, end) {
  202. var result, set;
  203. end += 1;
  204. set = this._get_set(key);
  205. if (end < 1) {
  206. end = set.length + end;
  207. }
  208. result = set.slice(start, end);
  209. if (result.constructor === String) {
  210. result = [result];
  211. }
  212. return result;
  213. };
  214. Lodis.prototype.lpush = function(key, item) {
  215. var set;
  216. set = this._get_set(key);
  217. set.unshift(item);
  218. return this._set_packed(key, set);
  219. };
  220. Lodis.prototype.rpush = function(key, item) {
  221. var set;
  222. set = this._get_set(key);
  223. set.push(item);
  224. return this._set_packed(key, set);
  225. };
  226. Lodis.prototype.rpushx = function(key, item) {
  227. if (this.exists(key)) {
  228. return this.rpush(key, item);
  229. }
  230. };
  231. Lodis.prototype.decr = function(key) {
  232. return this.decrby(key, 1);
  233. };
  234. Lodis.prototype.incr = function(key) {
  235. return this.incrby(key, 1);
  236. };
  237. Lodis.prototype.decrby = function(key, quantity) {
  238. if (quantity == null) {
  239. quantity = 1;
  240. }
  241. return this._alter_int_value(key, -quantity);
  242. };
  243. Lodis.prototype.incrby = function(key, quantity) {
  244. if (quantity == null) {
  245. quantity = 1;
  246. }
  247. return this._alter_int_value(key, quantity);
  248. };
  249. Lodis.prototype.echo = function(message) {
  250. return message;
  251. };
  252. Lodis.prototype.flushall = function() {
  253. return this.storage.clear();
  254. };
  255. Lodis.prototype.flushdb = function() {
  256. return this.flushall();
  257. };
  258. Lodis.prototype.getrange = function(key, start, end) {
  259. var string;
  260. if (this.exists(key)) {
  261. string = this.get(key);
  262. if (start < 0) {
  263. start = string.length + start;
  264. }
  265. if (end < 0) {
  266. end = string.length + end;
  267. }
  268. return string.substr(start, end + 1);
  269. }
  270. };
  271. Lodis.prototype.getset = function(key, value) {
  272. var old_value;
  273. if (this.exists(key)) {
  274. old_value = this.get(key);
  275. this.set(key, value);
  276. return old_value;
  277. }
  278. };
  279. Lodis.prototype.hset = function(hash_key, key, value) {
  280. var hash;
  281. hash = this._get_hash(hash_key);
  282. hash[key] = value;
  283. this._set_packed(hash_key, hash);
  284. return true;
  285. };
  286. Lodis.prototype.hget = function(hash_key, key) {
  287. var hash;
  288. if (this.exists(hash_key)) {
  289. hash = this._get_hash(hash_key);
  290. return hash[key];
  291. }
  292. };
  293. Lodis.prototype.hgetall = function(hash_key) {
  294. if (this.exists(hash_key)) {
  295. return this._get_from_hash(hash_key);
  296. }
  297. };
  298. Lodis.prototype.hexists = function(hash_key, key) {
  299. return this.hget(hash_key, key) != null;
  300. };
  301. Lodis.prototype.hkeys = function(hash_key) {
  302. if (this.exists(hash_key)) {
  303. return this._get_from_hash(hash_key, {
  304. with_keys: true,
  305. with_values: false
  306. });
  307. }
  308. };
  309. Lodis.prototype.hlen = function(hash_key) {
  310. if (this.exists(hash_key)) {
  311. return this.hkeys(hash_key).length;
  312. }
  313. };
  314. Lodis.prototype.hincrby = function(hash_key, key, quantity) {
  315. var new_value, old_value;
  316. if (this.hexists(hash_key, key)) {
  317. old_value = parseInt(this.hget(hash_key, key));
  318. if (typeof old_value === "number") {
  319. new_value = old_value + quantity;
  320. this.hset(hash_key, key, new_value);
  321. return new_value;
  322. } else {
  323. throw new Error("Invalid type");
  324. }
  325. }
  326. };
  327. Lodis.prototype.hmget = function() {
  328. var hash_key, keys;
  329. hash_key = arguments[0], keys = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  330. if (this.exists(hash_key)) {
  331. return this._get_from_hash(hash_key, {
  332. with_values: true,
  333. with_keys: false,
  334. only: keys
  335. });
  336. }
  337. };
  338. Lodis.prototype.hmset = function() {
  339. var hash_key, i, keys_and_values, result, value;
  340. hash_key = arguments[0], keys_and_values = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  341. result = {};
  342. for (i in keys_and_values) {
  343. value = keys_and_values[i];
  344. if (i % 2) {
  345. result[keys_and_values[i - 1]] = value;
  346. }
  347. }
  348. return this._set_packed(hash_key, result);
  349. };
  350. Lodis.prototype.hsetnx = function(hash_key, key, value) {
  351. if (!this.exists(hash_key)) {
  352. this.hset(hash_key, key, value);
  353. return true;
  354. } else {
  355. return false;
  356. }
  357. };
  358. Lodis.prototype.hvals = function(hash_key) {
  359. if (this.exists(hash_key)) {
  360. return this._get_from_hash(hash_key, {
  361. with_keys: false,
  362. with_values: true
  363. });
  364. }
  365. };
  366. Lodis.prototype.lindex = function(key, index) {
  367. var hash;
  368. if (this.exists(key)) {
  369. hash = this._get_set(key);
  370. if (index < 0) {
  371. index = hash.length + index;
  372. }
  373. return hash[index] || false;
  374. }
  375. };
  376. Lodis.prototype.linsert = function(key, direction, reference_value, value) {
  377. var left_side, result, right_side, set, _ref;
  378. if (this.exists(key)) {
  379. direction = (function() {
  380. switch (direction.toUpperCase()) {
  381. case "BEFORE":
  382. return -1;
  383. case "AFTER":
  384. return 1;
  385. }
  386. })();
  387. set = this._get_set(key);
  388. reference_value = set.indexOf(reference_value) + direction;
  389. _ref = [set.slice(0, reference_value), set.slice(reference_value)], left_side = _ref[0], right_side = _ref[1];
  390. result = left_side.concat([value]);
  391. result = result.concat(right_side);
  392. return this._set_packed(key, result);
  393. }
  394. };
  395. Lodis.prototype.llen = function(key) {
  396. var set;
  397. if (this.exists(key)) {
  398. set = this._get_set(key);
  399. return set.length;
  400. }
  401. };
  402. Lodis.prototype.lpop = function(key) {
  403. var set, value;
  404. if (this.exists(key)) {
  405. set = this._get_set(key);
  406. value = set.slice(1);
  407. this._set_packed(key, value);
  408. return value;
  409. }
  410. };
  411. Lodis.prototype.lpushx = function(key, value) {
  412. if (this.exists(key)) {
  413. return this.lpush(key, value);
  414. } else {
  415. return false;
  416. }
  417. };
  418. Lodis.prototype.lrem = function(key, count, item) {
  419. var quantity, result, set, value, _i, _len;
  420. if (this.exists(key)) {
  421. quantity = Math.abs(count);
  422. set = this._get_set(key);
  423. if (count < 0) {
  424. set = set.reverse();
  425. }
  426. result = [];
  427. for (_i = 0, _len = set.length; _i < _len; _i++) {
  428. value = set[_i];
  429. if (value === item && quantity > 0) {
  430. quantity -= 1;
  431. } else {
  432. result.push(value);
  433. }
  434. }
  435. if (count < 0) {
  436. result = result.reverse();
  437. }
  438. return this._set_packed(key, result);
  439. }
  440. };
  441. Lodis.prototype.lset = function(key, index, value) {
  442. var set;
  443. if (this.exists(key)) {
  444. set = this._get_set(key);
  445. if (index < 0) {
  446. index = set.length + index;
  447. }
  448. set[index] = value;
  449. return this._set_packed(key, set);
  450. }
  451. };
  452. Lodis.prototype.ltrim = function(key, start, end) {
  453. var result, set;
  454. if (this.exists(key)) {
  455. set = this._get_set(key);
  456. if (end < 0) {
  457. end = set.length + end;
  458. }
  459. result = set.slice(start, (end + 1) || 9e9);
  460. return this._set_packed(key, result);
  461. }
  462. };
  463. Lodis.prototype.mget = function() {
  464. var key, keys, result, _i, _len;
  465. keys = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  466. result = [];
  467. for (_i = 0, _len = keys.length; _i < _len; _i++) {
  468. key = keys[_i];
  469. result.push(this.get(key));
  470. }
  471. return result;
  472. };
  473. Lodis.prototype.mset = function() {
  474. var i, keys_and_values, value, _results;
  475. keys_and_values = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  476. _results = [];
  477. for (i in keys_and_values) {
  478. value = keys_and_values[i];
  479. if (i % 2) {
  480. _results.push(this.set(keys_and_values[i - 1], value));
  481. }
  482. }
  483. return _results;
  484. };
  485. Lodis.prototype.msetnx = function() {
  486. var i, key_or_value, keys_and_values;
  487. keys_and_values = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  488. for (i in keys_and_values) {
  489. key_or_value = keys_and_values[i];
  490. if (!(i % 2) && this.exists(key_or_value)) {
  491. return;
  492. }
  493. }
  494. return this.mset.apply(this, keys_and_values);
  495. };
  496. Lodis.prototype.persist = function(key) {
  497. if (this.exists(key)) {
  498. if (this._expiration_hash[key]) {
  499. clearTimeout(this._expiration_hash[key].id);
  500. return delete this._expiration_hash[key];
  501. }
  502. }
  503. };
  504. Lodis.prototype.ping = function() {
  505. return "PONG";
  506. };
  507. Lodis.prototype.randomkey = function() {
  508. var keys;
  509. keys = this.keys();
  510. return keys[Math.floor(Math.random() * keys.length)];
  511. };
  512. Lodis.prototype.rename = function(key, new_key) {
  513. var value;
  514. value = this.get(key);
  515. this.del(key);
  516. return this.set(new_key, value);
  517. };
  518. Lodis.prototype.renamenx = function(key, new_key) {
  519. if (!this.exists(new_key)) {
  520. return this.rename(key, new_key);
  521. }
  522. };
  523. Lodis.prototype.rpop = function(key) {
  524. var set, value;
  525. if (this.exists(key)) {
  526. set = this._get_set(key);
  527. value = set.pop();
  528. this._set_packed(key, set);
  529. return value;
  530. }
  531. };
  532. Lodis.prototype.rpoplpush = function(hash_key, other_hash_key) {
  533. var value;
  534. if (this.exists(hash_key)) {
  535. value = this.rpop(hash_key);
  536. this.lpush(other_hash_key, value);
  537. return value;
  538. }
  539. };
  540. Lodis.prototype.sadd = function() {
  541. var key, member, members, set, _i, _len, _results;
  542. key = arguments[0], members = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  543. set = this._get_set(key);
  544. _results = [];
  545. for (_i = 0, _len = members.length; _i < _len; _i++) {
  546. member = members[_i];
  547. if (__indexOf.call(set, member) < 0) {
  548. _results.push(this.lpush(key, member));
  549. }
  550. }
  551. return _results;
  552. };
  553. Lodis.prototype.smembers = function(key) {
  554. if (this.exists(key)) {
  555. return this._get_set(key);
  556. }
  557. };
  558. Lodis.prototype.save = function() {
  559. return true;
  560. };
  561. Lodis.prototype.scard = function(key) {
  562. return this._get_set(key).length;
  563. };
  564. Lodis.prototype.sdiff = function() {
  565. var keys;
  566. keys = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  567. return this._get_difference_or_intersection_for_sets.apply(this, ['DIFF'].concat(__slice.call(keys)));
  568. };
  569. Lodis.prototype.sdiffstore = function() {
  570. var destination, keys;
  571. destination = arguments[0], keys = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  572. return this._set_packed(destination, this.sdiff.apply(this, keys));
  573. };
  574. Lodis.prototype.select = function(db) {
  575. return db === 0;
  576. };
  577. Lodis.prototype.setex = function(key, expire, value) {
  578. this.set(key, value);
  579. return this.expire(key, expire);
  580. };
  581. Lodis.prototype.setnx = function(key, value) {
  582. if (!this.exists(key)) {
  583. return this.set(key, value);
  584. }
  585. };
  586. Lodis.prototype.setrange = function(key, offset, value) {
  587. var i, old_value, result;
  588. old_value = (function() {
  589. if (this.exists(key)) {
  590. return this.get(key).substr(0, offset);
  591. } else {
  592. result = new String;
  593. for (i = 0; 0 <= offset ? i < offset : i > offset; 0 <= offset ? i++ : i--) {
  594. result += " ";
  595. }
  596. return result;
  597. }
  598. }).call(this);
  599. return this.set(key, "" + old_value + value);
  600. };
  601. Lodis.prototype.shutdown = function() {
  602. return true;
  603. };
  604. Lodis.prototype.sinter = function() {
  605. var keys;
  606. keys = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  607. return this._get_difference_or_intersection_for_sets.apply(this, ['INTER'].concat(__slice.call(keys)));
  608. };
  609. Lodis.prototype.sinterstore = function() {
  610. var destination, keys;
  611. destination = arguments[0], keys = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  612. return this._set_packed(destination, this.sinter.apply(this, keys));
  613. };
  614. Lodis.prototype.sismember = function(key, value) {
  615. var set;
  616. if (this.exists(key)) {
  617. set = this._get_set(key);
  618. return set.indexOf(value) > -1;
  619. }
  620. };
  621. Lodis.prototype.smove = function(source, destination, member) {
  622. var result;
  623. if (this.exists(source)) {
  624. if (__indexOf.call(this.smembers(source), member) >= 0) {
  625. result = this._extract_from_set(source, member);
  626. this._set_packed(source, result);
  627. this.rpush(destination, member);
  628. return true;
  629. } else {
  630. return false;
  631. }
  632. }
  633. };
  634. Lodis.prototype.spop = function(key) {
  635. var set;
  636. if (this.exists(key)) {
  637. set = this._get_set(key);
  638. set.pop();
  639. return this._set_packed(key, set);
  640. }
  641. };
  642. Lodis.prototype.srandmember = function(key) {
  643. var set;
  644. if (this.exists(key)) {
  645. set = this._get_set(key);
  646. return set[Math.floor(Math.random() * set.length)];
  647. }
  648. };
  649. Lodis.prototype.srem = function() {
  650. var key, members, result, set;
  651. key = arguments[0], members = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  652. if (this.exists(key)) {
  653. set = this._get_set(key);
  654. result = this._extract_from_set.apply(this, [key].concat(__slice.call(members)));
  655. return this._set_packed(key, result);
  656. }
  657. };
  658. Lodis.prototype.strlen = function(key) {
  659. if (this.exists(key)) {
  660. return this.get(key).length;
  661. } else {
  662. return 0;
  663. }
  664. };
  665. Lodis.prototype.type = function(key) {
  666. if (this.exists(key)) {
  667. return this._get_unpacked(key).constructor.name.toLowerCase();
  668. }
  669. };
  670. return Lodis;
  671. })();
  672. }).call(this);