json-fs-query 0.1.0 → 0.1.1

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 (198) hide show
  1. package/dist/data/introspect/create.js +6 -4
  2. package/dist/data/introspect/create.min.js +1 -1
  3. package/dist/data/introspect/drop.js +2 -2
  4. package/dist/data/introspect/drop.min.js +1 -1
  5. package/dist/data/queries/deleteEntity.js +3 -3
  6. package/dist/data/queries/deleteEntity.min.js +1 -1
  7. package/dist/data/queries/groupBy.js +22 -22
  8. package/dist/data/queries/groupBy.min.js +1 -1
  9. package/dist/data/queries/insertEntity.js +5 -5
  10. package/dist/data/queries/insertEntity.min.js +1 -1
  11. package/dist/data/queries/readEntity.js +1 -1
  12. package/dist/data/queries/readEntity.min.js +1 -1
  13. package/dist/data/queries/updateEntity.js +6 -6
  14. package/dist/data/queries/updateEntity.min.js +1 -1
  15. package/dist/data/queries/where.js +1 -1
  16. package/dist/data/queries/where.min.js +1 -1
  17. package/dist/data/utilities/config.d.ts +22 -0
  18. package/dist/data/utilities/config.js +39 -0
  19. package/dist/data/utilities/config.min.js +1 -0
  20. package/dist/data/utilities/deregisterRecord.js +2 -2
  21. package/dist/data/utilities/deregisterRecord.min.js +1 -1
  22. package/dist/data/utilities/getConditionIndexedList.js +1 -1
  23. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  24. package/dist/data/utilities/getJoinIndexedList.js +2 -2
  25. package/dist/data/utilities/getJoinIndexedList.min.js +1 -1
  26. package/dist/data/utilities/getMatchingIndexes.js +2 -2
  27. package/dist/data/utilities/getMatchingIndexes.min.js +1 -1
  28. package/dist/data/utilities/matchIndexedJoins.js +2 -2
  29. package/dist/data/utilities/matchIndexedJoins.min.js +1 -1
  30. package/dist/data/utilities/reconcileJoin.js +26 -26
  31. package/dist/data/utilities/reconcileJoin.min.js +1 -1
  32. package/dist/data/utilities/reconcileJoins.js +26 -27
  33. package/dist/data/utilities/reconcileJoins.min.js +1 -1
  34. package/dist/data/utilities/registerRecord.js +2 -2
  35. package/dist/data/utilities/registerRecord.min.js +1 -1
  36. package/dist/data/utilities/removeFromIndex.js +2 -2
  37. package/dist/data/utilities/removeFromIndex.min.js +1 -1
  38. package/dist/data/utilities/restrictIndexedList.js +45 -45
  39. package/dist/data/utilities/restrictIndexedList.min.js +1 -1
  40. package/dist/data/utilities/retrieveFile.js +3 -3
  41. package/dist/data/utilities/retrieveFile.min.js +1 -1
  42. package/dist/data/utilities/retrieveIndexes.js +1 -1
  43. package/dist/data/utilities/retrieveIndexes.min.js +1 -1
  44. package/dist/data/utilities/updateIndex.js +2 -2
  45. package/dist/data/utilities/updateIndex.min.js +1 -1
  46. package/dist/data/utilities/useJoinClause.js +4 -4
  47. package/dist/data/utilities/useJoinClause.min.js +1 -1
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +7 -0
  50. package/dist/index.min.js +1 -1
  51. package/package.json +5 -1
  52. package/.browserslistrc +0 -1
  53. package/.nvmrc +0 -1
  54. package/MAIN.md +0 -15
  55. package/babel.config.js +0 -3
  56. package/build-tools.config.json +0 -30
  57. package/gulpfile.mjs +0 -15
  58. package/src/data/introspect/create.test.js +0 -67
  59. package/src/data/introspect/create.ts +0 -29
  60. package/src/data/introspect/definitions/field.test.js +0 -23
  61. package/src/data/introspect/definitions/field.ts +0 -48
  62. package/src/data/introspect/definitions/key.test.js +0 -100
  63. package/src/data/introspect/definitions/key.ts +0 -64
  64. package/src/data/introspect/definitions/keyReference.test.js +0 -8
  65. package/src/data/introspect/definitions/keyReference.ts +0 -23
  66. package/src/data/introspect/definitions/record.ts +0 -42
  67. package/src/data/introspect/describe.test.js +0 -36
  68. package/src/data/introspect/describe.ts +0 -9
  69. package/src/data/introspect/drop.test.js +0 -77
  70. package/src/data/introspect/drop.ts +0 -20
  71. package/src/data/introspect/index.ts +0 -8
  72. package/src/data/introspect/policies/foreignKeyExists.test.js +0 -44
  73. package/src/data/introspect/policies/foreignKeyExists.ts +0 -15
  74. package/src/data/introspect/policies/keyGenerate.ts +0 -11
  75. package/src/data/introspect/policies/keyUnique.ts +0 -11
  76. package/src/data/introspect/policies/typeCheck.test.js +0 -84
  77. package/src/data/introspect/policies/typeCheck.ts +0 -49
  78. package/src/data/introspect/policies/typeEnum.ts +0 -6
  79. package/src/data/introspect/policies/useDefault.ts +0 -6
  80. package/src/data/queries/deleteEntity.test.js +0 -86
  81. package/src/data/queries/deleteEntity.ts +0 -56
  82. package/src/data/queries/groupBy.test.js +0 -135
  83. package/src/data/queries/groupBy.ts +0 -16
  84. package/src/data/queries/insertEntity.test.js +0 -156
  85. package/src/data/queries/insertEntity.ts +0 -113
  86. package/src/data/queries/joinEntity.test.js +0 -109
  87. package/src/data/queries/joinEntity.ts +0 -20
  88. package/src/data/queries/mergeJoins.test.js +0 -174
  89. package/src/data/queries/mergeJoins.ts +0 -13
  90. package/src/data/queries/parser.test.js +0 -343
  91. package/src/data/queries/parser.ts +0 -24
  92. package/src/data/queries/query.test.js +0 -233
  93. package/src/data/queries/query.ts +0 -12
  94. package/src/data/queries/readEntity.test.js +0 -85
  95. package/src/data/queries/readEntity.ts +0 -8
  96. package/src/data/queries/sortBy.test.js +0 -131
  97. package/src/data/queries/sortBy.ts +0 -18
  98. package/src/data/queries/updateEntity.test.js +0 -228
  99. package/src/data/queries/updateEntity.ts +0 -162
  100. package/src/data/queries/where.test.js +0 -129
  101. package/src/data/queries/where.ts +0 -54
  102. package/src/data/utilities/deregisterRecord.test.js +0 -26
  103. package/src/data/utilities/deregisterRecord.ts +0 -24
  104. package/src/data/utilities/getConditionIndexedList.ts +0 -43
  105. package/src/data/utilities/getJoinIndexedList.ts +0 -53
  106. package/src/data/utilities/getMatchingIndexes.ts +0 -21
  107. package/src/data/utilities/matchIndexedJoins.ts +0 -45
  108. package/src/data/utilities/mergeJoin.test.js +0 -102
  109. package/src/data/utilities/mergeJoin.ts +0 -28
  110. package/src/data/utilities/parsers/findCommand.ts +0 -25
  111. package/src/data/utilities/parsers/findConditions.test.js +0 -38
  112. package/src/data/utilities/parsers/findConditions.ts +0 -32
  113. package/src/data/utilities/parsers/findGroupBy.ts +0 -20
  114. package/src/data/utilities/parsers/findInsertValues.test.js +0 -26
  115. package/src/data/utilities/parsers/findInsertValues.ts +0 -32
  116. package/src/data/utilities/parsers/findJoinClauses.ts +0 -29
  117. package/src/data/utilities/parsers/findJoinEntity.ts +0 -20
  118. package/src/data/utilities/parsers/findLimit.ts +0 -20
  119. package/src/data/utilities/parsers/findMergeJoins.ts +0 -27
  120. package/src/data/utilities/parsers/findOffset.ts +0 -20
  121. package/src/data/utilities/parsers/findSelects.ts +0 -31
  122. package/src/data/utilities/parsers/findSortClauses.ts +0 -31
  123. package/src/data/utilities/parsers/findUpdateValues.test.js +0 -37
  124. package/src/data/utilities/parsers/findUpdateValues.ts +0 -32
  125. package/src/data/utilities/parsers/isEntityProperty.ts +0 -1
  126. package/src/data/utilities/parsers/parseLiteralValue.test.js +0 -41
  127. package/src/data/utilities/parsers/parseLiteralValue.ts +0 -29
  128. package/src/data/utilities/parsers/parseQuery.ts +0 -73
  129. package/src/data/utilities/parsers/removeFromQuery.ts +0 -1
  130. package/src/data/utilities/parsers/splitEntityProperty.test.js +0 -8
  131. package/src/data/utilities/parsers/splitEntityProperty.ts +0 -17
  132. package/src/data/utilities/parsers/splitQueries.test.js +0 -33
  133. package/src/data/utilities/parsers/splitQueries.ts +0 -4
  134. package/src/data/utilities/reconcileJoin.test.js +0 -38
  135. package/src/data/utilities/reconcileJoin.ts +0 -23
  136. package/src/data/utilities/reconcileJoins.test.js +0 -160
  137. package/src/data/utilities/reconcileJoins.ts +0 -15
  138. package/src/data/utilities/registerRecord.test.js +0 -44
  139. package/src/data/utilities/registerRecord.ts +0 -44
  140. package/src/data/utilities/removeFromIndex.test.js +0 -44
  141. package/src/data/utilities/removeFromIndex.ts +0 -34
  142. package/src/data/utilities/restrictIndexedList.ts +0 -38
  143. package/src/data/utilities/retrieveFile.test.js +0 -49
  144. package/src/data/utilities/retrieveFile.ts +0 -19
  145. package/src/data/utilities/retrieveIndexes.ts +0 -17
  146. package/src/data/utilities/retrieveRecord.ts +0 -3
  147. package/src/data/utilities/retrieveRecords.test.js +0 -223
  148. package/src/data/utilities/retrieveRecords.ts +0 -16
  149. package/src/data/utilities/runQuery.test.js +0 -88
  150. package/src/data/utilities/runQuery.ts +0 -75
  151. package/src/data/utilities/updateIndex.test.js +0 -44
  152. package/src/data/utilities/updateIndex.ts +0 -45
  153. package/src/data/utilities/useJoinClause.test.js +0 -94
  154. package/src/data/utilities/useJoinClause.ts +0 -44
  155. package/src/global.d.ts +0 -1
  156. package/src/index.test.js +0 -52
  157. package/src/index.ts +0 -17
  158. package/test-data/__RECORDS.json +0 -32
  159. package/test-data/__indexes/exercise_muscle/fk_exercise_id.json +0 -14
  160. package/test-data/__indexes/exercise_muscle/fk_muscle_id.json +0 -14
  161. package/test-data/__indexes/exercise_muscle/pk__id.json +0 -14
  162. package/test-data/__indexes/exercises/pk__id.json +0 -14
  163. package/test-data/__indexes/muscles/pk__id.json +0 -58
  164. package/test-data/__indexes/workouts/fk_exercise_id.json +0 -23
  165. package/test-data/__indexes/workouts/index_date.json +0 -18
  166. package/test-data/__indexes/workouts/pk__id.json +0 -26
  167. package/test-data/copyDatabase.ts +0 -64
  168. package/test-data/exercise_muscle/bench_press_pectorals.json +0 -6
  169. package/test-data/exercise_muscle/deadlift_hamstrings.json +0 -6
  170. package/test-data/exercise_muscle/squat_quadriceps.json +0 -6
  171. package/test-data/exercise_muscle.json +0 -69
  172. package/test-data/exercises/bench_press.json +0 -5
  173. package/test-data/exercises/deadlift.json +0 -5
  174. package/test-data/exercises/squat.json +0 -5
  175. package/test-data/exercises.json +0 -34
  176. package/test-data/muscles/abdominal.json +0 -6
  177. package/test-data/muscles/biceps.json +0 -6
  178. package/test-data/muscles/calves.json +0 -6
  179. package/test-data/muscles/deltoids.json +0 -6
  180. package/test-data/muscles/erector_spinae.json +0 -6
  181. package/test-data/muscles/forearms.json +0 -6
  182. package/test-data/muscles/gluteus_maximus.json +0 -6
  183. package/test-data/muscles/hamstrings.json +0 -6
  184. package/test-data/muscles/latissimus_dorsi.json +0 -6
  185. package/test-data/muscles/obliques.json +0 -6
  186. package/test-data/muscles/pectorals.json +0 -6
  187. package/test-data/muscles/quadriceps.json +0 -6
  188. package/test-data/muscles/trapezius.json +0 -6
  189. package/test-data/muscles/triceps.json +0 -6
  190. package/test-data/muscles.json +0 -50
  191. package/test-data/workouts/2024-06-02-001.json +0 -10
  192. package/test-data/workouts/2024-06-02-002.json +0 -10
  193. package/test-data/workouts/2024-06-02-003.json +0 -10
  194. package/test-data/workouts/2024-06-05-001.json +0 -10
  195. package/test-data/workouts/2024-06-05-002.json +0 -10
  196. package/test-data/workouts/2024-06-05-003.json +0 -10
  197. package/test-data/workouts.json +0 -84
  198. package/tsconfig.json +0 -15
