UNPKG

4.22 kBJavaScriptView Raw
1
2var Multi = function(client, MockInterface) {
3 this._MockInterface = MockInterface
4 this._client = client;
5 this._commands = [];
6 this._results = [];
7 this._errors = [];
8 this._discarded = false;
9 this._callbacks = [];
10 this._batch = false;
11};
12
13/**
14 * Add a new command to the queue
15 */
16Multi.prototype._command = function(name, argList) {
17 var self = this;
18 var index = self._commands.length;
19
20 var callBack;
21 var args = argList;
22
23 var lastArg = args[args.length -1];
24 if(typeof lastArg === 'function') {
25 callBack = lastArg;
26 args = args.slice(0, args.length-1);
27 }
28
29 // Add a custom callback that chains the next commands,
30 // or to terminate the queue.
31 var command = args.concat(function (err, result) {
32 if(callBack) {
33 self._callbacks.push(function() {
34 callBack(err, result);
35 if (self._callbacks.length !== 0) {
36 self._MockInterface._callCallback(self._callbacks.shift());
37 }
38 });
39 }
40
41 self._errors[index] = err;
42 self._results[index] = result;
43
44 var nextIndex = index + 1;
45
46 if (self._commands.length === nextIndex) {
47 self._callbacks.push(function() {
48 self._done();
49 });
50 self._MockInterface._callCallback(self._callbacks.shift());
51 } else {
52 var next = function() {
53 self._commands[nextIndex]();
54 }
55 self._MockInterface._callCallback(next)
56 }
57 });
58
59 self._commands.push(function () {
60 self._client[name].apply(self, command)
61 });
62};
63
64/**
65 * called when all commands in the queue are finished
66 */
67Multi.prototype._done = function () {
68 var callBack = this._doneCallback;
69 if (callBack) {
70 var errs = this._errors.filter(function (err) {
71 return err !== null;
72 });
73
74 if (errs.length === 0) {
75 errs = null;
76 }
77
78 callBack(errs, this._results);
79 }
80};
81
82/**
83 * starts running all commands in the queue
84 */
85Multi.prototype.exec = Multi.prototype.exec_atomic = function(callback) {
86 this._doneCallback = callback;
87 if (this._discarded) {
88 var err = new Error('ERR EXEC without MULTI');
89 // In batch mode errors are propagated in values
90 if (this._batch) {
91 this._MockInterface._callCallback(callback, null, [err]);
92 } else {
93 this._MockInterface._callCallback(callback, err);
94 }
95 } else {
96 if (this._commands.length == 0) {
97 this._MockInterface._callCallback(callback, null, []);
98 } else {
99 this._commands[0]();
100 }
101 }
102 return this;
103};
104
105/**
106 * discards the queue
107 */
108Multi.prototype.discard = function (callback) {
109 this._doneCallback = callback;
110 this._commands.length = 0;
111 this._discarded = true;
112 return this;
113};
114
115/**
116 * Make a command (higher order function)
117 */
118var makeCommands = function(names) {
119 names.forEach(function (name) {
120 Multi.prototype[name] = Multi.prototype[name.toUpperCase()] = function () {
121 this._command(name, Array.prototype.slice.call(arguments));
122 //Return this for chaining
123 return this;
124 };
125 });
126};
127
128/**
129 * Mirror of all redis commands
130 */
131makeCommands([
132 'blpop',
133 'brpop',
134 'del',
135 'decr',
136 'decrby',
137 'exists',
138 'expire',
139 'get',
140 'getset',
141 'hdel',
142 'hexists',
143 'hget',
144 'hgetall',
145 'hincrby',
146 'hincrbyfloat',
147 'hkeys',
148 'hlen',
149 'hmget',
150 'hmset',
151 'hset',
152 'hsetnx',
153 'incr',
154 'incrby',
155 'incrbyfloat',
156 'keys',
157 'lindex',
158 'llen',
159 'lpop',
160 'lpush',
161 'lpushx',
162 'lrange',
163 'lrem',
164 'lset',
165 'ltrim',
166 'mget',
167 'mset',
168 'msetnx',
169 'pexpire',
170 'ping',
171 'pttl',
172 'rpop',
173 'rpoplpush',
174 'rpush',
175 'rpushx',
176 'sadd',
177 'sismember',
178 'scard',
179 'send_command',
180 'set',
181 'set',
182 'setex',
183 'setnx',
184 'smembers',
185 'smove',
186 'srem',
187 'ttl',
188 'zadd',
189 'zcard',
190 'zcount',
191 'zincrby',
192 'zrange',
193 'zrangebyscore',
194 'zrank',
195 'zrem',
196 'zremrangebyrank',
197 'zremrangebyscore',
198 'zrevrange',
199 'zrevrangebyscore',
200 'zrevrank',
201 'zscore'
202]);
203
204var multi = function (client, MockInterface, commands, isBatch) {
205 var result = new Multi(client, MockInterface);
206 result._batch = isBatch;
207 if(commands) {
208 commands.forEach(function (command) {
209 result._command(command[0], command.slice(1));
210 });
211 }
212 return result;
213};
214
215module.exports.multi = multi;
216module.exports.Multi = Multi;
\No newline at end of file