natural 6.11.1 → 7.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 (116) hide show
  1. package/.env +9 -7
  2. package/.eslintrc.json +13 -0
  3. package/.github/workflows/node.js.yml +57 -19
  4. package/lib/natural/analyzers/SenType.ts +30 -0
  5. package/lib/natural/analyzers/index.d.ts +6 -10
  6. package/lib/natural/brill_pos_tagger/index.d.ts +23 -14
  7. package/lib/natural/brill_pos_tagger/index.js +1 -1
  8. package/lib/natural/classifiers/bayes_classifier.js +6 -1
  9. package/lib/natural/classifiers/classifier.js +19 -32
  10. package/lib/natural/classifiers/classifier_train_parallel.js +7 -5
  11. package/lib/natural/classifiers/index.d.ts +36 -15
  12. package/lib/natural/classifiers/logistic_regression_classifier.js +7 -2
  13. package/lib/natural/classifiers/maxent/Classifier.js +5 -3
  14. package/lib/natural/distance/index.d.ts +11 -14
  15. package/lib/natural/inflectors/count_inflector.js +18 -21
  16. package/lib/natural/inflectors/fr/count_inflector.js +18 -19
  17. package/lib/natural/inflectors/index.d.ts +12 -3
  18. package/lib/natural/inflectors/index.js +3 -0
  19. package/lib/natural/ngrams/index.d.ts +5 -5
  20. package/lib/natural/normalizers/index.d.ts +24 -1
  21. package/lib/natural/normalizers/index.js +4 -1
  22. package/lib/natural/normalizers/normalizer_ja.js +109 -72
  23. package/lib/natural/phonetics/dm_soundex.js +52 -51
  24. package/lib/natural/phonetics/double_metaphone.js +397 -399
  25. package/lib/natural/phonetics/index.d.ts +42 -12
  26. package/lib/natural/phonetics/metaphone.js +134 -157
  27. package/lib/natural/phonetics/phonetic.js +5 -29
  28. package/lib/natural/phonetics/soundex.js +45 -54
  29. package/lib/natural/sentiment/index.d.ts +6 -6
  30. package/lib/natural/spellcheck/index.d.ts +2 -0
  31. package/lib/natural/stemmers/index.d.ts +43 -1
  32. package/lib/natural/stemmers/index.js +1 -0
  33. package/lib/natural/stemmers/token.js +131 -132
  34. package/lib/natural/tfidf/index.d.ts +7 -7
  35. package/lib/natural/tfidf/tfidf.js +7 -1
  36. package/lib/natural/tokenizers/index.d.ts +2 -2
  37. package/lib/natural/trie/index.d.ts +1 -1
  38. package/lib/natural/util/index.d.ts +8 -0
  39. package/lib/natural/util/index.js +2 -0
  40. package/lib/natural/util/storage/File.js +22 -0
  41. package/lib/natural/util/storage/Memcached.js +22 -0
  42. package/lib/natural/util/storage/MongoDB.js +31 -3
  43. package/lib/natural/util/storage/Postgres.js +49 -32
  44. package/lib/natural/util/storage/Redis.js +22 -0
  45. package/lib/natural/util/storage/StorageBackend.js +23 -0
  46. package/lib/natural/util/storage/index.d.ts +39 -0
  47. package/lib/natural/util/storage/index.js +24 -0
  48. package/package.json +22 -9
  49. package/ts_spec/MaxEntClassifier_spec.ts +130 -0
  50. package/ts_spec/SentimentAnalyzer_spec.ts +232 -0
  51. package/ts_spec/WordPunctTokenizer_spec.ts +57 -0
  52. package/ts_spec/aggressive_tokenizer_de_spec.ts +36 -0
  53. package/ts_spec/aggressive_tokenizer_es_spec.ts +39 -0
  54. package/ts_spec/aggressive_tokenizer_fr_spec.ts +111 -0
  55. package/ts_spec/aggressive_tokenizer_hi_spec.ts +70 -0
  56. package/ts_spec/aggressive_tokenizer_nl_spec.ts +39 -0
  57. package/ts_spec/aggressive_tokenizer_pt_spec.ts +48 -0
  58. package/ts_spec/aggressive_tokenizer_spec.ts +57 -0
  59. package/ts_spec/aggressive_tokenizer_sv_spec.ts +52 -0
  60. package/ts_spec/aggressive_tokenizer_vi_spec.ts +48 -0
  61. package/ts_spec/bayes_classifier_spec.ts +165 -0
  62. package/ts_spec/brill_pos_tagger_spec.ts +79 -0
  63. package/ts_spec/brill_pos_trainer_spec.ts +107 -0
  64. package/ts_spec/carry_stemmer_fr_spec.ts +97 -0
  65. package/ts_spec/classifier_spec.ts +104 -0
  66. package/ts_spec/count_inflector_fr_spec.ts +47 -0
  67. package/ts_spec/count_inflector_spec.ts +76 -0
  68. package/ts_spec/damerau_levenshtein_spec.ts +53 -0
  69. package/ts_spec/dice_coefficient_spec.ts +37 -0
  70. package/ts_spec/double_metaphone_spec.ts +739 -0
  71. package/ts_spec/hamming_distance_spec.ts +66 -0
  72. package/ts_spec/jaro-winkler_spec.ts +79 -0
  73. package/ts_spec/lancaster_stemmer_spec.ts +63 -0
  74. package/ts_spec/levenshtein_spec.ts +107 -0
  75. package/ts_spec/logistic_regression_classifier_spec.ts +93 -0
  76. package/ts_spec/longest_path_tree_spec.ts +111 -0
  77. package/ts_spec/metaphone_spec.ts +258 -0
  78. package/ts_spec/ngram_spec.ts +145 -0
  79. package/ts_spec/ngram_zh_spec.ts +124 -0
  80. package/ts_spec/normalizer_ja_spec.ts +165 -0
  81. package/ts_spec/normalizer_no_spec.ts +112 -0
  82. package/ts_spec/normalizer_spec.ts +141 -0
  83. package/ts_spec/noun_inflector_fr_spec.ts +472 -0
  84. package/ts_spec/noun_inflector_ja_spec.ts +116 -0
  85. package/ts_spec/noun_inflector_spec.ts +369 -0
  86. package/ts_spec/orthography_tokenizer_spec.ts +47 -0
  87. package/ts_spec/porter_stemmer_de_spec.ts +53 -0
  88. package/ts_spec/porter_stemmer_es_spec.ts +63 -0
  89. package/ts_spec/porter_stemmer_fr_spec.ts +103 -0
  90. package/ts_spec/porter_stemmer_it_spec.ts +56 -0
  91. package/ts_spec/porter_stemmer_nl_spec.ts +73 -0
  92. package/ts_spec/porter_stemmer_no_spec.ts +148 -0
  93. package/ts_spec/porter_stemmer_pt_spec.ts +50 -0
  94. package/ts_spec/porter_stemmer_ru_spec.ts +67 -0
  95. package/ts_spec/porter_stemmer_spec.ts +202 -0
  96. package/ts_spec/porter_stemmer_sv_spec.ts +41 -0
  97. package/ts_spec/present_verb_inflector_spec.ts +127 -0
  98. package/ts_spec/remove_diacritics_spec.ts +30 -0
  99. package/ts_spec/sentence_analyzer_spec.ts +293 -0
  100. package/ts_spec/sentence_tokenizer_parser_spec.ts +200 -0
  101. package/ts_spec/sentence_tokenizer_spec.ts +189 -0
  102. package/ts_spec/shortest_path_tree_spec.ts +141 -0
  103. package/ts_spec/soundex_spec.ts +162 -0
  104. package/ts_spec/spellcheck_spec.ts +112 -0
  105. package/ts_spec/stemmer_id_spec.ts +374 -0
  106. package/ts_spec/stemmer_ja_spec.ts +69 -0
  107. package/ts_spec/stemmer_token_spec.ts +163 -0
  108. package/ts_spec/tfidf_spec.ts +275 -0
  109. package/ts_spec/tokenizer_case_spec.ts +242 -0
  110. package/ts_spec/tokenizer_ja_spec.ts +63 -0
  111. package/ts_spec/transliterator_ja_spec.ts +105 -0
  112. package/ts_spec/treebank_word_tokenizer_spec.ts +38 -0
  113. package/ts_spec/trie_spec.ts +197 -0
  114. package/tsconfig.json +5 -3
  115. package/example.txt +0 -1
  116. package/f2f5d4bc-daa0-4392-8981-9614cd0c802e.json +0 -1
