1 | process.on('unhandledRejection', rejection => console.error(rejection));
|
2 |
|
3 | var _ = require('lodash');
|
4 | var fs = require('fs');
|
5 | var path = require('path');
|
6 | var Stagger = require('stagger');
|
7 | var request = require('request-promise');
|
8 |
|
9 | var args = process.argv.slice(2);
|
10 |
|
11 | if (args.length < 2) {
|
12 | console.error('Usage: url [doc] db1[,db2,db3...]');
|
13 | process.exit(0);
|
14 | }
|
15 |
|
16 | var DB_URL = args[0];
|
17 | var DB_NAME = args.length === 3 ? args[2] : args[1];
|
18 | var DOC_NAME = args.length === 3 ? args[1] : undefined;
|
19 |
|
20 | var COMMENT_PATTERN = new RegExp('(\\/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)', 'g');
|
21 |
|
22 | var docMap = {};
|
23 |
|
24 | function prepareFn (fn) {
|
25 | fn = fn.toString();
|
26 | fn = fn.replace(COMMENT_PATTERN, '');
|
27 | fn = 'function ' + fn.slice(fn.indexOf('(')).replace(/\t|\n/g, '');
|
28 | return fn;
|
29 | }
|
30 |
|
31 | function prepareDesignDoc (x) {
|
32 | for (var i in x) {
|
33 | if (i[0] !== '_') {
|
34 | if (typeof x[i] === 'function') {
|
35 | x[i] = prepareFn(x[i]);
|
36 | } else if (toString.call(x[i]) === '[object Array]') {
|
37 | x[i] = 'exports.' + x[i][0] + ' = ' + prepareFn(x[i][1]);
|
38 | } else if (typeof x[i] === 'object') {
|
39 | prepareDesignDoc(x[i]);
|
40 | }
|
41 | }
|
42 | }
|
43 | }
|
44 |
|
45 | function getDirs (srcpath) {
|
46 | return fs.readdirSync(srcpath).filter(function (file) {
|
47 | return fs.statSync(path.join(srcpath, file)).isDirectory();
|
48 | });
|
49 | }
|
50 |
|
51 | function deleteOldDesignDocs (newDesignDocs, dbName) {
|
52 | return function (cb) {
|
53 | request({
|
54 | method: 'GET',
|
55 | uri: [DB_URL, dbName, '_all_docs?startkey="_design"&endkey="_design0"&include_docs=true'].join('/'),
|
56 | simple: false,
|
57 | resolveWithFullResponse: true,
|
58 | })
|
59 | .then(
|
60 | function (response) {
|
61 | var result = JSON.parse(response.body);
|
62 |
|
63 | if (result.error) {
|
64 | console.error(dbName, result.error);
|
65 | process.exit(0);
|
66 | }
|
67 |
|
68 | var oldDocs = result.rows.map(function(row) {
|
69 | return row.doc;
|
70 | });
|
71 |
|
72 | oldDocs = oldDocs.filter(function (oldDoc) {
|
73 | return newDesignDocs.indexOf(oldDoc._id.replace('_design/', '')) === -1;
|
74 | });
|
75 |
|
76 | if (!oldDocs.length) {
|
77 | cb();
|
78 | return;
|
79 | }
|
80 |
|
81 | oldDocs = oldDocs.map(oldDoc => ({
|
82 | _id: oldDoc._id,
|
83 | _rev: oldDoc._rev,
|
84 | _deleted: true,
|
85 | }));
|
86 |
|
87 | request({
|
88 | method: 'POST',
|
89 | uri: [DB_URL, dbName, '_bulk_docs'].join('/'),
|
90 | headers: {
|
91 | 'Content-Type': 'application/json',
|
92 | },
|
93 | body: JSON.stringify({
|
94 | docs: oldDocs,
|
95 | }),
|
96 | simple: false,
|
97 | resolveWithFullResponse: true,
|
98 | })
|
99 | .then(
|
100 | function (response) {
|
101 | console.log(dbName, 'deleted', oldDocs.map(function (oldDoc) { return oldDoc._id; }).join(', '));
|
102 |
|
103 | cb();
|
104 | },
|
105 | function (error) {
|
106 | console.error(error.error);
|
107 | process.exit(1);
|
108 | }
|
109 | );
|
110 | },
|
111 | function (error) {
|
112 | console.error(error.error);
|
113 | process.exit(1);
|
114 | }
|
115 | );
|
116 | };
|
117 | }
|
118 |
|
119 | function createNewDesignDocs(dbName, designDocName, designDoc) {
|
120 | return function (cb) {
|
121 | var uri = [DB_URL, dbName, '_design', designDocName].join('/');
|
122 |
|
123 | docMap[uri] = _.cloneDeep(designDoc);
|
124 |
|
125 | request({
|
126 | method: 'GET',
|
127 | uri: uri,
|
128 | simple: false,
|
129 | resolveWithFullResponse: true,
|
130 | })
|
131 | .then(
|
132 | function (response) {
|
133 | var result = JSON.parse(response.body);
|
134 |
|
135 | if (result.error && result.error !== 'not_found') {
|
136 | console.error(dbName, result.error);
|
137 | process.exit(0);
|
138 | }
|
139 |
|
140 | var uri = response.request.uri.href;
|
141 | var dDoc = docMap[uri];
|
142 |
|
143 | if (response.statusCode === 200) {
|
144 | dDoc._rev = JSON.parse(response.body)._rev;
|
145 | }
|
146 |
|
147 | request({
|
148 | method: 'PUT',
|
149 | uri: response.request.uri.href,
|
150 | headers: {
|
151 | 'Content-Type': 'application/json',
|
152 | },
|
153 | body: JSON.stringify(dDoc),
|
154 | simple: true,
|
155 | resolveWithFullResponse: true,
|
156 | })
|
157 | .then(
|
158 | function (response) {
|
159 | var result = JSON.parse(response.body);
|
160 |
|
161 | if (result.error) {
|
162 | console.error(dbName, result.error);
|
163 | process.exit(0);
|
164 | }
|
165 |
|
166 | console.log('%d %s', response.statusCode, response.request.uri.path);
|
167 |
|
168 | cb();
|
169 | },
|
170 | function (error) {
|
171 | console.error('%d %s', error.statusCode, error.response.request.uri.path);
|
172 | process.exit(1);
|
173 | }
|
174 | );
|
175 | },
|
176 | function (error) {
|
177 | console.error(error.error);
|
178 | process.exit(1);
|
179 | }
|
180 | );
|
181 | };
|
182 | }
|
183 |
|
184 | function init() {
|
185 | var newDesignDocs = getDirs(path.resolve(__dirname));
|
186 |
|
187 | var dbs = DB_NAME.split(',');
|
188 |
|
189 | var part1 = new Stagger({
|
190 | requestsPerSecond: 2,
|
191 | });
|
192 |
|
193 | dbs.forEach(function(dbName) {
|
194 | part1.push(deleteOldDesignDocs(newDesignDocs, dbName));
|
195 | });
|
196 |
|
197 | part1.on('finish', function () {
|
198 |
|
199 | var part2 = new Stagger({
|
200 | requestsPerSecond: 2,
|
201 | });
|
202 |
|
203 | newDesignDocs.forEach(function (designDocName) {
|
204 | if (DOC_NAME && DOC_NAME !== designDocName) {
|
205 | return;
|
206 | }
|
207 |
|
208 | var designDoc = require(path.resolve(__dirname, designDocName));
|
209 |
|
210 | prepareDesignDoc(designDoc);
|
211 |
|
212 | dbs.forEach(function(dbName) {
|
213 | part2.push(createNewDesignDocs(dbName, designDocName, designDoc));
|
214 | });
|
215 | });
|
216 |
|
217 | part2.on('finish', function () {
|
218 | console.log('finished');
|
219 | });
|
220 |
|
221 | part2.start();
|
222 |
|
223 | });
|
224 |
|
225 | part1.start();
|
226 | }
|
227 |
|
228 | init();
|