@@ -1,53 +0,0 @@
1
- import siFunciona from 'si-funciona'
2
- import { splitEntityProperty } from './parsers/splitEntityProperty'
3
- import { retrieveRecord } from './retrieveRecord'
4
- import { ParsedQuery } from './parsers/parseQuery'
5
- import { getMatchingIndexes } from './getMatchingIndexes'
6
- import { matchIndexedJoins } from './matchIndexedJoins'
7
- import { restrictIndexedList } from './restrictIndexedList'
8
-
9
- export const getJoinIndexedList = async (parsed: ParsedQuery, recordData, dataSets) => {
10
- let reducedJoins = []
11
- const indexed = {}
12
- let firstIteration = true
13
- const entity = parsed.entity
14
- const joinEntity = parsed.joinEntity
15
- const joinClauses = parsed.joinClauses
16
- for (const anEntity in dataSets[entity]) {
17
- const currentEntity = dataSets[entity][anEntity]
18
- // Loop over each of the main entities
19
- let filterJoins = {}
20
- filterJoins[entity] = [siFunciona.cloneObject(currentEntity)]
21
- for (let joinClause of joinClauses) {
22
- let indexedClone = siFunciona.cloneObject(indexed)
23
- const { entity: entityA, property: propertyA } = splitEntityProperty(joinClause.propertyA)
24
- const { entity: entityB, property: propertyB } = splitEntityProperty(joinClause.propertyB)
25
-
26
- // Get the record for the entities A and B, store on the recordData
27
- if (!recordData.hasOwnProperty(entityA)) {
28
- recordData[entityA] = await retrieveRecord(entityA)
29
- }
30
- if (!recordData.hasOwnProperty(entityB)) {
31
- recordData[entityB] = await retrieveRecord(entityB)
32
- }
33
-
34
- indexedClone = restrictIndexedList(joinClause, filterJoins, indexedClone)
35
-
36
- const retrieveMatchedFiles = matchIndexedJoins(entity, indexedClone, dataSets)
37
-
38
- // Check if there are matching keys for the join condition
39
- const matchAResult = await getMatchingIndexes(entityA, propertyA, recordData, joinClause, filterJoins, indexed)
40
- const matchBResult = await getMatchingIndexes(entityB, propertyB, recordData, joinClause, filterJoins, indexed, retrieveMatchedFiles)
41
-
42
- const isIndexed = matchAResult || matchBResult
43
-
44
- if (!isIndexed && firstIteration) {
45
- reducedJoins.push(joinClause)
46
- firstIteration = false
47
- }
48
- }
49
- dataSets[entity][anEntity][joinEntity] = filterJoins[joinEntity]
50
- }
51
- parsed.joinClauses = reducedJoins
52
- return parsed
53
- }
@@ -1,21 +0,0 @@
1
- import { retrieveIndexes } from './retrieveIndexes'
2
-
3
- export const getMatchingIndexes = async (entity: string, property: string, recordData: Object, clause: Object, dataSet: Object, indexed: Object, cb: Function = null): Promise<boolean> => {
4
- let isIndexed = false
5
- for (let key of recordData[entity].keys) {
6
- if (key.fields.includes(property)) {
7
- dataSet[entity] = []
8
- if (!indexed.hasOwnProperty(entity)) {
9
- indexed[entity] = {}
10
- }
11
- if (!indexed[entity].hasOwnProperty(property)) {
12
- indexed[entity][property] = (await retrieveIndexes(entity, [property], recordData))[property]
13
- }
14
- if (typeof cb === 'function') {
15
- await cb(entity, property, recordData, clause, dataSet, indexed)
16
- }
17
- isIndexed = true
18
- }
19
- }
20
- return isIndexed
21
- }
@@ -1,45 +0,0 @@
1
- import siFunciona from 'si-funciona'
2
- import { where } from '../queries/where'
3
- import { retrieveFile } from './retrieveFile'
4
- import { splitEntityProperty } from './parsers/splitEntityProperty'
5
-
6
- export const matchIndexedJoins = (entity, indexedClone, dataSets) => async (focusEntity, property, recordData, joinClause, filterJoins, indexed) => {
7
- const { entity: entityA, property: propertyA } = splitEntityProperty(joinClause.propertyA)
8
- const { entity: entityB, property: propertyB } = splitEntityProperty(joinClause.propertyB)
9
- const properties = [
10
- { entityFirst: entityA, propertyFirst: propertyA, entitySecond: entityB, propertySecond: propertyB },
11
- { entityFirst: entityB, propertyFirst: propertyB, entitySecond: entityA, propertySecond: propertyA },
12
- ]
13
- for (let checkProp of properties) {
14
- if (!indexedClone.hasOwnProperty(checkProp.entitySecond)) {
15
- indexedClone[checkProp.entitySecond] = siFunciona.cloneObject(indexed[checkProp.entitySecond])
16
- }
17
- const matchedRecords = indexedClone[checkProp.entitySecond][checkProp.propertySecond].reduce(
18
- (dataA, dataB) => siFunciona.mergeArrays(
19
- dataA,
20
- where(indexedClone[checkProp.entityFirst][checkProp.propertyFirst], {
21
- property: 'value',
22
- comparator: joinClause.comparator,
23
- value: dataB.value
24
- })
25
- ),
26
- []
27
- )
28
- let skipPush = checkProp.entityFirst === entity
29
- if (!dataSets.hasOwnProperty(checkProp.entityFirst)) {
30
- dataSets[checkProp.entityFirst] = []
31
- }
32
- for (let matchedRecord of matchedRecords) {
33
- for (let file of matchedRecord.record) {
34
- let entityRecord = file
35
- if (typeof file === 'string') {
36
- entityRecord = await retrieveFile(`${checkProp.entityFirst}/${file}`)
37
- }
38
- if (!skipPush) {
39
- dataSets[checkProp.entityFirst].push(entityRecord)
40
- }
41
- filterJoins[checkProp.entityFirst].push(entityRecord)
42
- }
43
- }
44
- }
45
- }
@@ -1,102 +0,0 @@
1
- import { mergeJoin } from './mergeJoin'
2
- import { testHelpers } from 'js-build-tools/testHelpers'
3
- import { copyDatabase } from '../../../test-data/copyDatabase'
4
-
5
- const databasePath = 'merge-join-database/'
6
- const gulpConfig = testHelpers.gulpConfig
7
- gulpConfig.set('databasePath', databasePath)
8
- testHelpers.setDefaults(databasePath)
9
-
10
- beforeEach(
11
- () => testHelpers.beforeEach()
12
- .then(() => copyDatabase(databasePath))
13
- )
14
-
15
- afterEach(testHelpers.afterEach)
16
-
17
- describe('mergeJoin', () => {
18
- test('can combine both entities', async () => {
19
- const results = await mergeJoin('workouts.exercise_id', 'exercises._id')
20
- expect(results).toEqual({
21
- workouts: [
22
- {
23
- _id: 1,
24
- exercise_id: 1,
25
- weight_effort: '115lbs',
26
- reps: 10,
27
- sets: 3,
28
- note: '',
29
- order: 0,
30
- date: '2024-06-02',
31
- 'exercises.name': 'Bench Press',
32
- 'exercises.description': ''
33
- },
34
- {
35
- _id: 2,
36
- exercise_id: 2,
37
- weight_effort: '155lbs',
38
- reps: 10,
39
- sets: 3,
40
- note: '',
41
- order: 1,
42
- date: '2024-06-02',
43
- 'exercises.name': 'Deadlift',
44
- 'exercises.description': ''
45
- },
46
- {
47
- _id: 3,
48
- exercise_id: 3,
49
- weight_effort: '155lbs',
50
- reps: 10,
51
- sets: 3,
52
- note: '',
53
- order: 2,
54
- date: '2024-06-02',
55
- 'exercises.name': 'Squat',
56
- 'exercises.description': ''
57
- },
58
- {
59
- _id: 4,
60
- exercise_id: 1,
61
- weight_effort: '120lbs',
62
- reps: 10,
63
- sets: 3,
64
- note: '',
65
- order: 0,
66
- date: '2024-06-05',
67
- 'exercises.name': 'Bench Press',
68
- 'exercises.description': ''
69
- },
70
- {
71
- _id: 5,
72
- exercise_id: 2,
73
- weight_effort: '160lbs',
74
- reps: 10,
75
- sets: 3,
76
- note: '',
77
- order: 1,
78
- date: '2024-06-05',
79
- 'exercises.name': 'Deadlift',
80
- 'exercises.description': ''
81
- },
82
- {
83
- _id: 6,
84
- exercise_id: 3,
85
- weight_effort: '160lbs',
86
- reps: 10,
87
- sets: 3,
88
- note: '',
89
- order: 2,
90
- date: '2024-06-05',
91
- 'exercises.name': 'Squat',
92
- 'exercises.description': ''
93
- }
94
- ],
95
- exercises: [
96
- { _id: 1, name: 'Bench Press', description: '' },
97
- { _id: 2, name: 'Deadlift', description: '' },
98
- { _id: 3, name: 'Squat', description: '' }
99
- ]
100
- })
101
- })
102
- })
@@ -1,28 +0,0 @@
1
- import { readEntity } from '../queries/readEntity'
2
- import { splitEntityProperty } from './parsers/splitEntityProperty'
3
- import { where } from '../queries/where'
4
-
5
- export const mergeJoin = async (propertyA = '', propertyB = '', dataSets = {}) => {
6
- const { entity: entityA, property: propA } = splitEntityProperty(propertyA)
7
- const { entity: entityB, property: propB } = splitEntityProperty(propertyB)
8
-
9
- dataSets = await readEntity(entityA, dataSets)
10
- dataSets = await readEntity(entityB, dataSets)
11
-
12
- dataSets[entityA] = dataSets[entityA].map((dataA) => {
13
- const matches = where(dataSets[entityB], { property: propB, comparator: '=', value: dataA[propA] })
14
- if (!matches.length) {
15
- return dataA
16
- }
17
- const mergeMatch = matches[0]
18
- for (let prop in mergeMatch) {
19
- if (prop === propB) {
20
- // Skip the condition property since it is irrelevant
21
- continue
22
- }
23
- dataA[`${entityB}.${prop}`] = mergeMatch[prop]
24
- }
25
- return dataA
26
- })
27
- return dataSets
28
- }
@@ -1,25 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const commandMatch: RegExp = /^(delete|insert|read|update)\s+([a-z0-9_-]+)[\w\n]*/i
5
-
6
- export type ParsedCommand = string | 'delete' | 'insert' | 'read' | 'update'
7
-
8
- export type ParsedEntity = string
9
-
10
- /**
11
- * Extract command clauses from the query.
12
- * @param parsed
13
- * @param query
14
- */
15
- export const findCommand = (parsed: ParsedQuery, query: string): string => {
16
- const commandFound: RegExpMatchArray = query.match(commandMatch)
17
- parsed['command'] = undefined
18
- parsed['entity'] = undefined
19
- if (commandFound) {
20
- parsed['command'] = commandFound[1]
21
- parsed['entity'] = commandFound[2]
22
- return removeFromQuery(commandFound[0], query)
23
- }
24
- return query
25
- }
@@ -1,38 +0,0 @@
1
- import { findConditions } from './findConditions'
2
-
3
- const parse = (query) => {
4
- const parsed = { conditions: [] }
5
- const remaining = findConditions(parsed, query)
6
- return { parsed, remaining }
7
- }
8
-
9
- describe('findConditions', () => {
10
- test('extracts a quoted string value', () => {
11
- const { parsed, remaining } = parse("where date = '2024-06-02'")
12
- expect(parsed.conditions).toEqual([{ property: 'date', comparator: '=', value: '2024-06-02' }])
13
- expect(remaining).toBe('')
14
- })
15
-
16
- test('extracts an unquoted number as a real number', () => {
17
- const { parsed } = parse('where reps > 10')
18
- expect(parsed.conditions).toEqual([{ property: 'reps', comparator: '>', value: 10 }])
19
- })
20
-
21
- test('extracts an array literal as a real array', () => {
22
- const { parsed } = parse('where exercise_id in [1,2,3]')
23
- expect(parsed.conditions).toEqual([{ property: 'exercise_id', comparator: 'in', value: [1, 2, 3] }])
24
- })
25
-
26
- test('extracts null as the real null value', () => {
27
- const { parsed } = parse('where note = null')
28
- expect(parsed.conditions).toEqual([{ property: 'note', comparator: '=', value: null }])
29
- })
30
-
31
- test('extracts true and false as real booleans', () => {
32
- const { parsed } = parse('where active = true where archived = false')
33
- expect(parsed.conditions).toEqual([
34
- { property: 'active', comparator: '=', value: true },
35
- { property: 'archived', comparator: '=', value: false }
36
- ])
37
- })
38
- })
@@ -1,32 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { parseLiteralValue, LiteralValue } from './parseLiteralValue'
3
- import { ParsedQuery } from './parseQuery'
4
-
5
- const conditionMatch: RegExp = /(and|or)?\s*(where)\s+([a-z0-9_-]+\.?[a-z0-9_-]*)\s+(=|!=|>|<|>=|<=|in|between|like)\s+(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/ig
6
-
7
- export type ConditionValue = LiteralValue
8
-
9
- export type ParsedCondition = {
10
- property: string
11
- comparator: string
12
- value: ConditionValue
13
- }
14
-
15
- /**
16
- * Extract condition clauses from the query.
17
- * @param parsed
18
- * @param query
19
- */
20
- export const findConditions = (parsed: ParsedQuery, query: string): string => {
21
- const conditionsFound: IterableIterator<RegExpMatchArray> = query.matchAll(conditionMatch)
22
- // @ts-ignore
23
- for (let condition of conditionsFound) {
24
- parsed['conditions'].push({
25
- property: condition[3],
26
- comparator: condition[4],
27
- value: parseLiteralValue(condition, 6)
28
- })
29
- query = removeFromQuery(condition[0], query)
30
- }
31
- return query
32
- }
@@ -1,20 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const groupMatch: RegExp = /group\s+by\s+(,?[a-z0-9._-]+)+/i
5
-
6
- export type ParsedGroupBy = string
7
-
8
- /**
9
- * Extract the group by clauses from the query.
10
- * @param parsed
11
- * @param query
12
- */
13
- export const findGroupBy = (parsed: ParsedQuery, query: string): string => {
14
- const groupFound: RegExpMatchArray = query.match(groupMatch)
15
- if (groupFound) {
16
- parsed['groupBy'] = groupFound ? groupFound[1] : undefined
17
- return removeFromQuery(groupFound[0], query)
18
- }
19
- return query
20
- }
@@ -1,26 +0,0 @@
1
- import { findInsertValues } from './findInsertValues'
2
-
3
- const parse = (query) => {
4
- const parsed = {}
5
- const remaining = findInsertValues(parsed, query)
6
- return { parsed, remaining }
7
- }
8
-
9
- describe('findInsertValues', () => {
10
- test('extracts a single row, wrapped in a one-element array', () => {
11
- const { parsed, remaining } = parse("insert workouts values reps = 12, date = '2024-06-02'")
12
- expect(parsed.insertValues).toEqual([{ reps: 12, date: '2024-06-02' }])
13
- expect(remaining).toBe('insert workouts')
14
- })
15
-
16
- test('extracts every literal shape', () => {
17
- const { parsed } = parse('values active = true, tags = [1,2,3], note = null')
18
- expect(parsed.insertValues).toEqual([{ active: true, tags: [1, 2, 3], note: null }])
19
- })
20
-
21
- test('leaves the query untouched, with an empty insertValues, when there is no values clause', () => {
22
- const { parsed, remaining } = parse("read workouts where date = '2024-06-02'")
23
- expect(parsed.insertValues).toEqual([])
24
- expect(remaining).toBe("read workouts where date = '2024-06-02'")
25
- })
26
- })
@@ -1,32 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { parseLiteralValue } from './parseLiteralValue'
3
- import { ParsedQuery } from './parseQuery'
4
-
5
- const literal = '(?:["\'][^"\']*[\'"]|[0-9]+|\\[.*?]|null|true|false)'
6
- const valuesClauseMatch: RegExp = new RegExp(`(values)\\s+([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`, 'i')
7
- const assignmentMatch: RegExp = /([a-z0-9_-]+)\s*=\s*(["'](.*?)['"]|([0-9]+)|(\[.*?])|(null)|(true)|(false))/ig
8
-
9
- export type ParsedInsertRow = { [field: string]: any }
10
-
11
- /**
12
- * Extract an insert's "values field = value, field2 = value2" clause from the query, the same way
13
- * findUpdateValues() does for "set". insertEntity() accepts an array of rows for bulk inserts, but
14
- * a query string only describes a single row for now - wrapped in a one-element array to match.
15
- * @param parsed
16
- * @param query
17
- */
18
- export const findInsertValues = (parsed: ParsedQuery, query: string): string => {
19
- const clauseFound: RegExpMatchArray = query.match(valuesClauseMatch)
20
- parsed['insertValues'] = []
21
- if (!clauseFound) {
22
- return query
23
- }
24
- const row = {}
25
- const assignmentsFound: IterableIterator<RegExpMatchArray> = clauseFound[2].matchAll(assignmentMatch)
26
- // @ts-ignore
27
- for (const assignment of assignmentsFound) {
28
- row[assignment[1]] = parseLiteralValue(assignment, 3)
29
- }
30
- parsed['insertValues'] = [row]
31
- return removeFromQuery(clauseFound[0], query)
32
- }
@@ -1,29 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const joinClauseMatch: RegExp = /(and)?\s*on\s+([a-z0-9_-]+\.[a-z0-9_-]+)\s+(=|!=|>|<|>=|<=|in|between|like)\s+([a-z0-9_-]+\.[a-z0-9_-]+)/ig
5
-
6
- export type ParsedJoinClause = {
7
- propertyA: string
8
- comparator: string
9
- propertyB: string
10
- }
11
-
12
- /**
13
- * Extract condition clauses from the query.
14
- * @param parsed
15
- * @param query
16
- */
17
- export const findJoinClauses = (parsed: ParsedQuery, query: string): string => {
18
- const joinClausesFound: IterableIterator<RegExpMatchArray> = query.matchAll(joinClauseMatch)
19
- // @ts-ignore
20
- for (let joinClause of joinClausesFound) {
21
- parsed['joinClauses'].push({
22
- propertyA: joinClause[2],
23
- comparator: joinClause[3],
24
- propertyB: joinClause[4]
25
- })
26
- query = removeFromQuery(joinClause[0], query)
27
- }
28
- return query
29
- }
@@ -1,20 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const joinEntityMatch: RegExp = /\.([a-z0-9_-]+)/i
5
-
6
- export type ParsedJoinEntity = string
7
-
8
- /**
9
- * Extract the main join entity from the query.
10
- * @param parsed
11
- * @param query
12
- */
13
- export const findJoinEntity = (parsed: ParsedQuery, query: string): string => {
14
- const joinEntityFound: RegExpMatchArray = query.match(joinEntityMatch)
15
- if (joinEntityFound) {
16
- parsed['joinEntity'] = joinEntityFound ? joinEntityFound[1] : undefined
17
- return removeFromQuery(joinEntityFound[0], query)
18
- }
19
- return query
20
- }
@@ -1,20 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const limitMatch: RegExp = /limit\s*(\d+)/i
5
-
6
- export type ParsedLimit = number
7
-
8
- /**
9
- * Extract the limit clauses from the query.
10
- * @param parsed
11
- * @param query
12
- */
13
- export const findLimit = (parsed: ParsedQuery, query: string): string => {
14
- const limitFound: RegExpMatchArray = query.match(limitMatch)
15
- if (limitFound) {
16
- parsed['limit'] = limitFound ? parseInt(limitFound[1]) : undefined
17
- return removeFromQuery(limitFound[0], query)
18
- }
19
- return query
20
- }
@@ -1,27 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const mergeJoinMatch: RegExp = /(and)?\s*merge\s+([a-z0-9_-]+\.[a-z0-9_-]+)\s+with\s+([a-z0-9_-]+\.[a-z0-9_-]+)/ig
5
-
6
- export type ParsedMergeJoin = {
7
- propertyA: string
8
- propertyB: string
9
- }
10
-
11
- /**
12
- * Extract merge-join clauses from the query.
13
- * @param parsed
14
- * @param query
15
- */
16
- export const findMergeJoins = (parsed: ParsedQuery, query: string): string => {
17
- const mergeJoinsFound: IterableIterator<RegExpMatchArray> = query.matchAll(mergeJoinMatch)
18
- // @ts-ignore
19
- for (let mergeJoin of mergeJoinsFound) {
20
- parsed['mergeJoins'].push({
21
- propertyA: mergeJoin[2],
22
- propertyB: mergeJoin[3]
23
- })
24
- query = removeFromQuery(mergeJoin[0].trim(), query)
25
- }
26
- return query
27
- }
@@ -1,20 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const offsetMatch: RegExp = /offset\s*(\d+)/i
5
-
6
- export type ParsedOffset = number
7
-
8
- /**
9
- * Extract the offset clauses from the query.
10
- * @param parsed
11
- * @param query
12
- */
13
- export const findOffset = (parsed: ParsedQuery, query: string): string => {
14
- const offsetFound: RegExpMatchArray = query.match(offsetMatch)
15
- if (offsetFound) {
16
- parsed['offset'] = offsetFound ? parseInt(offsetFound[1]) : undefined
17
- return removeFromQuery(offsetFound[0], query)
18
- }
19
- return query
20
- }
@@ -1,31 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const selectClausesMatch: RegExp = /select\s+([a-z0-9=._-]+\s*(as\s+)?([a-z0-9_-]+)?)+\s*(,\s*[a-z0-9=._-]+\s*(as\s*[a-z0-9_-]+)?)*/i
5
- const selectClauseMatch: RegExp = /(select)?\s*,?\s*([a-z0-9=._-]+)\s*(as\s+)?([a-z0-9_-]+)?/ig
6
-
7
- export type ParsedSelect = {
8
- property: string
9
- alias: string | undefined
10
- }
11
-
12
- /**
13
- * Extract select clauses from the query.
14
- * @param parsed
15
- * @param query
16
- */
17
- export const findSelects = (parsed: ParsedQuery, query: string): string => {
18
- const selectsFound: RegExpMatchArray = query.match(selectClausesMatch)
19
- if (selectsFound) {
20
- const selectClausesFound: IterableIterator<RegExpMatchArray> = selectsFound[0].matchAll(selectClauseMatch)
21
- // @ts-ignore
22
- for (let selectClause of selectClausesFound) {
23
- parsed['selectClauses'].push({
24
- property: selectClause[2],
25
- alias: selectClause[4],
26
- })
27
- }
28
- return removeFromQuery(selectsFound[0], query)
29
- }
30
- return query
31
- }
@@ -1,31 +0,0 @@
1
- import { removeFromQuery } from './removeFromQuery'
2
- import { ParsedQuery } from './parseQuery'
3
-
4
- const sortMatch: RegExp = /sort\s+([a-z0-9._-]+\s*(asc|desc)?)+\s*(,\s*[a-z0-9._-]+\s*(asc|desc)?)*/i
5
- const sortRuleMatch: RegExp = /(sort)?\s*,?\s*([a-z0-9._-]+)\s*(asc|desc)?/ig
6
-
7
- export type ParsedSortClause = {
8
- property: string
9
- direction: string | 'asc' | 'desc'
10
- }
11
-
12
- /**
13
- * Extract sort clauses from the query.
14
- * @param parsed
15
- * @param query
16
- */
17
- export const findSortClauses = (parsed: ParsedQuery, query: string): string => {
18
- const sortFound: RegExpMatchArray = query.match(sortMatch)
19
- if (sortFound) {
20
- const sortRulesFound: IterableIterator<RegExpMatchArray> = sortFound[0].matchAll(sortRuleMatch)
21
- // @ts-ignore
22
- for (let sortClause of sortRulesFound) {
23
- parsed['sortClauses'].push({
24
- property: sortClause[2],
25
- direction: sortClause[3] || 'asc',
26
- })
27
- }
28
- return removeFromQuery(sortFound[0], query)
29
- }
30
- return query
31
- }
@@ -1,37 +0,0 @@
1
- import { findUpdateValues } from './findUpdateValues'
2
-
3
- const parse = (query) => {
4
- const parsed = {}
5
- const remaining = findUpdateValues(parsed, query)
6
- return { parsed, remaining }
7
- }
8
-
9
- describe('findUpdateValues', () => {
10
- test('extracts a single assignment', () => {
11
- const { parsed, remaining } = parse("update workouts set reps = 12")
12
- expect(parsed.updateValues).toEqual({ reps: 12 })
13
- expect(remaining).toBe('update workouts')
14
- })
15
-
16
- test('extracts multiple comma-separated assignments', () => {
17
- const { parsed } = parse("set reps = 12, note = 'done'")
18
- expect(parsed.updateValues).toEqual({ reps: 12, note: 'done' })
19
- })
20
-
21
- test('stops before a following where clause', () => {
22
- const { parsed, remaining } = parse("set reps = 12 where date = '2024-06-02'")
23
- expect(parsed.updateValues).toEqual({ reps: 12 })
24
- expect(remaining).toBe("where date = '2024-06-02'")
25
- })
26
-
27
- test('extracts every literal shape', () => {
28
- const { parsed } = parse('set active = true, archived = false, note = null, tags = [1,2,3]')
29
- expect(parsed.updateValues).toEqual({ active: true, archived: false, note: null, tags: [1, 2, 3] })
30
- })
31
-
32
- test('leaves the query untouched, with an empty updateValues, when there is no set clause', () => {
33
- const { parsed, remaining } = parse("read workouts where date = '2024-06-02'")
34
- expect(parsed.updateValues).toEqual({})
35
- expect(remaining).toBe("read workouts where date = '2024-06-02'")
36
- })
37
- })