@jd-data-limited/easy-fm 1.0.1-alpha1 → 1.0.2-alpha1

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.
@@ -0,0 +1,15 @@
1
+ > Why do I have a folder named ".expo" in my project?
2
+
3
+ The ".expo" folder is created when an Expo project is started using "expo start" command.
4
+
5
+ > What do the files contain?
6
+
7
+ - "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
8
+ - "packager-info.json": contains port numbers and process PIDs that are used to serve the application to the mobile device/simulator.
9
+ - "settings.json": contains the server configuration that is used to serve the application manifest.
10
+
11
+ > Should I commit the ".expo" folder?
12
+
13
+ No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
14
+
15
+ Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
@@ -0,0 +1,8 @@
1
+ {
2
+ "hostType": "lan",
3
+ "lanType": "ip",
4
+ "dev": true,
5
+ "minify": false,
6
+ "urlRandomness": null,
7
+ "https": false
8
+ }
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2022. See LICENSE file for more information
2
+ * Copyright (c) 2022-2023. See LICENSE file for more information
3
3
  */
4
4
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
5
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@@ -102,7 +102,11 @@ export default class FileMakerConnection extends database {
102
102
  super(conn.database);
103
103
  this.host = this;
104
104
  this.hostname = conn.hostname;
105
- this.externalSources = externalDataSources.map(i => { let e = new database(i, this); e.external = true; return e; });
105
+ this.externalSources = externalDataSources.map(i => {
106
+ let e = new database(i, this);
107
+ e.external = true;
108
+ return e;
109
+ });
106
110
  this.rejectUnauthroized = rejectUnauthorized;
107
111
  }
108
112
  logout() {
@@ -459,7 +463,9 @@ class field {
459
463
  reject(new FMError(_res.messages[0].code, _res.status, data));
460
464
  }
461
465
  })
462
- .catch(e => { reject(e); });
466
+ .catch(e => {
467
+ reject(e);
468
+ });
463
469
  }));
464
470
  }
465
471
  download() {
@@ -503,10 +509,12 @@ class portalItem extends record {
503
509
  return res;
504
510
  }
505
511
  }