@@ -22,141 +22,140 @@ THE SOFTWARE.
22
22
 
23
23
  'use strict'
24
24
 
25
- module.exports = (function () {
26
- /**
27
- * Stemmer token constructor.
28
- *
29
- * @param {String} string Token string.
30
- */
31
- const Token = function (string) {
32
- this.vowels = ''
33
- this.regions = {}
34
- this.string = string
35
- this.original = string
25
+ /**
26
+ * Stemmer token constructor.
27
+ *
28
+ * @param {String} string Token string.
29
+ */
30
+ function Token (string) {
31
+ this.vowels = ''
32
+ this.regions = {}
33
+ this.string = string
34
+ this.original = string
35
+ }
36
+
37
+ /**
38
+ * Set vowels.
39
+ *
40
+ * @param {String|Array} vowels List of vowels.
41
+ * @return {Token} Token instance.
42
+ */
43
+ Token.prototype.usingVowels = function (vowels) {
44
+ this.vowels = vowels
45
+ return this
46
+ }
47
+
48
+ /**
49
+ * Marks a region by defining its starting index or providing a callback
50
+ * function that does.
51
+ *
52
+ * @param {String} region Region name.
53
+ * @param {Array|Number} args Callback arguments or region start index.
54
+ * @param {Function} callback Function that determines the start index (optional).
55
+ * @param {Object} context Callback context (optional, defaults to this).
56
+ * @return {Token} Token instance.
57
+ */
58
+ Token.prototype.markRegion = function (region, args, callback, context) {
59
+ if (typeof callback === 'function') {
60
+ // this.regions[region] = callback.apply(context || this, [].concat(args))
61
+ this.regions[region] = callback.apply(context || this, [].concat(args))
62
+ } else if (!isNaN(args)) {
63
+ this.regions[region] = args
36
64
  }
37
65
 
38
- /**
39
- * Set vowels.
40
- *
41
- * @param {String|Array} vowels List of vowels.
42
- * @return {Token} Token instance.
43
- */
44
- Token.prototype.usingVowels = function (vowels) {
45
- this.vowels = vowels
46
- return this
47
- }
48
-
49
- /**
50
- * Marks a region by defining its starting index or providing a callback
51
- * function that does.
52
- *
53
- * @param {String} region Region name.
54
- * @param {Array|Number} args Callback arguments or region start index.
55
- * @param {Function} callback Function that determines the start index (optional).
56
- * @param {Object} context Callback context (optional, defaults to this).
57
- * @return {Token} Token instance.
58
- */
59
- Token.prototype.markRegion = function (region, args, callback, context) {
60
- if (typeof callback === 'function') {
61
- this.regions[region] = callback.apply(context || this, [].concat(args))
62
- } else if (!isNaN(args)) {
63
- this.regions[region] = args
66
+ return this
67
+ }
68
+
69
+ /**
70
+ * Replaces all instances of a string with another.
71
+ *
72
+ * @param {String} find String to be replaced.
73
+ * @param {String} replace Replacement string.
74
+ * @return {Token} Token instance.
75
+ */
76
+ Token.prototype.replaceAll = function (find, replace) {
77
+ this.string = this.string.split(find).join(replace)
78
+ return this
79
+ }
80
+
81
+ /**
82
+ * Replaces the token suffix if in a region.
83
+ *
84
+ * @param {String} suffix Suffix to replace.
85
+ * @param {String} replace Replacement string.
86
+ * @param {String} region Region name.
87
+ * @return {Token} Token instance.
88
+ */
89
+ Token.prototype.replaceSuffixInRegion = function (suffix, replace, region) {
90
+ const suffixes = [].concat(suffix)
91
+ for (let i = 0; i < suffixes.length; i++) {
92
+ if (this.hasSuffixInRegion(suffixes[i], region)) {
93
+ this.string = this.string.slice(0, -suffixes[i].length) + replace
94
+ return this
64
95
  }
65
-
66
- return this
67
- }
68
-
69
- /**
70
- * Replaces all instances of a string with another.
71
- *
72
- * @param {String} find String to be replaced.
73
- * @param {String} replace Replacement string.
74
- * @return {Token} Token instance.
75
- */
76
- Token.prototype.replaceAll = function (find, replace) {
77
- this.string = this.string.split(find).join(replace)
78
- return this
79
96
  }
80
-
81
- /**
82
- * Replaces the token suffix if in a region.
83
- *
84
- * @param {String} suffix Suffix to replace.
85
- * @param {String} replace Replacement string.
86
- * @param {String} region Region name.
87
- * @return {Token} Token instance.
88
- */
89
- Token.prototype.replaceSuffixInRegion = function (suffix, replace, region) {
90
- const suffixes = [].concat(suffix)
91
- for (let i = 0; i < suffixes.length; i++) {
92
- if (this.hasSuffixInRegion(suffixes[i], region)) {
93
- this.string = this.string.slice(0, -suffixes[i].length) + replace
94
- return this
95
- }
96
- }
97
- return this
97
+ return this
98
+ }
99
+
100
+ /**
101
+ * Determines whether the token has a vowel at the provided index.
102
+ *
103
+ * @param {Integer} index Character index.
104
+ * @return {Boolean} Whether the token has a vowel at the provided index.
105
+ */
106
+ Token.prototype.hasVowelAtIndex = function (index) {
107
+ return this.vowels.indexOf(this.string[index]) !== -1
108
+ }
109
+
110
+ /**
111
+ * Finds the next vowel in the token.
112
+ *
113
+ * @param {Integer} start Starting index offset.
114
+ * @return {Integer} Vowel index, or the end of the string.
115
+ */
116
+ Token.prototype.nextVowelIndex = function (start) {
117
+ let index = (start >= 0 && start < this.string.length) ? start : this.string.length
118
+ while (index < this.string.length && !this.hasVowelAtIndex(index)) {
119
+ index++
98
120
  }
99
-
100
- /**
101
- * Determines whether the token has a vowel at the provided index.
102
- *
103
- * @param {Integer} index Character index.
104
- * @return {Boolean} Whether the token has a vowel at the provided index.
105
- */
106
- Token.prototype.hasVowelAtIndex = function (index) {
107
- return this.vowels.indexOf(this.string[index]) !== -1
121
+ return index
122
+ }
123
+
124
+ /**
125
+ * Finds the next consonant in the token.
126
+ *
127
+ * @param {Integer} start Starting index offset.
128
+ * @return {Integer} Consonant index, or the end of the string.
129
+ */
130
+ Token.prototype.nextConsonantIndex = function (start) {
131
+ let index = (start >= 0 && start < this.string.length) ? start : this.string.length
132
+ while (index < this.string.length && this.hasVowelAtIndex(index)) {
133
+ index++
108
134
  }
109
-
110
- /**
111
- * Finds the next vowel in the token.
112
- *
113
- * @param {Integer} start Starting index offset.
114
- * @return {Integer} Vowel index, or the end of the string.
115
- */
116
- Token.prototype.nextVowelIndex = function (start) {
117
- let index = (start >= 0 && start < this.string.length) ? start : this.string.length
118
- while (index < this.string.length && !this.hasVowelAtIndex(index)) {
119
- index++
120
- }
121
- return index
122
- }
123
-
124
- /**
125
- * Finds the next consonant in the token.
126
- *
127
- * @param {Integer} start Starting index offset.
128
- * @return {Integer} Consonant index, or the end of the string.
129
- */
130
- Token.prototype.nextConsonantIndex = function (start) {
131
- let index = (start >= 0 && start < this.string.length) ? start : this.string.length
132
- while (index < this.string.length && this.hasVowelAtIndex(index)) {
133
- index++
134
- }
135
- return index
136
- }
137
-
138
- /**
139
- * Determines whether the token has the provided suffix.
140
- * @param {String} suffix Suffix to match.
141
- * @return {Boolean} Whether the token string ends in suffix.
142
- */
143
- Token.prototype.hasSuffix = function (suffix) {
144
- return this.string.slice(-suffix.length) === suffix
145
- }
146
-
147
- /**
148
- * Determines whether the token has the provided suffix within the specified
149
- * region.
150
- *
151
- * @param {String} suffix Suffix to match.
152
- * @param {String} region Region name.
153
- * @return {Boolean} Whether the token string ends in suffix.
154
- */
155
- Token.prototype.hasSuffixInRegion = function (suffix, region) {
156
- const regionStart = this.regions[region] || 0
157
- const suffixStart = this.string.length - suffix.length
158
- return this.hasSuffix(suffix) && suffixStart >= regionStart
159
- }
160
-
161
- return Token
162
- })()
135
+ return index
136
+ }
137
+
138
+ /**
139
+ * Determines whether the token has the provided suffix.
140
+ * @param {String} suffix Suffix to match.
141
+ * @return {Boolean} Whether the token string ends in suffix.
142
+ */
143
+ Token.prototype.hasSuffix = function (suffix) {
144
+ return this.string.slice(-suffix.length) === suffix
145
+ }
146
+
147
+ /**
148
+ * Determines whether the token has the provided suffix within the specified
149
+ * region.
150
+ *
151
+ * @param {String} suffix Suffix to match.
152
+ * @param {String} region Region name.
153
+ * @return {Boolean} Whether the token string ends in suffix.
154
+ */
155
+ Token.prototype.hasSuffixInRegion = function (suffix, region) {
156
+ const regionStart = this.regions[region] || 0
157
+ const suffixStart = this.string.length - suffix.length
158
+ return this.hasSuffix(suffix) && suffixStart >= regionStart
159
+ }
160
+
161
+ module.exports = Token
@@ -23,9 +23,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  THE SOFTWARE.
24
24
  */
25
25
 
26
- import { Tokenizer } from '../tokenizers'
26
+ import type { Tokenizer } from '../tokenizers'
27
27
 
28
- declare type TfIdfCallback = (i: number, measure: number, key?: string) => void
28
+ declare type TfIdfCallback = (i: number, measure: number, key?: string | Record<string, any>) => void
29
29
 
30
30
  declare interface TfIdfTerm {
31
31
  term: string
@@ -34,15 +34,15 @@ declare interface TfIdfTerm {
34
34
  tfidf: number
35
35
  }
36
36
 
37
- declare type TfIdfDocument = { __key: string | undefined } | { [key: string]: number | undefined }
37
+ declare type TfIdfDocument = Record<string, number>
38
38
 
39
39
  export class TfIdf {
40
- documents: TfIdfDocument | undefined
41
- _idfCache: { [key: string]: number } | undefined
40
+ documents: TfIdfDocument[]
41
+ _idfCache: Record<string, number>
42
42
 
43
- constructor (deserialized?: { documents: TfIdfDocument[] })
43
+ constructor (deserialized?: Record<string, unknown>)
44
44
  idf (term: string, force?: boolean): number
45
- addDocument (document: string | string[], key?: string, restoreCache?: boolean): void
45
+ addDocument (document: string | string[] | Record<string, string>, key?: Record<string, any> | any, restoreCache?: boolean): void
46
46
  addFileSync (path: string, encoding?: string, key?: string, restoreCache?: boolean): void
47
47
  tfidf (terms: string | string[], d: number): number
48
48
  tfidfs (terms: string | string[], callback?: TfIdfCallback): number[]
@@ -26,6 +26,8 @@ let tokenizer = new Tokenizer()
26
26
  let stopwords = require('../util/stopwords').words
27
27
  const fs = require('fs')
28
28
 
29
+ // Returns a frequency map of word to frequency
30
+ // Key is the document key and stored in the map that is returned as __keys
29
31
  function buildDocument (text, key) {
30
32
  let stopOut
31
33
 
@@ -87,6 +89,8 @@ class TfIdf {
87
89
  return document[term] ? document[term] : 0
88
90
  }
89
91
 
92
+ // Returns the inverse document frequency of the term
93
+ // If force is true the cache will be invalidated and recomputed
90
94
  idf (term, force) {
91
95
  // Lookup the term in the New term-IDF caching,
92
96
  // this will cut search times down exponentially on large document sets.
@@ -95,10 +99,12 @@ class TfIdf {
95
99
  return this._idfCache[term]
96
100
  }
97
101
 
102
+ // Count the number of documents that contain the term
98
103
  const docsWithTerm = this.documents.reduce(function (count, document) {
99
104
  return count + (documentHasTerm(term, document) ? 1 : 0)
100
105
  }, 0)
101
106
 
107
+ // Compute the inverse document frequency
102
108
  const idf = 1 + Math.log((this.documents.length) / (1 + docsWithTerm))
103
109
 
104
110
  // Add the idf to the term cache and return it
@@ -169,7 +175,7 @@ class TfIdf {
169
175
  if (this.documents[d]) {
170
176
  if (term !== '__key') {
171
177
  terms.push({
172
- term: term,
178
+ term,
173
179
  tf: TfIdf.tf(term, _this.documents[d]),
174
180
  idf: _this.idf(term),
175
181
  tfidf: _this.tfidf(term, d)
@@ -92,7 +92,7 @@ export class AggressiveTokenizer extends Tokenizer {
92
92
  }
93
93
 
94
94
  export class CaseTokenizer extends Tokenizer {
95
- tokenize (text: string): string[]
95
+ tokenize (text: string, preserveApostrophe?: boolean): string[]
96
96
  }
97
97
 
98
98
  declare interface RegexTokenizerOptions {
@@ -103,7 +103,7 @@ declare interface RegexTokenizerOptions {
103
103
 
104
104
  export class RegexpTokenizer extends Tokenizer {
105
105
  constructor (opts?: RegexTokenizerOptions)
106
- tokenize (text: string): string[] | null
106
+ tokenize (text: string): string[]
107
107
  }
108
108
 
109
109
  declare interface OrthographyTokenizerOptions extends RegexTokenizerOptions {
@@ -27,7 +27,7 @@ export class Trie {
27
27
  addString (string: string): boolean
28
28
  addStrings (list: string[]): void
29
29
  contains (string: string): boolean
30
- findPrefix (search: string): string[]
30
+ findPrefix (search: string): Array<string | null>
31
31
  findMatchesOnPath (search: string): string[]
32
32
  keysWithPrefix (prefix: string): string[]
33
33
  getSize (): number
@@ -70,3 +70,11 @@ export class LongestPathTree {
70
70
  hasPathTo (vertex: number): boolean
71
71
  pathTo (vertex: number): number[]
72
72
  }
73
+
74
+ export class Topological {
75
+ constructor (digraph: EdgeWeightedDigraph)
76
+ isDAG (): boolean
77
+ order (): number[]
78
+ }
79
+
80
+ export * from './storage'
@@ -27,3 +27,5 @@ exports.ShortestPathTree = require('./shortest_path_tree')
27
27
  exports.LongestPathTree = require('./longest_path_tree')
28
28
  exports.DirectedEdge = require('./directed_edge')
29
29
  exports.EdgeWeightedDigraph = require('./edge_weighted_digraph')
30
+ exports.Topological = require('./topological')
31
+ exports.StorageBackend = require('./storage')
@@ -1,3 +1,25 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  require('dotenv').config()
2
24
  const { v4: uuidv4 } = require('uuid')
3
25
  const fs = require('fs').promises
@@ -1,3 +1,25 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  const { v4: uuidv4 } = require('uuid')
2
24
  require('dotenv').config()
3
25
  const memjs = require('memjs')
@@ -1,14 +1,42 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  require('dotenv').config()
2
24
  const mongoose = require('mongoose')
3
25
  const mongoDBConnectionString = 'mongodb://' + process.env.MONGO_HOST + ':' +
4
26
  process.env.MONGO_PORT + '/' + process.env.MONGO_DATABASE
27
+ const objectModelName = process.env.MONGO_OBJECTMODEL
5
28
 
6
29
  class MongoDBPlugin {
7
30
  constructor () {
8
31
  mongoose.connect(mongoDBConnectionString, {})
9
- // We do not enforce a schema with MongoDB
10
- this.ObjectModel = mongoose.model('ObjectModel', new mongoose.Schema({},
11
- { strict: false, versionKey: false }))
32
+
33
+ if (!mongoose.models[objectModelName]) {
34
+ // We do not enforce a schema with MongoDB
35
+ this.ObjectModel = mongoose.model(objectModelName, new mongoose.Schema({},
36
+ { strict: false, versionKey: false }))
37
+ } else {
38
+ this.ObjectModel = mongoose.models[objectModelName]
39
+ }
12
40
  }
13
41
 
14
42
  async store (object, options) {
@@ -1,54 +1,71 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  const postgres = require('pg')
2
24
  require('dotenv').config()
3
25
 
4
26
  class PostgresPlugin {
5
27
  constructor () {
6
- this.configPostgres()
28
+ this.postgresClient = null
7
29
  }
8
30
 
9
31
  async configPostgres () {
10
32
  // Initialize connection to Postgres
11
33
  const client = new postgres.Client({
12
- user: process.env.PG_USER,
13
- host: process.env.PG_HOST,
14
- database: process.env.PG_DATABASE,
15
- password: process.env.PG_PASSWORD,
16
- port: process.env.PG_PORT
34
+ user: process.env.POSTGRES_USER,
35
+ host: process.env.POSTGRES_HOST,
36
+ database: process.env.POSTGRES_DB,
37
+ password: process.env.POSTGRES_PASSWORD,
38
+ port: process.env.POSTGRES_PORT
17
39
  })
18
40
  this.postgresClient = client
19
- this.postgresTableName = process.env.PG_TABLE
41
+ this.postgresTableName = process.env.POSTGRES_TABLE
42
+
20
43
  // Connect to the database
21
- return new Promise((resolve, reject) => {
22
- client.connect()
23
- .then(() => {
24
- // Call the function to create the table
25
- createTable(this.postgresTableName)
26
- resolve()
27
- })
28
- .catch(err => {
29
- console.error('Error connecting to the database:', err)
30
- reject(err)
31
- })
32
- })
44
+ await client.connect()
45
+
46
+ // Call the function to create the table
47
+ await this.createTableIfNotExists(client, this.postgresTableName)
48
+
49
+ // Don't forget to close the connection when done
50
+ // await client.end()
51
+ }
52
+
53
+ // Function to create the table
54
+ async createTableIfNotExists (client, tableName) {
55
+ // Check if the table exists
56
+ const query = `SELECT to_regclass('${tableName}')`
57
+ const result = await client.query(query)
33
58
 
34
- // Function to create the table
35
- function createTable (tableName) {
36
- // We use JSONB (binary JSON format of Postgres) to store objects
59
+ if (result.rows[0].to_regclass === null) {
60
+ // Table does not exist, create it
37
61
  const createTableQuery = `
38
- CREATE TABLE IF NOT EXISTS ${tableName} (
62
+ CREATE TABLE ${tableName} (
39
63
  id SERIAL PRIMARY KEY,
40
64
  data JSONB
41
65
  );
42
66
  `
43
- return new Promise((resolve, reject) => {
44
- client.query(createTableQuery)
45
- .then(() => {
46
- resolve()
47
- })
48
- .catch(error => {
49
- reject(error)
50
- })
51
- })
67
+ await client.query(createTableQuery)
68
+ console.log('table created')
52
69
  }
53
70
  }
54
71
 
@@ -1,3 +1,25 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  const { v4: uuidv4 } = require('uuid')
2
24
  require('dotenv').config()
3
25
  const redis = require('redis')
@@ -1,3 +1,25 @@
1
+ /*
2
+ Copyright (c) 2024, Hugo W.L. ter Doest
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ */
22
+
1
23
  const PostgresPlugin = require('./Postgres')
2
24
  const MongoDBPlugin = require('./MongoDB')
3
25
  const RedisPlugin = require('./Redis')
@@ -38,6 +60,7 @@ class StorageBackend {
38
60
  switch (storageType) {
39
61
  case STORAGE_TYPES.POSTGRES:
40
62
  this.client = new PostgresPlugin()
63
+ await this.client.configPostgres()
41
64
  break
42
65
  case STORAGE_TYPES.REDIS:
43
66
  this.client = new RedisPlugin()