@xuda.io/xuda-db-adapter-module 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.mjs +899 -0
  2. package/package.json +8 -0
package/index.mjs ADDED
@@ -0,0 +1,899 @@
1
+ const _this = {};
2
+
3
+ export const init_module = async (e) => {
4
+ _this.func = e.func;
5
+ _this.glb = e.glb;
6
+ _this.SESSION_OBJ = e.SESSION_OBJ;
7
+ _this.APP_OBJ = e.APP_OBJ;
8
+ _this.IS_DOCKER = e.IS_DOCKER;
9
+ _this.IS_API_SERVER = e.IS_API_SERVER;
10
+ _this.IS_PROCESS_SERVER = e.IS_PROCESS_SERVER;
11
+ if (!_this.xuda_dbs_plugin && typeof _this.IS_DOCKER === 'undefined' && typeof _this.IS_PROCESS_SERVER === 'undefined' && typeof _this.IS_API_SERVER === 'undefined') {
12
+ await init_xuda_dbs_plugin(e.SESSION_ID);
13
+ }
14
+ _this.db_replication_store;
15
+ _this.db_changes_store;
16
+ _this.db_replication_from_stat = 3;
17
+ _this.db_replication_to_stat = 3;
18
+ };
19
+
20
+ export let _db = {};
21
+
22
+ _db.save_data = async function (SESSION_ID, dsSessionP, keyP) {
23
+ // const app_id = _this.SESSION_OBJ[SESSION_ID].app_id;
24
+
25
+ var db_driver = await this.get_db_driver(SESSION_ID, dsSessionP);
26
+ if (db_driver === 'pouchdb' && _this.glb.IS_WORKER) {
27
+ var callback_id = _this.func.utils.set_callback_queue(SESSION_ID, callbackP);
28
+ var obj = _this.func.utils.clean_returned_datasource(SESSION_ID, dsSessionP);
29
+ return _this.func.utils.post_back_to_client(SESSION_ID, 'execute_local_sava_data', _this.SESSION_OBJ[SESSION_ID].worker_id, {
30
+ ds_obj: obj,
31
+ dsSessionP: dsSessionP,
32
+ keyP: keyP,
33
+ callback_id: callback_id,
34
+ });
35
+ }
36
+
37
+ _db.save_indicator(SESSION_ID, true);
38
+
39
+ var _ds = _this.SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
40
+
41
+ let _view_obj = await _this.func.utils.VIEWS_OBJ.get(SESSION_ID, _ds.prog_id);
42
+
43
+ var dataSourceTableId = _view_obj?.progDataSource?.dataSourceTableId;
44
+
45
+ if (!dataSourceTableId) {
46
+ _db.save_indicator(SESSION_ID, false);
47
+ _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0105'); //Table entry missing
48
+ return;
49
+ }
50
+
51
+ var db_driver = await _db.get_db_driver(SESSION_ID, dsSessionP);
52
+
53
+ let table_ret = await _this.func.utils.FILES_OBJ.get(SESSION_ID, dataSourceTableId);
54
+
55
+ if (!table_ret.tableIndexes || _.isEmpty(table_ret.tableIndexes)) {
56
+ _db.save_indicator(SESSION_ID, false);
57
+ _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0104'); //index missing
58
+ return;
59
+ }
60
+
61
+ if (!_ds.data_feed.rows) {
62
+ return console.error('data_feed rows is empty');
63
+ }
64
+
65
+ const clean_virtual_fields = async function (table_id, data) {
66
+ let table_obj = await func.utils.VIEWS_OBJ.get(SESSION_ID, table_id);
67
+ var data_obj = {};
68
+ for (const [key, val] of Object.entries(data)) {
69
+ const _tableFieldsObj = func.common.find_item_by_key(table_obj.tableFields, 'field_id', key);
70
+ if (_tableFieldsObj) {
71
+ data_obj[key] = val;
72
+ }
73
+ }
74
+ return data_obj;
75
+ };
76
+ let save_ret;
77
+ // component
78
+ if (_view_obj.properties.menuType === 'component') {
79
+ if (_view_obj?.properties?.rwMode !== 'U') {
80
+ return _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0126'); //Program Read Only
81
+ }
82
+
83
+ // check if rows exist
84
+ // ==============
85
+ // add
86
+ //===============
87
+ let data = { prog_id: _ds.prog_id };
88
+ if (_ds.data_feed.rows_added?.length) {
89
+ if (!_view_obj?.properties?.allowCreate) {
90
+ _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0120'); //Create Mode Denied
91
+ }
92
+
93
+ _.forEach(_ds.data_feed.rows_added, function (val, key) {
94
+ data[key] = val;
95
+ });
96
+
97
+ delete _ds.data_feed.rows_added['newRecord'];
98
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_create', data, {}, dsSessionP);
99
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
100
+ row_id: save_ret.data.id,
101
+ table_id: dataSourceTableId,
102
+ });
103
+ return save_ret;
104
+ }
105
+ // ==============
106
+ // delete
107
+ //===============
108
+ if (_ds.data_feed.rows_deleted?.length) {
109
+ data.table_id = _ds._dataSourceTableId;
110
+ data.ids = [];
111
+ for await (const [key, val] of Object.entries(_ds.data_feed.rows_deleted)) {
112
+ data.ids.push(val);
113
+
114
+ try {
115
+ const row_idx = func.common.find_ROWID_idx(_ds, val);
116
+
117
+ delete _ds.data_feed.rows[row_idx];
118
+ } catch (error) {}
119
+ }
120
+ _ds.data_feed.rows_deleted = [];
121
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_delete', data, {}, dsSessionP);
122
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
123
+ row_id: save_ret.data?.id?.[0],
124
+ table_id: dataSourceTableId,
125
+ });
126
+ return save_ret;
127
+ }
128
+ // ==============
129
+ // update
130
+ //===============
131
+ if (_ds.data_feed.rows_changed?.length) {
132
+ for await (const [key, row_id] of Object.entries(_ds.data_feed.rows_changed)) {
133
+ if (row_id === 'datasource_main') continue;
134
+
135
+ let data = { prog_id: _ds.prog_id };
136
+
137
+ try {
138
+ const row_idx = func.common.find_ROWID_idx(_ds, row_id);
139
+
140
+ data.table_data = await clean_virtual_fields(_ds._dataSourceTableId, _ds.data_feed.rows[row_idx]);
141
+ } catch (err) {
142
+ console.error(err);
143
+ }
144
+
145
+ data.table_id = _ds._dataSourceTableId;
146
+ data.row_id = row_id;
147
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_update', data, {}, dsSessionP);
148
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
149
+ row_id: save_ret.data?.id?.[0],
150
+ table_id: dataSourceTableId,
151
+ });
152
+ }
153
+ return save_ret;
154
+ }
155
+ return;
156
+ }
157
+ // alert Program Read Only
158
+ if (_view_obj.properties.menuType !== 'set_data') {
159
+ return _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0126'); //Program Read Only
160
+ }
161
+
162
+ // set_data
163
+ var mode = _ds.set_mode; //screenInfo.crudMode;
164
+
165
+ if (!mode || mode === 'U') {
166
+ let data = { prog_id: _ds.prog_id };
167
+ data.table_id = _ds._dataSourceTableId;
168
+ data.row_id = _ds.currentRecordId;
169
+ data.table_data = {};
170
+
171
+ try {
172
+ const row_idx = func.common.find_ROWID_idx(_ds, _ds.currentRecordId);
173
+
174
+ data.table_data = await clean_virtual_fields(_ds._dataSourceTableId, _ds.data_feed.rows[row_idx]);
175
+ } catch (err) {
176
+ console.error(err);
177
+ }
178
+
179
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_update', data, {}, dsSessionP);
180
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
181
+ row_id: save_ret.data?.id?.[0],
182
+ table_id: dataSourceTableId,
183
+ });
184
+ }
185
+ if (mode === 'D') {
186
+ // _id = _ds.key._id;
187
+ let data = { prog_id: _ds.prog_id };
188
+ data.table_id = _ds._dataSourceTableId;
189
+ data.ids = [_ds.currentRecordId];
190
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_delete', data, {}, dsSessionP);
191
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
192
+ row_id: save_ret.data?.id?.[0],
193
+ table_id: dataSourceTableId,
194
+ });
195
+ return save_ret;
196
+ }
197
+ if (mode === 'C') {
198
+ if (_view_obj.properties.crudMode !== 'C' && _view_obj.properties.crudMode === 'U' && !_view_obj.properties.allowCreate) {
199
+ return _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0120'); //Create Mode Denied
200
+ }
201
+
202
+ let data = { prog_id: _ds.prog_id };
203
+ data.table_id = _ds._dataSourceTableId;
204
+
205
+ try {
206
+ const row_idx = func.common.find_ROWID_idx(_ds, _ds.currentRecordId);
207
+
208
+ data.table_data = _ds.data_feed.rows[row_idx];
209
+ save_ret = await _this.func.common.db(SESSION_ID, 'dbs_create', data, {}, dsSessionP);
210
+ refresh_document_changes_for_realtime_update(SESSION_ID, {
211
+ row_id: save_ret.data.id,
212
+ table_id: dataSourceTableId,
213
+ });
214
+ return save_ret;
215
+ } catch (err) {
216
+ console.error(err);
217
+ }
218
+ }
219
+ };
220
+
221
+ _db.get_db_driver = async function (SESSION_ID, dsSessionP) {
222
+ var db_driver;
223
+
224
+ if (dsSessionP) {
225
+ var _ds = _this.SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
226
+ let _view_obj = await _this.func.utils.VIEWS_OBJ.get(SESSION_ID, _ds.prog_id);
227
+ var dataSourceTableId = _view_obj?.progDataSource?.dataSourceTableId;
228
+
229
+ if (!dataSourceTableId) {
230
+ _this.func.utils.alerts.invoke(SESSION_ID, 'system_msg', 'SYS_MSG_0105'); //Table repository missing
231
+ return;
232
+ }
233
+ let file_ret = await _this.func.utils.FILES_OBJ.get(SESSION_ID, dataSourceTableId);
234
+ db_driver = file_ret.properties.db_driver || 'xuda';
235
+ }
236
+
237
+ if (_this.SESSION_OBJ[SESSION_ID].engine_mode === 'live_preview' && !db_driver && _this.SESSION_OBJ[SESSION_ID].app_id === 'temp') {
238
+ db_driver = 'pouchdb';
239
+ }
240
+
241
+ return db_driver;
242
+ };
243
+ _db.get_query = async function (
244
+ SESSION_ID,
245
+ table_id,
246
+ queryP,
247
+ dsSessionP,
248
+ viewSourceDescP,
249
+ sourceP,
250
+ reduceP,
251
+ skipP,
252
+ limitP,
253
+ countP,
254
+ idsP,
255
+ sortModel,
256
+ sort_dir,
257
+ filterModel = {
258
+ filterModelNative,
259
+ filterModelMongo,
260
+ filterModelSql,
261
+ filterModelUserMongo,
262
+ filterModelUserSql,
263
+ },
264
+ dataSourceFilterModelType = 'index',
265
+ total_fields_info,
266
+ ) {
267
+ const get_fields = async function (_ds) {
268
+ var fields = [];
269
+ const _view_obj = await _this.func.utils.VIEWS_OBJ.get(SESSION_ID, _ds.prog_id);
270
+ if (_view_obj.progFields) {
271
+ for (let val of _view_obj.progFields) {
272
+ if (val.data.type === 'table') {
273
+ fields.push(val.data.field_id);
274
+ }
275
+ }
276
+ }
277
+ return fields;
278
+ };
279
+ const run_local = async function () {
280
+ if (!_this.SESSION_OBJ[SESSION_ID]) return;
281
+
282
+ if (!_this.SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP]) return;
283
+ var ds = _this.SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
284
+ var v = ds.v;
285
+
286
+ var query_string;
287
+ if (queryP.indexId) {
288
+ if (countP && queryP.desc) {
289
+ query_string = `startkey=${JSON.stringify(queryP.endkey)}&endkey=${JSON.stringify(queryP.startkey)}`;
290
+ } else {
291
+ query_string = `startkey=${JSON.stringify(queryP.startkey)}&endkey=${JSON.stringify(queryP.endkey)}&desc=${queryP.desc}`;
292
+ }
293
+ } else {
294
+ query_string = 'key=' + queryP.table_id;
295
+ }
296
+ var db_driver = await _db.get_db_driver(SESSION_ID, dsSessionP);
297
+ var fields_arr = await get_fields(ds);
298
+
299
+ const response = {
300
+ success: async function (json) {
301
+ if (dsSessionP && !_this.SESSION_OBJ[SESSION_ID]?.DS_GLB?.[dsSessionP]) {
302
+ return;
303
+ }
304
+
305
+ if (json.code < 0) {
306
+ response.error(json.data);
307
+ return;
308
+ }
309
+ var data = json.data;
310
+ // if (!countP)
311
+ // //!reduceP &&
312
+ // data = {
313
+ // rows: data.rows.map((item) => ({
314
+ // ...item.value,
315
+ // _ROWID: item.id,
316
+ // })),
317
+ // };
318
+
319
+ // const get_locate = function (data) {
320
+ // var ret = false;
321
+ // _this.$_each2(data, function (key, val) {
322
+ // if (
323
+ // val >= v.locateQuery.startkey[2][key] &&
324
+ // val <= v.locateQuery.endkey[2][key]
325
+ // ) {
326
+ // ret = true;
327
+ // } else {
328
+ // ret = false;
329
+ // return;
330
+ // }
331
+ // });
332
+ // return ret;
333
+ // };
334
+
335
+ if (dsSessionP)
336
+ _this.func.utils.debug.log(SESSION_ID, ds._dataSourceTableId, {
337
+ module: ds.viewModule,
338
+ action: 'read',
339
+ prop: sourceP,
340
+ details: query_string,
341
+ result: data.rows ? data.rows.length : 0,
342
+ error: null,
343
+ source: viewSourceDescP,
344
+ json: data,
345
+ fields: _.assignIn(ds.locate_from, ds.locate_to),
346
+ type: 'file',
347
+ dsSession: dsSessionP,
348
+ });
349
+
350
+ return data;
351
+ },
352
+ error: async function (err) {
353
+ if (dsSessionP && !ds) return;
354
+ if (dsSessionP) {
355
+ var err_msg = err && err.data ? err.data : err;
356
+ _this.func.utils.debug.log(SESSION_ID, _this.SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP]._dataSourceTableId, {
357
+ module: ds.viewModule,
358
+ action: 'read',
359
+ prop: sourceP,
360
+ details: query_string,
361
+ result: null,
362
+ error: err_msg,
363
+ source: viewSourceDescP,
364
+ json: null,
365
+ fields: _.assignIn(ds.locate_from, ds.locate_to),
366
+ type: 'file',
367
+ dsSession: dsSessionP,
368
+ });
369
+ }
370
+ _this.func.utils.debug_report(SESSION_ID, 'datasource couchDB query ' + sourceP, err_msg, 'E');
371
+
372
+ return {
373
+ rows: [],
374
+ error: true,
375
+ };
376
+ },
377
+ };
378
+
379
+ var data = {
380
+ desc: queryP.desc,
381
+ indexId: queryP.indexId,
382
+ key: queryP.table_id,
383
+ reduce: reduceP,
384
+ viewSourceDesc: viewSourceDescP,
385
+ limit: limitP,
386
+ skip: skipP,
387
+ count: countP,
388
+ ids: idsP,
389
+ table_id: queryP.table_id,
390
+ prog_id: ds.prog_id,
391
+ };
392
+
393
+ data.filter_from = JSON.stringify(queryP.filter_from);
394
+ data.filter_to = JSON.stringify(queryP.filter_to);
395
+ data.sortOrder = queryP.sortOrder;
396
+ data.table_id = queryP.table_id;
397
+
398
+ data.startkey = JSON.stringify(queryP.startkey);
399
+ data.endkey = JSON.stringify(queryP.endkey);
400
+
401
+ if (countP && queryP.desc) {
402
+ data.sortOrder = 'asc';
403
+ data.startkey = JSON.stringify(queryP.endkey);
404
+ data.endkey = JSON.stringify(queryP.startkey);
405
+ }
406
+
407
+ data.dataSourceFilterModelType = dataSourceFilterModelType;
408
+ // if (dataSourceFilterModelType === "query") {
409
+ if (sortModel) {
410
+ data.sortModel = JSON.stringify(sortModel);
411
+ data.sort_dir = sort_dir;
412
+ }
413
+
414
+ if (!_.isEmpty(filterModel?.filterModelNative)) {
415
+ data.filterModelNative = JSON.stringify(filterModel.filterModelNative);
416
+ }
417
+ if (!_.isEmpty(filterModel?.filterModelMongo)) {
418
+ data.filterModelMongo = JSON.stringify(filterModel.filterModelMongo);
419
+ }
420
+
421
+ if (filterModel?.filterModelSql) {
422
+ data.filterModelSql = JSON.stringify(filterModel.filterModelSql);
423
+ }
424
+ if (!_.isEmpty(filterModel?.filterModelUserMongo)) {
425
+ data.filterModelUserMongo = JSON.stringify(filterModel.filterModelUserMongo);
426
+ }
427
+ if (filterModel?.filterModelUserSql) {
428
+ data.filterModelUserSql = JSON.stringify(filterModel.filterModelUserSql);
429
+ }
430
+ // }
431
+
432
+ if (total_fields_info) {
433
+ data.total_fields_info = JSON.stringify(total_fields_info);
434
+ }
435
+
436
+ if (!reduceP && !countP) {
437
+ data.fields = fields_arr; //[];
438
+ }
439
+
440
+ try {
441
+ const json = await _this.func.common.db(SESSION_ID, 'dbs_read', data, { node: true }, dsSessionP);
442
+ return await response.success(json);
443
+ } catch (e) {
444
+ return await response.error(e?.message || e?.data || e);
445
+ }
446
+ };
447
+
448
+ var db_driver = await this.get_db_driver(SESSION_ID, dsSessionP);
449
+ if (db_driver === 'pouchdb' && _this.glb.IS_WORKER && !_this.SESSION_OBJ[SESSION_ID].engine_mode === 'live_preview') {
450
+ var callback_id = _this.func.utils.set_callback_queue(SESSION_ID, callbackP);
451
+ var obj = _this.func.utils.clean_returned_datasource(SESSION_ID, dsSessionP);
452
+ return _this.func.utils.post_back_to_client(SESSION_ID, 'execute_local_db_query', _this.SESSION_OBJ[SESSION_ID].worker_id, {
453
+ ds_obj: obj,
454
+ dsSessionP,
455
+ table_id,
456
+ queryP,
457
+ dsSessionP,
458
+ viewSourceDescP,
459
+ sourceP,
460
+ reduceP,
461
+ skipP,
462
+ limitP,
463
+ countP,
464
+ idsP,
465
+ callback_id,
466
+ });
467
+ }
468
+ return await run_local();
469
+ };
470
+ _db.utils = {};
471
+
472
+ _db.save_indicator = function (SESSION_ID, stateP) {
473
+ if (!_this.glb.IS_WORKER) {
474
+ _this.func.UI.utils.save(SESSION_ID, stateP);
475
+ }
476
+ };
477
+
478
+ // _db.save_image = function (SESSION_ID, filename, base64) {
479
+ // var response = {
480
+ // success: function (jsonP, ajaxP) {
481
+ // // console.log(jsonP);
482
+ // _this.func.utils.post_back_to_client(
483
+ // SESSION_ID,
484
+ // "change_loaded_image",
485
+ // _this.SESSION_OBJ[SESSION_ID].worker_id,
486
+ // jsonP
487
+ // );
488
+ // },
489
+ // error: function (status) {
490
+ // console.log("error save_image:" + status);
491
+ // },
492
+ // fail: function (status) {
493
+ // console.log("error save_image:" + status);
494
+ // },
495
+ // };
496
+
497
+ // // const app_id = _this.SESSION_OBJ[SESSION_ID].app_id;
498
+
499
+ // let app_id = _this.SESSION_OBJ[SESSION_ID].app_id;
500
+ // let app_id_reference = APP_OBJ[app_id].app_id_reference;
501
+
502
+ // _this.$_ajax({
503
+ // url: _this.func.common.get_url(SESSION_ID, "rpi", "runtime_save_image"),
504
+ // dataType: "json",
505
+ // type: "POST",
506
+ // data: {
507
+ // base64: base64,
508
+ // filename: filename,
509
+ // app_id_reference: app_id_reference,
510
+ // app_id: app_id,
511
+ // },
512
+
513
+ // success: function (json) {
514
+ // response.success(json);
515
+ // },
516
+ // fail: function (jqXHR, textStatus) {
517
+ // response.error(jqXHR, textStatus, errorThrown);
518
+ // },
519
+ // error: function (jqXHR, textStatus, errorThrown) {
520
+ // response.error(jqXHR, textStatus, errorThrown);
521
+ // },
522
+ // timeout: 60000, //60 seconds timeout
523
+ // });
524
+ // };
525
+
526
+ const init_xuda_dbs_plugin = async function (SESSION_ID) {
527
+ var _session = _this.SESSION_OBJ[SESSION_ID];
528
+
529
+ const plugin_name = '@xuda.io/xuda-dbs-plugin-xuda';
530
+
531
+ const get_path = function (plugin_name, resource) {
532
+ var path = `https://${_session.domain}/plugins/${plugin_name}${resource ? '/' + resource : ''}?app_id=${_session.app_id}`;
533
+
534
+ return path;
535
+ };
536
+
537
+ try {
538
+ _this.xuda_dbs_plugin = await import(get_path(plugin_name, 'studio.mjs'));
539
+
540
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
541
+ await _db.call_pouch_xuda_dbs_plugin(SESSION_ID, 'create_design', { db });
542
+ } catch (err) {
543
+ return console.error(err.message);
544
+ }
545
+ };
546
+
547
+ _db.call_pouch_xuda_dbs_plugin = async function (SESSION_ID, method, params) {
548
+ return new Promise(async (resolve, reject) => {
549
+ try {
550
+ // var table_obj = {};
551
+ if (params.e) {
552
+ params.table_obj = await func.utils.DOCS_OBJ.get(SESSION_ID, params.e.table_id);
553
+ }
554
+
555
+ await _this.xuda_dbs_plugin[method](params, resolve, reject);
556
+ } catch (err) {
557
+ reject();
558
+ }
559
+ });
560
+ };
561
+ _db.pouch = {};
562
+ _db.pouch.dbs_read = async function (SESSION_ID, e) {
563
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
564
+ return await _db.call_pouch_xuda_dbs_plugin(SESSION_ID, 'read', { db, e });
565
+ };
566
+ _db.pouch.dbs_create = async function (SESSION_ID, e) {
567
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
568
+ return await _db.call_pouch_xuda_dbs_plugin(SESSION_ID, 'create', { db, e });
569
+ };
570
+ _db.pouch.dbs_delete = async function (SESSION_ID, e) {
571
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
572
+ return await _db.call_pouch_xuda_dbs_plugin(SESSION_ID, 'del', { db, e });
573
+ };
574
+ _db.pouch.dbs_update = async function (SESSION_ID, e) {
575
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
576
+ return await _db.call_pouch_xuda_dbs_plugin(SESSION_ID, 'update', { db, e });
577
+ };
578
+
579
+ _db.pouch.init_db_replication = async function (SESSION_ID) {
580
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
581
+ var _session = _this.SESSION_OBJ[SESSION_ID];
582
+
583
+ if (_session.url_params.avoid_local || _session.engine_mode === 'miniapp' || (_session.engine_mode !== 'live_preview' && !_session.opt.enable_offline)) {
584
+ return;
585
+ }
586
+
587
+ // handle realtime refresh programs
588
+ const changes = db
589
+ .changes({
590
+ // since: "now",
591
+ live: true,
592
+ include_docs: true,
593
+ })
594
+ .on('change', function (change) {
595
+ // handle change
596
+
597
+ if (!change.doc.udfData) return;
598
+ // console.log("handle change", change);
599
+ func.UI.screen.refresh_document_changes_for_realtime_update(SESSION_ID, {
600
+ row_id: change.id,
601
+ table_id: change.doc.udfData.udffileid,
602
+ });
603
+ })
604
+ .on('complete', function (info) {
605
+ // changes() was canceled
606
+ console.log('complete', info);
607
+ })
608
+ .on('error', function (err) {
609
+ console.error(err);
610
+ });
611
+
612
+ set_replication_stat(SESSION_ID, null, 3);
613
+
614
+ // replicate to server
615
+ const db_name = APP_OBJ[_session.app_id].app_db_name;
616
+ const rep = db.replicate
617
+ .to(`https://${_session.domain}/db/${db_name}`, {
618
+ selector: { docType: 'database' },
619
+ live: true,
620
+ retry: true,
621
+ fetch: function (url, opts) {
622
+ if (_session.gtp_token) {
623
+ opts.headers.set('xu-gtp-token', _session.gtp_token);
624
+ }
625
+ if (_session.app_token) opts.headers.set('xu-app-token', _session.app_token);
626
+ {
627
+ opts.headers.set('xu-db', db_name);
628
+ }
629
+ return PouchDB.fetch(url, opts);
630
+ },
631
+ })
632
+ .on('change', function (info) {
633
+ // handle change
634
+ })
635
+ .on('paused', function (err) {
636
+ if (err) {
637
+ return set_replication_stat(SESSION_ID, null, 2);
638
+ }
639
+ set_replication_stat(SESSION_ID, null, 3);
640
+ // replication paused (e.g. replication up to date, user went offline)
641
+ })
642
+ .on('active', function () {
643
+ // replicate resumed (e.g. new changes replicating, user went back online)
644
+ })
645
+ .on('denied', function (err) {
646
+ set_replication_stat(SESSION_ID, null, 2);
647
+ // a document failed to replicate (e.g. due to permissions)
648
+ })
649
+ .on('complete', function (info) {
650
+ // handle complete
651
+ })
652
+ .on('error', function (err) {
653
+ set_replication_stat(SESSION_ID, null, 2);
654
+ IS_ONLINE = false;
655
+ // handle error
656
+ });
657
+
658
+ _db.pouch.set_db_replication_from_server(SESSION_ID);
659
+ $('body').on('set_db_replication_from_server', () => {
660
+ _db.pouch.set_db_replication_from_server(SESSION_ID);
661
+ });
662
+ };
663
+ _db.pouch.set_db_replication_from_server = async function (SESSION_ID) {
664
+ if (!IS_ONLINE) return;
665
+
666
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
667
+ const rep_docs = await _db.pouch.get_replications(SESSION_ID);
668
+ const _session = _this.SESSION_OBJ[SESSION_ID];
669
+ const db_name = APP_OBJ[_session.app_id].app_db_name;
670
+ const remote_db_url = `https://${_session.domain}/db/${db_name}`;
671
+ const remote_db = new PouchDB(remote_db_url, {
672
+ fetch: function (url, opts) {
673
+ if (_session.gtp_token) {
674
+ opts.headers.set('xu-gtp-token', _session.gtp_token);
675
+ }
676
+ if (_session.app_token) opts.headers.set('xu-app-token', _session.app_token);
677
+ {
678
+ opts.headers.set('xu-db', db_name);
679
+ }
680
+ return PouchDB.fetch(url, opts);
681
+ },
682
+ });
683
+
684
+ if (_this.db_changes_store) {
685
+ _this.db_changes_store.cancel();
686
+ }
687
+
688
+ const write_stat = async function (rep_id, stat, reason) {
689
+ try {
690
+ let doc = await db.get(rep_id);
691
+ // console.log("> replication ", stat, reason, doc);
692
+ doc.stat = stat;
693
+ doc.stat_reason = reason;
694
+ try {
695
+ db.put(doc);
696
+ } catch (err) {}
697
+ } catch (err) {}
698
+ };
699
+ const download_documents = async function (rep_doc) {
700
+ await write_stat(rep_doc._id, 2);
701
+
702
+ const remote_db = new PouchDB(remote_db_url, {
703
+ fetch: function (url, opts) {
704
+ opts.headers.set('xu-prog_id', rep_doc.prog_id);
705
+
706
+ if (_session.gtp_token) {
707
+ opts.headers.set('xu-gtp-token', _session.gtp_token);
708
+ }
709
+ if (_session.app_token) opts.headers.set('xu-app-token', _session.app_token);
710
+ {
711
+ opts.headers.set('xu-db', db_name);
712
+ }
713
+ return PouchDB.fetch(url, opts);
714
+ },
715
+ });
716
+
717
+ const ret = await remote_db.find({
718
+ selector: rep_doc.selector,
719
+ fields: ['_id'],
720
+ limit: 9999999999,
721
+ // prog_id: rep_doc.prog_id,
722
+ });
723
+
724
+ if (ret?.code < 0) {
725
+ return func.utils.debug_report(SESSION_ID, 'download_documents', ret.data, 'E');
726
+ }
727
+
728
+ try {
729
+ var doc_ids = [];
730
+ for await (let doc of ret.docs) {
731
+ doc_ids.push(doc._id);
732
+ }
733
+ db.replicate
734
+ .from(remote_db_url, {
735
+ doc_ids,
736
+ retry: true,
737
+ style: 'main_only',
738
+ fetch: function (url, opts) {
739
+ if (_session.gtp_token) {
740
+ opts.headers.set('xu-gtp-token', _session.gtp_token);
741
+ }
742
+ if (_session.app_token) opts.headers.set('xu-app-token', _session.app_token);
743
+ {
744
+ opts.headers.set('xu-db', db_name);
745
+ }
746
+ return PouchDB.fetch(url, opts);
747
+ },
748
+ })
749
+ .on('paused', async function (err) {
750
+ // replication paused (e.g. replication up to date, user went offline)
751
+
752
+ if (err) {
753
+ // set_replication_stat(SESSION_ID, 2);
754
+ return;
755
+ }
756
+ const read_ret = await _db.pouch.dbs_read(SESSION_ID, rep_doc.e); // trigger reindexing
757
+ await write_stat(rep_doc._id, 3);
758
+ });
759
+ } catch (err) {
760
+ await write_stat(rep_doc._id, 2, err.message);
761
+ console.error('replication from error', err);
762
+ }
763
+ // console.log(ret);
764
+ };
765
+
766
+ let filter_tables = [];
767
+ for (let doc of rep_docs) {
768
+ if (!filter_tables.includes(doc.table_id)) filter_tables.push(doc.table_id);
769
+ if (doc.stat < 3) await download_documents(doc);
770
+ }
771
+
772
+ try {
773
+ _this.db_changes_store = remote_db
774
+ .changes({
775
+ since: 'now',
776
+ live: true,
777
+ timeout: 300000, // 5 min
778
+ style: 'main_only',
779
+ include_docs: false,
780
+ // heartbeat: 10000
781
+ })
782
+ .on('change', async function (change) {
783
+ if (change.id.substr(0, 4) !== 'dbs-') return;
784
+
785
+ if (_this.db_replication_from_stat !== 3) {
786
+ set_replication_stat(SESSION_ID, 3);
787
+ }
788
+
789
+ try {
790
+ const existing_doc = await db.get(change.id);
791
+
792
+ db.replicate.from(remote_db_url, {
793
+ doc_ids: [change.id],
794
+ retry: true,
795
+ style: 'main_only',
796
+ fetch: function (url, opts) {
797
+ if (_session.gtp_token) {
798
+ opts.headers.set('xu-gtp-token', _session.gtp_token);
799
+ }
800
+ if (_session.app_token) opts.headers.set('xu-app-token', _session.app_token);
801
+ {
802
+ opts.headers.set('xu-db', db_name);
803
+ }
804
+ return PouchDB.fetch(url, opts);
805
+ },
806
+ });
807
+ } catch (err) {
808
+ // new doc change
809
+ try {
810
+ const table_id = change.id.split('_')[0].substr(4);
811
+
812
+ for (let doc of rep_docs) {
813
+ if (doc.table_id === table_id) {
814
+ download_documents(doc);
815
+ }
816
+ }
817
+ } catch (err) {
818
+ console.warn(err);
819
+ }
820
+ }
821
+ })
822
+ .on('complete', function (info) {
823
+ // changes() was canceled
824
+ })
825
+ .on('error', function (err) {
826
+ console.error(err);
827
+ set_replication_stat(SESSION_ID, 2);
828
+ _this.db_changes_store.cancel();
829
+ });
830
+ } catch (err) {
831
+ console.error(err);
832
+ }
833
+
834
+ return;
835
+ };
836
+ _db.pouch.remove_db_replication_from_server = async function (SESSION_ID, rep_id) {
837
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
838
+
839
+ try {
840
+ const doc = await db.get(rep_id);
841
+
842
+ // _this.db_replication_store[rep_id].cancel();
843
+ db.remove(doc);
844
+ // delete _this.db_replication_store[rep_id];
845
+ } catch (error) {}
846
+ };
847
+
848
+ _db.pouch.get_replications = async function (SESSION_ID = Object.keys(SESSION_OBJ)[0]) {
849
+ const db = await func.utils.connect_pouchdb(SESSION_ID);
850
+ // source: "runtime"
851
+ let ret = await db.find({
852
+ selector: { docType: 'rep_request' },
853
+ });
854
+
855
+ return ret.docs;
856
+ };
857
+
858
+ _db.pouch.get_replication_stat = async function (SESSION_ID) {
859
+ const _session = _this.SESSION_OBJ[SESSION_ID];
860
+ return _session?.DS_GLB?.[0]?.data_system?.SYS_GLOBAL_BOL_REPLICATION_STAT;
861
+ };
862
+
863
+ const set_replication_stat = async function (SESSION_ID, from_stat, to_stat) {
864
+ var _session = _this.SESSION_OBJ[SESSION_ID];
865
+ if (!_session?.DS_GLB?.[0]) {
866
+ return setTimeout(function () {
867
+ set_replication_stat(SESSION_ID, from_stat, to_stat);
868
+ }, 1000);
869
+ }
870
+
871
+ if (from_stat) _this.db_replication_from_stat = from_stat;
872
+ if (to_stat) _this.db_replication_to_stat = to_stat;
873
+
874
+ var data = {};
875
+ if (_this.db_replication_from_stat === 3 && _this.db_replication_to_stat === 3) {
876
+ data.SYS_GLOBAL_BOL_REPLICATION_STAT = 1;
877
+ console.info('Replication On');
878
+ } else {
879
+ data.SYS_GLOBAL_BOL_REPLICATION_STAT = 0;
880
+ console.info('Replication Off');
881
+ }
882
+
883
+ var datasource_changes = {
884
+ [0]: {
885
+ ['data_system']: data,
886
+ },
887
+ };
888
+ await func.datasource.update(SESSION_ID, datasource_changes);
889
+ };
890
+
891
+ const refresh_document_changes_for_realtime_update = function (SESSION_ID, doc_change) {
892
+ var _session = _this.SESSION_OBJ[SESSION_ID];
893
+
894
+ if (glb.IS_WORKER) {
895
+ return func.utils.post_back_to_client(SESSION_ID, 'refresh_document_changes_for_realtime_update', _session.worker_id, { doc_change });
896
+ }
897
+
898
+ func.UI.screen.refresh_document_changes_for_realtime_update(SESSION_ID, doc_change);
899
+ };
package/package.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "@xuda.io/xuda-db-adapter-module",
3
+ "version": "1.0.0",
4
+ "main": "index.mjs",
5
+ "type": "module",
6
+ "description": "Auto-generated build for xuda-db-adapter-module.mjs",
7
+ "author": "Auto Publisher"
8
+ }