506
- class find {
512
+ class recordGetOperation {
507
513
  constructor(layout) {
514
+ this.limit = 100;
515
+ this.limitPortals = [];
516
+ this.offset = 0;
508
517
  this.layout = layout;
509
- this.queries = [];
510
518
  this.scripts = {
511
519
  "script": null,
512
520
  "script.prerequeset": null,
@@ -514,6 +522,86 @@ class find {
514
522
  };
515
523
  this.sort = [];
516
524
  }
525
+ /*
526
+ addToPortalLimit() will adjust the results of the get request so that if a layout has multiple portals in it,
527
+ only data from the specified ones will be read. This may help reduce load on your FileMaker API
528
+ */
529
+ addToPortalLimit(portal, offset = 0, limit = 100) {
530
+ if (offset < 0)
531
+ throw "Portal offset cannot be less than 0";
532
+ this.limitPortals.push({ portal, offset, limit });
533
+ }
534
+ setLimit(limit) {
535
+ if (limit < 1)
536
+ throw "Record limit too low";
537
+ this.limit = limit;
538
+ }
539
+ addSort(fieldName, sortOrder) {
540
+ this.sort.push({ fieldName, sortOrder });
541
+ return this;
542
+ }
543
+ setOffset(offset) {
544
+ if (offset < 0)
545
+ throw "Record offset too low";
546
+ this.limit = offset;
547
+ }
548
+ }
549
+ class recordGetRange extends recordGetOperation {
550
+ constructor(layout) {
551
+ super(layout);
552
+ }
553
+ generateQueryParams() {
554
+ let params = [];
555
+ if (this.limit !== 100)
556
+ params.push("_limit=" + this.limit);
557
+ if (this.offset !== 0)
558
+ params.push("_offset=" + this.offset);
559
+ if (this.sort.length > 0)
560
+ params.push("_sort=" + encodeURI(JSON.stringify(this.sort)));
561
+ if (this.limitPortals.length > 0) {
562
+ params.push("portal=" + encodeURI(JSON.stringify(this.limitPortals.map(p => p.portal.name))));
563
+ for (let item of this.limitPortals) {
564
+ if (item.offset !== 0)
565
+ params.push("_offset." + item.portal.name.replace(/[^0-9A-z]/g, "") + "=" + item.offset);
566
+ if (item.limit !== 100)
567
+ params.push("_limit." + item.portal.name.replace(/[^0-9A-z]/g, "") + "=" + item.limit);
568
+ }
569
+ }
570
+ if (params.length === 0)
571
+ return "";
572
+ return "?" + params.join("&");
573
+ }
574
+ run() {
575
+ return new Promise((resolve, reject) => {
576
+ // console.log(this.#toObject())
577
+ this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams()}`, {
578
+ method: "GET"
579
+ }).then((res) => __awaiter(this, void 0, void 0, function* () {
580
+ // // console.log(res)
581
+ if (res.messages[0].code === "0") {
582
+ // console.log("RESOLVING")
583
+ if (!this.layout.metadata)
584
+ yield this.layout.getLayoutMeta();
585
+ let data = res.response.data.map(item => {
586
+ return new record(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
587
+ });
588
+ resolve(data);
589
+ }
590
+ else {
591
+ reject(new FMError(res.messages[0].code, res.status, res));
592
+ }
593
+ }))
594
+ .catch(e => {
595
+ reject(e);
596
+ });
597
+ });
598
+ }
599
+ }
600
+ class find extends recordGetOperation {
601
+ constructor(layout) {
602
+ super(layout);
603
+ this.queries = [];
604
+ }
517
605
  toObject() {
518
606
  let out = { query: this.queries, sort: undefined };
519
607
  if (this.sort.length !== 0)
@@ -525,6 +613,17 @@ class find {
525
613
  out[item + ".param"] = this.scripts[item].parameter;
526
614
  }
527
615
  }
616
+ if (this.limit !== 100)
617
+ out["limit"] = this.limit;
618
+ if (this.offset !== 0)
619
+ out["offset"] = this.offset;
620
+ if (this.limitPortals.length > 0) {
621
+ out["portal"] = this.limitPortals.map(p => p.portal.name);
622
+ for (let item of this.limitPortals) {
623
+ out["offset." + item.portal.name.replace(/[^0-9A-z]/g, "")] = item.offset;
624
+ out["limit." + item.portal.name.replace(/[^0-9A-z]/g, "")] = item.limit;
625
+ }
626
+ }
528
627
  return out;
529
628
  }
530
629
  addRequests(...requests) {
@@ -532,11 +631,10 @@ class find {
532
631
  this.queries.push(item);
533
632
  return this;
534
633
  }
535
- addSort(fieldName, sortOrder) {
536
- this.sort.push({ fieldName, sortOrder });
537
- return this;
538
- }
539
634
  find() {
635
+ return this.run();
636
+ }
637
+ run() {
540
638
  return new Promise((resolve, reject) => {
541
639
  // console.log(this.#toObject())
542
640
  this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
package/index.ts CHANGED
@@ -15,14 +15,15 @@ import fetch, {
15
15
  Request,
16
16
  Response
17
17
  } from 'node-fetch';
18
- import { EventEmitter } from "events";
18
+ import {EventEmitter} from "events";
19
19
  // @ts-ignore
20
20
  import fs from "fs"
21
21
  // @ts-ignore
22
22
  import path from "path"
23
23
  // @ts-ignore
24
- import { fileURLToPath } from "url"
24
+ import {fileURLToPath} from "url"
25
25
  import * as https from "https";
26
+
26
27
  // import * as btoa from "btoa";
27
28
 
28
29
  interface connectionOptions {
@@ -66,6 +67,12 @@ interface loginOptionsClaris extends databaseOptions {
66
67
  }
67
68
  }
68
69
 
70
+ interface limitPortalsInterface {
71
+ portal: portal,
72
+ offset: number,
73
+ limit: number
74
+ }
75
+
69
76
  // @ts-ignore
70
77
  const errs = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'fmErrors.json')).toString())
71
78
 
@@ -168,18 +175,22 @@ class database {
168
175
  }
169
176
  }
170
177
 
171
- export default class FileMakerConnection extends database{
178
+ export default class FileMakerConnection extends database {
172
179
  private _token: any;
173
180
  private username: any;
174
181
  private password: any;
175
182
  public readonly rejectUnauthroized: boolean;
176
183
  externalSources: database[];
177
184
 
178
- constructor(conn: hostConnectionOptions, externalDataSources:databaseOptions[] = [], rejectUnauthorized = true) {
185
+ constructor(conn: hostConnectionOptions, externalDataSources: databaseOptions[] = [], rejectUnauthorized = true) {
179
186
  super(conn.database);
180
187
  this.host = this
181
188
  this.hostname = conn.hostname
182
- this.externalSources = externalDataSources.map(i => {let e = new database(i, this); e.external = true; return e;})
189
+ this.externalSources = externalDataSources.map(i => {
190
+ let e = new database(i, this);
191
+ e.external = true;
192
+ return e;
193
+ })
183
194
  this.rejectUnauthroized = rejectUnauthorized
184
195
  }
185
196
 
@@ -230,13 +241,11 @@ export default class FileMakerConnection extends database{
230
241
  .catch(e => {
231
242
  reject(e)
232
243
  })
233
- }
234
- else if (this.props.method === "token") {
244
+ } else if (this.props.method === "token") {
235
245
  this._token = (<loginOptionsToken>this.props).token
236
246
  this.name = this.props.database
237
247
  resolve(this.token)
238
- }
239
- else if (this.props.method === "oauth") {
248
+ } else if (this.props.method === "oauth") {
240
249
  this.name = this.props.database
241
250
  fetch(`${this.endpoint}/sessions`, {
242
251
  method: "POST",
@@ -253,8 +262,7 @@ export default class FileMakerConnection extends database{
253
262
  this._token = _res.headers["x-fm-data-access-token"]
254
263
  resolve(this.token)
255
264
  })
256
- }
257
- else if (this.props.method === "claris") {
265
+ } else if (this.props.method === "claris") {
258
266
  this.name = this.props.database
259
267
  fetch(`${this.endpoint}/sessions`, {
260
268
  method: "POST",
@@ -283,6 +291,7 @@ class layout {
283
291
  readonly database: database;
284
292
  protected name: string;
285
293
  metadata: any;
294
+
286
295
  constructor(database: database, name: string) {
287
296
  this.database = database
288
297
  this.name = name
@@ -357,7 +366,7 @@ class record extends EventEmitter {
357
366
  fields: field[];
358
367
  readonly portals: portal[];
359
368
  private portalData: any[];
360
-
369
+
361
370
  constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
362
371
  super();
363
372
  this.layout = layout
@@ -399,7 +408,9 @@ class record extends EventEmitter {
399
408
  }
400
409
 
401
410
  get() {
402
- if (this.recordId === -1) {throw "Cannot get this record until a commit() is done."}
411
+ if (this.recordId === -1) {
412
+ throw "Cannot get this record until a commit() is done."
413
+ }
403
414
  return new Promise(async (resolve, reject) => {
404
415
  if (!this.layout.metadata) await this.layout.getLayoutMeta()
405
416
 
@@ -445,8 +456,7 @@ class record extends EventEmitter {
445
456
  .then(res => {
446
457
  if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
447
458
  reject(new FMError(res.response.scriptError, res.status, res))
448
- }
449
- else if (res.messages[0].code === "0") {
459
+ } else if (res.messages[0].code === "0") {
450
460
  console.log(res)
451
461
  this.recordId = parseInt(res.response.recordId)
452
462
  this.modId = parseInt(res.response.modId)
@@ -455,7 +465,7 @@ class record extends EventEmitter {
455
465
  reject(new FMError(res.messages[0].code, res.status, res))
456
466
  }
457
467
  })
458
- sh .catch(e => {
468
+ .catch(e => {
459
469
  reject(e)
460
470
  })
461
471
 
@@ -471,8 +481,7 @@ class record extends EventEmitter {
471
481
  .then(res => {
472
482
  if (typeof res.response.scriptError !== "undefined" && res.response.scriptError !== '0') {
473
483
  reject(new FMError(res.response.scriptError, res.status, res))
474
- }
475
- else if (res.messages[0].code === "0") {
484
+ } else if (res.messages[0].code === "0") {
476
485
  console.log(res)
477
486
  this.modId = res.response.modId
478
487
  this.emit("saved")
@@ -529,6 +538,7 @@ class field {
529
538
  id: number;
530
539
  value: string | number;
531
540
  edited: boolean;
541
+
532
542
  constructor(record, id, contents) {
533
543
  this.record = record
534
544
  this.id = id
@@ -570,9 +580,12 @@ class field {
570
580
  reject(new FMError(_res.messages[0].code, _res.status, data))
571
581
  }
572
582
  })
573
- .catch(e => {reject(e)})
583
+ .catch(e => {
584
+ reject(e)
585
+ })
574
586
  })
575
587
  }
588
+
576
589
  download() {
577
590
  return new Promise((resolve, reject) => {
578
591
  https.get(this.value.toString(), (res) => {
@@ -624,15 +637,16 @@ class portalItem extends record {
624
637
  }
625
638
  }
626
639
 
627
- class find {
640
+ class recordGetOperation {
628
641
  protected layout: layout
629
- protected queries: object[]
642
+ protected limit: number = 100
630
643
  protected scripts: object
631
644
  protected sort: object[]
645
+ protected limitPortals: limitPortalsInterface[] = []
646
+ protected offset: number = 0
632
647
 
633
648
  constructor(layout) {
634
649
  this.layout = layout
635
- this.queries = []
636
650
  this.scripts = {
637
651
  "script": null, // Runs after everything
638
652
  "script.prerequeset": null, // Runs before the request
@@ -641,6 +655,86 @@ class find {
641
655
  this.sort = []
642
656
  }
643
657
 
658
+ /*
659
+ addToPortalLimit() will adjust the results of the get request so that if a layout has multiple portals in it,
660
+ only data from the specified ones will be read. This may help reduce load on your FileMaker API
661
+ */
662
+ addToPortalLimit(portal: portal, offset = 0, limit = 100) {
663
+ if (offset < 0) throw "Portal offset cannot be less than 0"
664
+ this.limitPortals.push({portal, offset, limit})
665
+ }
666
+
667
+ setLimit(limit: number) {
668
+ if (limit < 1) throw "Record limit too low"
669
+ this.limit = limit
670
+ }
671
+
672
+ addSort(fieldName, sortOrder) {
673
+ this.sort.push({fieldName, sortOrder})
674
+ return this
675
+ }
676
+
677
+ setOffset(offset: number) {
678
+ if (offset < 0) throw "Record offset too low"
679
+ this.limit = offset
680
+ }
681
+ }
682
+
683
+ class recordGetRange extends recordGetOperation {
684
+ constructor(layout) {
685
+ super(layout)
686
+ }
687
+
688
+ private generateQueryParams() {
689
+ let params = []
690
+ if (this.limit !== 100) params.push("_limit=" + this.limit)
691
+ if (this.offset !== 0) params.push("_offset=" + this.offset)
692
+ if (this.sort.length > 0) params.push("_sort=" + encodeURI(JSON.stringify(this.sort)))
693
+ if (this.limitPortals.length > 0) {
694
+ params.push("portal=" + encodeURI(JSON.stringify(this.limitPortals.map(p => p.portal.name))))
695
+ for (let item of this.limitPortals) {
696
+ if (item.offset !== 0) params.push("_offset." + item.portal.name.replace(/[^0-9A-z]/g, "") + "=" + item.offset)
697
+ if (item.limit !== 100) params.push("_limit." + item.portal.name.replace(/[^0-9A-z]/g, "") + "=" + item.limit)
698
+ }
699
+ }
700
+
701
+ if (params.length === 0) return ""
702
+ return "?" + params.join("&")
703
+ }
704
+
705
+ run() {
706
+ return new Promise((resolve, reject) => {
707
+ // console.log(this.#toObject())
708
+ this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams()}`, {
709
+ method: "GET"
710
+ }).then(async res => {
711
+ // // console.log(res)
712
+ if (res.messages[0].code === "0") {
713
+ // console.log("RESOLVING")
714
+ if (!this.layout.metadata) await this.layout.getLayoutMeta()
715
+ let data = res.response.data.map(item => {
716
+ return new record(this.layout, item.recordId, item.modId, item.fieldData, item.portalData)
717
+ })
718
+ resolve(data)
719
+ } else {
720
+ reject(new FMError(res.messages[0].code, res.status, res))
721
+ }
722
+ })
723
+ .catch(e => {
724
+ reject(e)
725
+ })
726
+ })
727
+ }
728
+ }
729
+
730
+ class find extends recordGetOperation {
731
+ protected queries: object[]
732
+
733
+ constructor(layout) {
734
+ super(layout)
735
+ this.queries = []
736
+ }
737
+
644
738
  private toObject() {
645
739
  let out = {query: this.queries, sort: undefined}
646
740
  if (this.sort.length !== 0) out.sort = this.sort
@@ -652,6 +746,16 @@ class find {
652
746
  }
653
747
  }
654
748
 
749
+ if (this.limit !== 100) out["limit"] = this.limit
750
+ if (this.offset !== 0) out["offset"] = this.offset
751
+ if (this.limitPortals.length > 0) {
752
+ out["portal"] = this.limitPortals.map(p => p.portal.name)
753
+ for (let item of this.limitPortals) {
754
+ out["offset." + item.portal.name.replace(/[^0-9A-z]/g, "")] = item.offset
755
+ out["limit." + item.portal.name.replace(/[^0-9A-z]/g, "")] = item.limit
756
+ }
757
+ }
758
+
655
759
  return out
656
760
  }
657
761
 
@@ -660,12 +764,11 @@ class find {
660
764
  return this
661
765
  }
662
766
 
663
- addSort(fieldName, sortOrder) {
664
- this.sort.push({fieldName, sortOrder})
665
- return this
767
+ find() {
768
+ return this.run()
666
769
  }
667
770
 
668
- find() {
771
+ run() {
669
772
  return new Promise((resolve, reject) => {
670
773
  // console.log(this.#toObject())
671
774
  this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jd-data-limited/easy-fm",
3
- "version": "1.0.1alpha1",
3
+ "version": "1.0.2alpha1",
4
4
  "dependencies": {
5
5
  "@types/btoa": "^1.2.3",
6
6
  "@types/events": "^3.0.0",