json-fs-query 0.1.0 → 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 (212) hide show
  1. package/README.md +41 -6
  2. package/browser/jsonFsQuery.js +28271 -0
  3. package/browser/jsonFsQuery.min.js +1 -0
  4. package/dist/data/introspect/create.js +6 -4
  5. package/dist/data/introspect/create.min.js +1 -1
  6. package/dist/data/introspect/drop.js +2 -2
  7. package/dist/data/introspect/drop.min.js +1 -1
  8. package/dist/data/introspect/policies/hasDependents.d.ts +13 -0
  9. package/dist/data/introspect/policies/hasDependents.js +52 -0
  10. package/dist/data/introspect/policies/hasDependents.min.js +1 -0
  11. package/dist/data/introspect/policies/keyGenerate.js +1 -1
  12. package/dist/data/introspect/policies/keyGenerate.min.js +1 -1
  13. package/dist/data/introspect/policies/keyUnique.d.ts +9 -1
  14. package/dist/data/introspect/policies/keyUnique.js +19 -9
  15. package/dist/data/introspect/policies/keyUnique.min.js +1 -1
  16. package/dist/data/queries/deleteEntity.js +36 -15
  17. package/dist/data/queries/deleteEntity.min.js +1 -1
  18. package/dist/data/queries/groupBy.js +22 -22
  19. package/dist/data/queries/groupBy.min.js +1 -1
  20. package/dist/data/queries/insertEntity.js +14 -12
  21. package/dist/data/queries/insertEntity.min.js +1 -1
  22. package/dist/data/queries/readEntity.js +1 -1
  23. package/dist/data/queries/readEntity.min.js +1 -1
  24. package/dist/data/queries/updateEntity.js +68 -42
  25. package/dist/data/queries/updateEntity.min.js +1 -1
  26. package/dist/data/queries/where.js +1 -1
  27. package/dist/data/queries/where.min.js +1 -1
  28. package/dist/data/utilities/computeKeyValue.d.ts +13 -0
  29. package/dist/data/utilities/computeKeyValue.js +26 -0
  30. package/dist/data/utilities/computeKeyValue.min.js +1 -0
  31. package/dist/data/utilities/config.d.ts +28 -0
  32. package/dist/data/utilities/config.js +45 -0
  33. package/dist/data/utilities/config.min.js +1 -0
  34. package/dist/data/utilities/deregisterRecord.js +2 -2
  35. package/dist/data/utilities/deregisterRecord.min.js +1 -1
  36. package/dist/data/utilities/getConditionIndexedList.js +1 -1
  37. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  38. package/dist/data/utilities/getJoinIndexedList.js +2 -2
  39. package/dist/data/utilities/getJoinIndexedList.min.js +1 -1
  40. package/dist/data/utilities/getMatchingIndexes.js +2 -2
  41. package/dist/data/utilities/getMatchingIndexes.min.js +1 -1
  42. package/dist/data/utilities/matchIndexedJoins.js +2 -2
  43. package/dist/data/utilities/matchIndexedJoins.min.js +1 -1
  44. package/dist/data/utilities/reconcileJoin.js +26 -26
  45. package/dist/data/utilities/reconcileJoin.min.js +1 -1
  46. package/dist/data/utilities/reconcileJoins.js +26 -27
  47. package/dist/data/utilities/reconcileJoins.min.js +1 -1
  48. package/dist/data/utilities/registerRecord.js +2 -2
  49. package/dist/data/utilities/registerRecord.min.js +1 -1
  50. package/dist/data/utilities/removeFromIndex.js +2 -2
  51. package/dist/data/utilities/removeFromIndex.min.js +1 -1
  52. package/dist/data/utilities/restrictIndexedList.js +45 -45
  53. package/dist/data/utilities/restrictIndexedList.min.js +1 -1
  54. package/dist/data/utilities/retrieveFile.js +3 -3
  55. package/dist/data/utilities/retrieveFile.min.js +1 -1
  56. package/dist/data/utilities/retrieveIndexes.js +1 -1
  57. package/dist/data/utilities/retrieveIndexes.min.js +1 -1
  58. package/dist/data/utilities/updateIndex.js +2 -2
  59. package/dist/data/utilities/updateIndex.min.js +1 -1
  60. package/dist/data/utilities/useJoinClause.js +4 -4
  61. package/dist/data/utilities/useJoinClause.min.js +1 -1
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +7 -0
  64. package/dist/index.min.js +1 -1
  65. package/package.json +11 -4
  66. package/.browserslistrc +0 -1
  67. package/.nvmrc +0 -1
  68. package/MAIN.md +0 -15
  69. package/babel.config.js +0 -3
  70. package/build-tools.config.json +0 -30
  71. package/gulpfile.mjs +0 -15
  72. package/src/data/introspect/create.test.js +0 -67
  73. package/src/data/introspect/create.ts +0 -29
  74. package/src/data/introspect/definitions/field.test.js +0 -23
  75. package/src/data/introspect/definitions/field.ts +0 -48
  76. package/src/data/introspect/definitions/key.test.js +0 -100
  77. package/src/data/introspect/definitions/key.ts +0 -64
  78. package/src/data/introspect/definitions/keyReference.test.js +0 -8
  79. package/src/data/introspect/definitions/keyReference.ts +0 -23
  80. package/src/data/introspect/definitions/record.ts +0 -42
  81. package/src/data/introspect/describe.test.js +0 -36
  82. package/src/data/introspect/describe.ts +0 -9
  83. package/src/data/introspect/drop.test.js +0 -77
  84. package/src/data/introspect/drop.ts +0 -20
  85. package/src/data/introspect/index.ts +0 -8
  86. package/src/data/introspect/policies/foreignKeyExists.test.js +0 -44
  87. package/src/data/introspect/policies/foreignKeyExists.ts +0 -15
  88. package/src/data/introspect/policies/keyGenerate.ts +0 -11
  89. package/src/data/introspect/policies/keyUnique.ts +0 -11
  90. package/src/data/introspect/policies/typeCheck.test.js +0 -84
  91. package/src/data/introspect/policies/typeCheck.ts +0 -49
  92. package/src/data/introspect/policies/typeEnum.ts +0 -6
  93. package/src/data/introspect/policies/useDefault.ts +0 -6
  94. package/src/data/queries/deleteEntity.test.js +0 -86
  95. package/src/data/queries/deleteEntity.ts +0 -56
  96. package/src/data/queries/groupBy.test.js +0 -135
  97. package/src/data/queries/groupBy.ts +0 -16
  98. package/src/data/queries/insertEntity.test.js +0 -156
  99. package/src/data/queries/insertEntity.ts +0 -113
  100. package/src/data/queries/joinEntity.test.js +0 -109
  101. package/src/data/queries/joinEntity.ts +0 -20
  102. package/src/data/queries/mergeJoins.test.js +0 -174
  103. package/src/data/queries/mergeJoins.ts +0 -13
  104. package/src/data/queries/parser.test.js +0 -343
  105. package/src/data/queries/parser.ts +0 -24
  106. package/src/data/queries/query.test.js +0 -233
  107. package/src/data/queries/query.ts +0 -12
  108. package/src/data/queries/readEntity.test.js +0 -85
  109. package/src/data/queries/readEntity.ts +0 -8
  110. package/src/data/queries/sortBy.test.js +0 -131
  111. package/src/data/queries/sortBy.ts +0 -18
  112. package/src/data/queries/updateEntity.test.js +0 -228
  113. package/src/data/queries/updateEntity.ts +0 -162
  114. package/src/data/queries/where.test.js +0 -129
  115. package/src/data/queries/where.ts +0 -54
  116. package/src/data/utilities/deregisterRecord.test.js +0 -26
  117. package/src/data/utilities/deregisterRecord.ts +0 -24
  118. package/src/data/utilities/getConditionIndexedList.ts +0 -43
  119. package/src/data/utilities/getJoinIndexedList.ts +0 -53
  120. package/src/data/utilities/getMatchingIndexes.ts +0 -21
  121. package/src/data/utilities/matchIndexedJoins.ts +0 -45
  122. package/src/data/utilities/mergeJoin.test.js +0 -102
  123. package/src/data/utilities/mergeJoin.ts +0 -28
  124. package/src/data/utilities/parsers/findCommand.ts +0 -25
  125. package/src/data/utilities/parsers/findConditions.test.js +0 -38
  126. package/src/data/utilities/parsers/findConditions.ts +0 -32
  127. package/src/data/utilities/parsers/findGroupBy.ts +0 -20
  128. package/src/data/utilities/parsers/findInsertValues.test.js +0 -26
  129. package/src/data/utilities/parsers/findInsertValues.ts +0 -32
  130. package/src/data/utilities/parsers/findJoinClauses.ts +0 -29
  131. package/src/data/utilities/parsers/findJoinEntity.ts +0 -20
  132. package/src/data/utilities/parsers/findLimit.ts +0 -20
  133. package/src/data/utilities/parsers/findMergeJoins.ts +0 -27
  134. package/src/data/utilities/parsers/findOffset.ts +0 -20
  135. package/src/data/utilities/parsers/findSelects.ts +0 -31
  136. package/src/data/utilities/parsers/findSortClauses.ts +0 -31
  137. package/src/data/utilities/parsers/findUpdateValues.test.js +0 -37
  138. package/src/data/utilities/parsers/findUpdateValues.ts +0 -32
  139. package/src/data/utilities/parsers/isEntityProperty.ts +0 -1
  140. package/src/data/utilities/parsers/parseLiteralValue.test.js +0 -41
  141. package/src/data/utilities/parsers/parseLiteralValue.ts +0 -29
  142. package/src/data/utilities/parsers/parseQuery.ts +0 -73
  143. package/src/data/utilities/parsers/removeFromQuery.ts +0 -1
  144. package/src/data/utilities/parsers/splitEntityProperty.test.js +0 -8
  145. package/src/data/utilities/parsers/splitEntityProperty.ts +0 -17
  146. package/src/data/utilities/parsers/splitQueries.test.js +0 -33
  147. package/src/data/utilities/parsers/splitQueries.ts +0 -4
  148. package/src/data/utilities/reconcileJoin.test.js +0 -38
  149. package/src/data/utilities/reconcileJoin.ts +0 -23
  150. package/src/data/utilities/reconcileJoins.test.js +0 -160
  151. package/src/data/utilities/reconcileJoins.ts +0 -15
  152. package/src/data/utilities/registerRecord.test.js +0 -44
  153. package/src/data/utilities/registerRecord.ts +0 -44
  154. package/src/data/utilities/removeFromIndex.test.js +0 -44
  155. package/src/data/utilities/removeFromIndex.ts +0 -34
  156. package/src/data/utilities/restrictIndexedList.ts +0 -38
  157. package/src/data/utilities/retrieveFile.test.js +0 -49
  158. package/src/data/utilities/retrieveFile.ts +0 -19
  159. package/src/data/utilities/retrieveIndexes.ts +0 -17
  160. package/src/data/utilities/retrieveRecord.ts +0 -3
  161. package/src/data/utilities/retrieveRecords.test.js +0 -223
  162. package/src/data/utilities/retrieveRecords.ts +0 -16
  163. package/src/data/utilities/runQuery.test.js +0 -88
  164. package/src/data/utilities/runQuery.ts +0 -75
  165. package/src/data/utilities/updateIndex.test.js +0 -44
  166. package/src/data/utilities/updateIndex.ts +0 -45
  167. package/src/data/utilities/useJoinClause.test.js +0 -94
  168. package/src/data/utilities/useJoinClause.ts +0 -44
  169. package/src/global.d.ts +0 -1
  170. package/src/index.test.js +0 -52
  171. package/src/index.ts +0 -17
  172. package/test-data/__RECORDS.json +0 -32
  173. package/test-data/__indexes/exercise_muscle/fk_exercise_id.json +0 -14
  174. package/test-data/__indexes/exercise_muscle/fk_muscle_id.json +0 -14
  175. package/test-data/__indexes/exercise_muscle/pk__id.json +0 -14
  176. package/test-data/__indexes/exercises/pk__id.json +0 -14
  177. package/test-data/__indexes/muscles/pk__id.json +0 -58
  178. package/test-data/__indexes/workouts/fk_exercise_id.json +0 -23
  179. package/test-data/__indexes/workouts/index_date.json +0 -18
  180. package/test-data/__indexes/workouts/pk__id.json +0 -26
  181. package/test-data/copyDatabase.ts +0 -64
  182. package/test-data/exercise_muscle/bench_press_pectorals.json +0 -6
  183. package/test-data/exercise_muscle/deadlift_hamstrings.json +0 -6
  184. package/test-data/exercise_muscle/squat_quadriceps.json +0 -6
  185. package/test-data/exercise_muscle.json +0 -69
  186. package/test-data/exercises/bench_press.json +0 -5
  187. package/test-data/exercises/deadlift.json +0 -5
  188. package/test-data/exercises/squat.json +0 -5
  189. package/test-data/exercises.json +0 -34
  190. package/test-data/muscles/abdominal.json +0 -6
  191. package/test-data/muscles/biceps.json +0 -6
  192. package/test-data/muscles/calves.json +0 -6
  193. package/test-data/muscles/deltoids.json +0 -6
  194. package/test-data/muscles/erector_spinae.json +0 -6
  195. package/test-data/muscles/forearms.json +0 -6
  196. package/test-data/muscles/gluteus_maximus.json +0 -6
  197. package/test-data/muscles/hamstrings.json +0 -6
  198. package/test-data/muscles/latissimus_dorsi.json +0 -6
  199. package/test-data/muscles/obliques.json +0 -6
  200. package/test-data/muscles/pectorals.json +0 -6
  201. package/test-data/muscles/quadriceps.json +0 -6
  202. package/test-data/muscles/trapezius.json +0 -6
  203. package/test-data/muscles/triceps.json +0 -6
  204. package/test-data/muscles.json +0 -50
  205. package/test-data/workouts/2024-06-02-001.json +0 -10
  206. package/test-data/workouts/2024-06-02-002.json +0 -10
  207. package/test-data/workouts/2024-06-02-003.json +0 -10
  208. package/test-data/workouts/2024-06-05-001.json +0 -10
  209. package/test-data/workouts/2024-06-05-002.json +0 -10
  210. package/test-data/workouts/2024-06-05-003.json +0 -10
  211. package/test-data/workouts.json +0 -84
  212. package/tsconfig.json +0 -15
@@ -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 setClauseMatch: RegExp = new RegExp(`(set)\\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 ParsedUpdateValues = { [field: string]: any }
10
-
11
- /**
12
- * Extract an update's "set field = value, field2 = value2" clause from the query. Uses a two-pass
13
- * match, unlike the other parsers here: the set clause's own boundary is found first (so it can
14
- * be removed from the query as a whole, and so the comma-separated list doesn't get confused with
15
- * anything that follows, like a where clause), then each individual assignment is parsed out of
16
- * that captured substring.
17
- * @param parsed
18
- * @param query
19
- */
20
- export const findUpdateValues = (parsed: ParsedQuery, query: string): string => {
21
- const clauseFound: RegExpMatchArray = query.match(setClauseMatch)
22
- parsed['updateValues'] = {}
23
- if (!clauseFound) {
24
- return query
25
- }
26
- const assignmentsFound: IterableIterator<RegExpMatchArray> = clauseFound[2].matchAll(assignmentMatch)
27
- // @ts-ignore
28
- for (const assignment of assignmentsFound) {
29
- parsed['updateValues'][assignment[1]] = parseLiteralValue(assignment, 3)
30
- }
31
- return removeFromQuery(clauseFound[0], query)
32
- }
@@ -1 +0,0 @@
1
- export const isEntityProperty = (property: string): boolean => /^[a-z0-9_-]+\.([a-z0-9_-]+)$/i.test(property)
@@ -1,41 +0,0 @@
1
- import { parseLiteralValue } from './parseLiteralValue'
2
-
3
- describe('parseLiteralValue', () => {
4
- const groupMatch = (regex, str) => str.match(regex)
5
-
6
- test('extracts a quoted string', () => {
7
- const regex = /(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
8
- const match = groupMatch(regex, "'foo'")
9
- expect(parseLiteralValue(match, 2)).toBe('foo')
10
- })
11
-
12
- test('extracts a number', () => {
13
- const regex = /(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
14
- const match = groupMatch(regex, '42')
15
- expect(parseLiteralValue(match, 2)).toBe(42)
16
- })
17
-
18
- test('extracts an array', () => {
19
- const regex = /(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
20
- const match = groupMatch(regex, '[1,2,3]')
21
- expect(parseLiteralValue(match, 2)).toEqual([1, 2, 3])
22
- })
23
-
24
- test('extracts null', () => {
25
- const regex = /(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
26
- const match = groupMatch(regex, 'null')
27
- expect(parseLiteralValue(match, 2)).toBeNull()
28
- })
29
-
30
- test('extracts true/false', () => {
31
- const regex = /(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
32
- expect(parseLiteralValue(groupMatch(regex, 'true'), 2)).toBe(true)
33
- expect(parseLiteralValue(groupMatch(regex, 'false'), 2)).toBe(false)
34
- })
35
-
36
- test('honors a different baseIndex for a differently-shaped parent regex', () => {
37
- const regex = /([a-z]+)\s*=\s*(["'](.*)['"]|([0-9]+)|(\[.*])|(null)|(true)|(false))/
38
- const match = groupMatch(regex, 'reps=10')
39
- expect(parseLiteralValue(match, 3)).toBe(10)
40
- })
41
- })
@@ -1,29 +0,0 @@
1
- export type LiteralValue = string | number | boolean | null | any[]
2
-
3
- /**
4
- * Several parsers (findConditions, findInsertValues, findUpdateValues) capture a query-string
5
- * literal into one of six consecutive alternation groups depending on its shape - quoted string,
6
- * number, array, null, true, false - since a single regex can't otherwise tell them apart. Given
7
- * the match and the index of the first of those six groups (which shifts depending on how many
8
- * groups come before it in the parent regex), return the literal with its real JS type.
9
- * @param match
10
- * @param baseIndex
11
- */
12
- export const parseLiteralValue = (match: RegExpMatchArray, baseIndex: number): LiteralValue => {
13
- if (typeof match[baseIndex] !== 'undefined') {
14
- return match[baseIndex]
15
- }
16
- if (typeof match[baseIndex + 1] !== 'undefined') {
17
- return Number(match[baseIndex + 1])
18
- }
19
- if (typeof match[baseIndex + 2] !== 'undefined') {
20
- return JSON.parse(match[baseIndex + 2])
21
- }
22
- if (typeof match[baseIndex + 3] !== 'undefined') {
23
- return null
24
- }
25
- if (typeof match[baseIndex + 4] !== 'undefined') {
26
- return true
27
- }
28
- return false
29
- }
@@ -1,73 +0,0 @@
1
- import siFunciona from 'si-funciona'
2
- import { findCommand, ParsedCommand, ParsedEntity } from './findCommand'
3
- import { findInsertValues, ParsedInsertRow } from './findInsertValues'
4
- import { findUpdateValues, ParsedUpdateValues } from './findUpdateValues'
5
- import { findJoinEntity, ParsedJoinEntity } from './findJoinEntity'
6
- import { findSelects, ParsedSelect } from './findSelects'
7
- import { findConditions, ParsedCondition } from './findConditions'
8
- import { findJoinClauses, ParsedJoinClause } from './findJoinClauses'
9
- import { findMergeJoins, ParsedMergeJoin } from './findMergeJoins'
10
- import { findSortClauses, ParsedSortClause } from './findSortClauses'
11
- import { findGroupBy, ParsedGroupBy } from './findGroupBy'
12
- import { findLimit, ParsedLimit } from './findLimit'
13
- import { findOffset, ParsedOffset } from './findOffset'
14
-
15
- export type ParsedQuery = {
16
- command: ParsedCommand | undefined
17
- entity: ParsedEntity | undefined
18
- joinEntity: ParsedJoinEntity | undefined
19
- selectClauses: ParsedSelect[]
20
- insertValues: ParsedInsertRow[]
21
- updateValues: ParsedUpdateValues
22
- conditions: ParsedCondition[]
23
- joinClauses: ParsedJoinClause[]
24
- mergeJoins: ParsedMergeJoin[]
25
- sortClauses: ParsedSortClause[]
26
- groupBy: ParsedGroupBy | undefined
27
- limit: ParsedLimit | undefined
28
- offset: ParsedOffset | undefined
29
- }
30
-
31
- /**
32
- * Break a query down into its components.
33
- * @param query
34
- */
35
- export const parseQuery = (query: string): ParsedQuery => {
36
- let parsedQuery: ParsedQuery = {
37
- command: undefined,
38
- entity: undefined,
39
- joinEntity: undefined,
40
- selectClauses: [],
41
- insertValues: [],
42
- updateValues: {},
43
- conditions: [],
44
- joinClauses: [],
45
- mergeJoins: [],
46
- sortClauses: [],
47
- groupBy: undefined,
48
- limit: undefined,
49
- offset: undefined,
50
- }
51
-
52
- const { curry, pipe } = siFunciona
53
-
54
- query = pipe(
55
- curry(findCommand)(parsedQuery),
56
- curry(findInsertValues)(parsedQuery),
57
- curry(findUpdateValues)(parsedQuery),
58
- curry(findJoinEntity)(parsedQuery),
59
- curry(findSelects)(parsedQuery),
60
- curry(findConditions)(parsedQuery),
61
- curry(findJoinClauses)(parsedQuery),
62
- curry(findMergeJoins)(parsedQuery),
63
- curry(findSortClauses)(parsedQuery),
64
- curry(findGroupBy)(parsedQuery),
65
- curry(findLimit)(parsedQuery),
66
- curry(findOffset)(parsedQuery)
67
- )(query)
68
-
69
- if (query) {
70
- throw new Error(`Unrecognized query value: ${query}`)
71
- }
72
- return parsedQuery
73
- }
@@ -1 +0,0 @@
1
- export const removeFromQuery = (substring: string, query: string): string => query.replace(substring, '').trim()
@@ -1,8 +0,0 @@
1
- import { splitEntityProperty } from './splitEntityProperty'
2
-
3
- describe('splitEntityProperty', () => {
4
- test('can parse entity property', () => {
5
- const result = splitEntityProperty('workouts.exercise_id')
6
- expect(result).toEqual({ entity: 'workouts', property: 'exercise_id' })
7
- })
8
- })
@@ -1,17 +0,0 @@
1
- const entityMatch = /^[a-z0-9_-]+/i
2
- const propertyMatch = /\.([a-z0-9_-]+)$/i
3
-
4
- export const splitEntityProperty = entityProp => {
5
- const entityFound = entityProp.match(entityMatch)
6
- if (!entityFound) {
7
- throw new Error(`Unable to use property: ${entityProp}`)
8
- }
9
- const propFound = entityProp.match(propertyMatch)
10
- if (!propFound) {
11
- throw new Error(`Unable to use property: ${entityProp}`)
12
- }
13
- return {
14
- entity: entityFound[0],
15
- property: propFound[1]
16
- }
17
- }
@@ -1,33 +0,0 @@
1
- import { splitQueries } from './splitQueries'
2
-
3
- const sampleQueries = [
4
- 'read workouts where date = \'2024-06-02\'',
5
- 'read workouts.muscles'
6
- + ' on workouts.exercise_id = exercises._id'
7
- + ' and on exercises._id = exercise_muscle.exercise_id'
8
- + ' and on exercise_muscle.muscle_id = muscles._id'
9
- + ' where muscles.alias = \'chest\'',
10
- 'read workouts.muscles'
11
- + ' on workouts.exercise_id = exercises._id'
12
- + ' and on exercises._id = exercise_muscle.exercise_id'
13
- + ' and on exercise_muscle.muscle_id = muscles._id'
14
- + ' merge workouts.exercise_id with exercises._id'
15
- + ' merge exercise_muscle.muscle_id with muscles._id'
16
- + ' where muscles.alias = \'chest\'',
17
- 'read workouts sort date desc, order',
18
- 'read workouts group by date',
19
- 'read workouts.exercises'
20
- + ' select exercises.name as exercise, workouts.sets as sets, reps'
21
- + ' on workouts.exercise_id = exercises._id'
22
- + ' merge workouts.exercise_id with exercises._id'
23
- + ' limit 2'
24
- + ' offset 1'
25
- ]
26
-
27
- describe('splitQueries', () => {
28
- test('can identify all queries', () => {
29
- const queries = sampleQueries.reduce((concatQueries, query) => concatQueries = `${concatQueries} ${query}`, '')
30
- const result = splitQueries(queries)
31
- expect(result).toEqual(sampleQueries)
32
- })
33
- })
@@ -1,4 +0,0 @@
1
- const queryMatch = /\s*(?=(?:delete|insert|read|update)\s+[a-z0-9._-]+)\s*/i
2
-
3
- export const splitQueries = (queries: string = ''): string[] =>
4
- queries.split(queryMatch).filter((query) => query.length > 0)
@@ -1,38 +0,0 @@
1
- import { reconcileJoin } from './reconcileJoin'
2
-
3
- describe('reconcileJoin', () => {
4
- test('will apply found join with changes', () => {
5
- const dataSet = {
6
- workouts: [
7
- {
8
- _id: 1,
9
- exercise_id: 1,
10
- weight_effort: '115lbs',
11
- reps: 10,
12
- sets: 3,
13
- note: '',
14
- date: '2024-06-02',
15
- muscles: [{ _id: 11, name: 'Pectorals', alias: 'chest', image: '' }]
16
- }
17
- ],
18
- muscles: [
19
- {
20
- _id: 11,
21
- name: 'Pectorals',
22
- alias: 'chest',
23
- image: '',
24
- 'exercise_muscle._id': 1,
25
- 'exercise_muscle.exercise_id': 1,
26
- 'exercise_muscle.muscle_rank': 100
27
- },
28
- { _id: 14, name: 'Triceps', alias: '', image: '' }
29
- ]
30
- }
31
- const entity = 'workouts'
32
- const index = 0
33
- const joinEntity = 'muscles'
34
- const joinProperty = '_id'
35
- const result = reconcileJoin(dataSet, entity, index, joinEntity, joinProperty)
36
- expect(result[entity][index][joinEntity][0]).toEqual(dataSet[joinEntity][0])
37
- })
38
- })
@@ -1,23 +0,0 @@
1
- import { where } from '../queries/where'
2
-
3
- export const reconcileJoin = (dataSet, entityName, entityKey, joinEntity, joinProp) => {
4
- const entity = dataSet[entityName][entityKey]
5
- if (entity.hasOwnProperty(joinEntity) && Array.isArray(entity[joinEntity])) {
6
- entity[joinEntity].forEach(
7
- (mergedEntity, k) => {
8
- const matchedEntity = where(
9
- dataSet[joinEntity],
10
- {
11
- property: joinProp,
12
- comparator: '=',
13
- value: mergedEntity[joinProp]
14
- }
15
- )
16
- if (matchedEntity.length) {
17
- dataSet[entityName][entityKey][joinEntity][k] = matchedEntity[0]
18
- }
19
- }
20
- )
21
- }
22
- return dataSet
23
- }
@@ -1,160 +0,0 @@
1
- import { reconcileJoins } from './reconcileJoins'
2
-
3
- describe('reconcileJoins', () => {
4
- test('reconciles several joins', () => {
5
- const propertyA = 'muscles._id'
6
- const propertyB = 'exercise_muscle.muscle_id'
7
- const dataSet = {
8
- workouts: [
9
- {
10
- _id: 1,
11
- exercise_id: 1,
12
- weight_effort: '115lbs',
13
- reps: 10,
14
- sets: 3,
15
- note: '',
16
- date: '2024-06-02',
17
- muscles: [{ _id: 11, name: 'Pectorals', alias: 'chest', image: '' }]
18
- },
19
- {
20
- _id: 2,
21
- exercise_id: 2,
22
- weight_effort: '155lbs',
23
- reps: 10,
24
- sets: 3,
25
- note: '',
26
- date: '2024-06-02',
27
- muscles: [{ _id: 8, name: 'Hamstrings', alias: 'abs', image: '' }]
28
- },
29
- {
30
- _id: 3,
31
- exercise_id: 3,
32
- weight_effort: '155lbs',
33
- reps: 10,
34
- sets: 3,
35
- note: '',
36
- date: '2024-06-02',
37
- muscles: [{ _id: 12, name: 'Quadriceps', alias: 'quads', image: '' }]
38
- }
39
- ],
40
- muscles: [
41
- {
42
- _id: 1,
43
- name: 'Abdominal',
44
- alias: 'abs',
45
- image: '../img/abdominals.jpg'
46
- },
47
- { _id: 2, name: 'Biceps', alias: '', image: '' },
48
- { _id: 3, name: 'Calves', alias: '', image: '' },
49
- { _id: 4, name: 'Deltoids', alias: 'shoulders', image: '' },
50
- {
51
- _id: 5,
52
- name: 'Erector Spinae',
53
- alias: 'mid back, along spine',
54
- image: ''
55
- },
56
- { _id: 6, name: 'Forearms', alias: 'abs', image: '' },
57
- { _id: 7, name: 'Gluteus Maximus', alias: 'abs', image: '' },
58
- {
59
- _id: 8,
60
- name: 'Hamstrings',
61
- alias: 'abs',
62
- image: '',
63
- 'exercise_muscle._id': 2,
64
- 'exercise_muscle.exercise_id': 2,
65
- 'exercise_muscle.muscle_rank': 100
66
- },
67
- {
68
- _id: 9,
69
- name: 'Latissimus Dorsi',
70
- alias: 'outer lower back',
71
- image: ''
72
- },
73
- { _id: 10, name: 'Obliques', alias: 'outer abs', image: '' },
74
- {
75
- _id: 11,
76
- name: 'Pectorals',
77
- alias: 'chest',
78
- image: '',
79
- 'exercise_muscle._id': 1,
80
- 'exercise_muscle.exercise_id': 1,
81
- 'exercise_muscle.muscle_rank': 100
82
- },
83
- {
84
- _id: 12,
85
- name: 'Quadriceps',
86
- alias: 'quads',
87
- image: '',
88
- 'exercise_muscle._id': 3,
89
- 'exercise_muscle.exercise_id': 3,
90
- 'exercise_muscle.muscle_rank': 100
91
- },
92
- { _id: 13, name: 'Trapezius', alias: 'upper back', image: '' },
93
- { _id: 14, name: 'Triceps', alias: '', image: '' }
94
- ]
95
- }
96
- const result = reconcileJoins(propertyA, propertyB, dataSet)
97
- expect(result['workouts']).toEqual([
98
- {
99
- _id: 1,
100
- exercise_id: 1,
101
- weight_effort: '115lbs',
102
- reps: 10,
103
- sets: 3,
104
- note: '',
105
- date: '2024-06-02',
106
- muscles: [
107
- {
108
- _id: 11,
109
- name: 'Pectorals',
110
- alias: 'chest',
111
- image: '',
112
- 'exercise_muscle._id': 1,
113
- 'exercise_muscle.exercise_id': 1,
114
- 'exercise_muscle.muscle_rank': 100
115
- }
116
- ]
117
- },
118
- {
119
- _id: 2,
120
- exercise_id: 2,
121
- weight_effort: '155lbs',
122
- reps: 10,
123
- sets: 3,
124
- note: '',
125
- date: '2024-06-02',
126
- muscles: [
127
- {
128
- _id: 8,
129
- name: 'Hamstrings',
130
- alias: 'abs',
131
- image: '',
132
- 'exercise_muscle._id': 2,
133
- 'exercise_muscle.exercise_id': 2,
134
- 'exercise_muscle.muscle_rank': 100
135
- }
136
- ]
137
- },
138
- {
139
- _id: 3,
140
- exercise_id: 3,
141
- weight_effort: '155lbs',
142
- reps: 10,
143
- sets: 3,
144
- note: '',
145
- date: '2024-06-02',
146
- muscles: [
147
- {
148
- _id: 12,
149
- name: 'Quadriceps',
150
- alias: 'quads',
151
- image: '',
152
- 'exercise_muscle._id': 3,
153
- 'exercise_muscle.exercise_id': 3,
154
- 'exercise_muscle.muscle_rank': 100
155
- }
156
- ]
157
- }
158
- ])
159
- })
160
- })
@@ -1,15 +0,0 @@
1
- import { splitEntityProperty } from './parsers/splitEntityProperty'
2
- import { reconcileJoin } from './reconcileJoin'
3
-
4
- export const reconcileJoins = (propertyA, propertyB, dataSet) => {
5
- const { entity: entityA, property: propA } = splitEntityProperty(propertyA)
6
- const { entity: entityB, property: propB } = splitEntityProperty(propertyB)
7
- for (let entityName in dataSet) {
8
- for (let entityKey in dataSet[entityName]) {
9
- const entity = dataSet[entityName][entityKey]
10
- dataSet = reconcileJoin(dataSet, entityName, entityKey, entityA, propA)
11
- dataSet = reconcileJoin(dataSet, entityName, entityKey, entityB, propB)
12
- }
13
- }
14
- return dataSet
15
- }
@@ -1,44 +0,0 @@
1
- import { registerRecord } from './registerRecord'
2
- import { testHelpers } from 'js-build-tools/testHelpers'
3
-
4
- const { readFile } = require('fs/promises')
5
-
6
- const databasePath = 'register-record-database/'
7
- const gulpConfig = testHelpers.gulpConfig
8
- gulpConfig.set('databasePath', databasePath)
9
- testHelpers.setDefaults(databasePath)
10
-
11
- beforeEach(testHelpers.beforeEach)
12
-
13
- afterEach(testHelpers.afterEach)
14
-
15
- describe('registerRecord', () => {
16
- test('creates a fresh registry the first time a record is registered', async () => {
17
- const result = await registerRecord('foo')
18
- expect(result).toEqual({
19
- path: '',
20
- definition: [
21
- { name: 'path', type: 'string', optional: false, autoGenerate: false },
22
- { name: 'definition', type: 'object', optional: false, autoGenerate: false },
23
- { name: 'keys', type: 'array', optional: false, autoGenerate: false },
24
- { name: 'entries', type: 'array', optional: false, autoGenerate: false }
25
- ],
26
- keys: [],
27
- entries: ['foo.json']
28
- })
29
- const onDisk = JSON.parse(await readFile(`${databasePath}__RECORDS.json`, 'utf8'))
30
- expect(onDisk).toEqual(result)
31
- })
32
-
33
- test('appends onto an existing registry without disturbing other entries', async () => {
34
- await registerRecord('foo')
35
- const result = await registerRecord('bar')
36
- expect(result.entries).toEqual(['foo.json', 'bar.json'])
37
- })
38
-
39
- test('registering the same record twice does not duplicate its entry', async () => {
40
- await registerRecord('foo')
41
- const result = await registerRecord('foo')
42
- expect(result.entries).toEqual(['foo.json'])
43
- })
44
- })
@@ -1,44 +0,0 @@
1
- import { recordDefinition } from '../introspect/definitions/record'
2
-
3
- const gulpConfig = require('js-build-tools/gulp.config')
4
- const { readFile, writeFile } = require('fs/promises')
5
-
6
- /**
7
- * __RECORDS is itself an ordinary record - path/definition/keys/entries - whose entries are the
8
- * filenames of every other record that has been created. This is the schema it's given the first
9
- * time a record is registered and no __RECORDS.json exists yet, matching what a hand-authored
10
- * database (see test-data/__RECORDS.json) already expects to find.
11
- */
12
- const defaultRegistry = (): recordDefinition => ({
13
- path: '',
14
- definition: [
15
- { name: 'path', type: 'string', optional: false, autoGenerate: false },
16
- { name: 'definition', type: 'object', optional: false, autoGenerate: false },
17
- { name: 'keys', type: 'array', optional: false, autoGenerate: false },
18
- { name: 'entries', type: 'array', optional: false, autoGenerate: false }
19
- ],
20
- keys: [],
21
- entries: []
22
- })
23
-
24
- /**
25
- * Add a record's filename to the __RECORDS registry, creating the registry file the first time
26
- * a record is created if it doesn't already exist.
27
- * @param recordName
28
- */
29
- export const registerRecord = async (recordName: string): Promise<recordDefinition> => {
30
- const databasePath = gulpConfig.get('databasePath', 'database/')
31
- const registryPath = `${databasePath}__RECORDS.json`
32
- let registry: recordDefinition
33
- try {
34
- registry = JSON.parse(await readFile(registryPath, 'utf8'))
35
- } catch (err) {
36
- registry = defaultRegistry()
37
- }
38
- const fileName = `${recordName}.json`
39
- if (!registry.entries.includes(fileName)) {
40
- registry.entries.push(fileName)
41
- }
42
- await writeFile(registryPath, JSON.stringify(registry, null, 2))
43
- return registry
44
- }
@@ -1,44 +0,0 @@
1
- import { updateIndex } from './updateIndex'
2
- import { removeFromIndex } from './removeFromIndex'
3
- import { testHelpers } from 'js-build-tools/testHelpers'
4
-
5
- const { readFile } = require('fs/promises')
6
-
7
- const databasePath = 'remove-from-index-database/'
8
- const gulpConfig = testHelpers.gulpConfig
9
- gulpConfig.set('databasePath', databasePath)
10
- testHelpers.setDefaults(databasePath)
11
-
12
- beforeEach(testHelpers.beforeEach)
13
-
14
- afterEach(testHelpers.afterEach)
15
-
16
- describe('removeFromIndex', () => {
17
- test('does nothing for a key with no lookup', async () => {
18
- const result = await removeFromIndex('foo', { type: 'multi', fields: ['a', 'b'], lookup: '' }, 'x', 'x.json')
19
- expect(result).toBeNull()
20
- })
21
-
22
- test('does nothing when the index file does not exist yet', async () => {
23
- const key = { type: 'primary', fields: ['_id'], lookup: 'pk__id.json' }
24
- const result = await removeFromIndex('foo', key, 1, '1.json')
25
- expect(result).toBeNull()
26
- })
27
-
28
- test('removes a file from its value, keeping other files on that value', async () => {
29
- const key = { type: 'index', fields: ['date'], lookup: 'index_date.json' }
30
- await updateIndex('foo', key, '2024-06-02', '1.json')
31
- await updateIndex('foo', key, '2024-06-02', '2.json')
32
- const result = await removeFromIndex('foo', key, '2024-06-02', '1.json')
33
- expect(result).toEqual([{ value: '2024-06-02', record: ['2.json'] }])
34
- })
35
-
36
- test('drops the whole value once its last file is removed', async () => {
37
- const key = { type: 'primary', fields: ['_id'], lookup: 'pk__id.json' }
38
- await updateIndex('foo', key, 1, '1.json')
39
- const result = await removeFromIndex('foo', key, 1, '1.json')
40
- expect(result).toEqual([])
41
- const onDisk = JSON.parse(await readFile(`${databasePath}__indexes/foo/pk__id.json`, 'utf8'))
42
- expect(onDisk).toEqual([])
43
- })
44
- })
@@ -1,34 +0,0 @@
1
- import { keyDefinition } from '../introspect/definitions/key'
2
- import { recordPath } from '../introspect/definitions/record'
3
- import { indexEntry } from './updateIndex'
4
-
5
- const gulpConfig = require('js-build-tools/gulp.config')
6
- const { readFile, writeFile } = require('fs/promises')
7
-
8
- /**
9
- * Remove a single entry file from the index that backs one of a record's keys, dropping a value
10
- * entirely once its last file is removed. A key with no lookup, or an index file that doesn't
11
- * exist yet, is left untouched.
12
- * @param path
13
- * @param key
14
- * @param value
15
- * @param fileName
16
- */
17
- export const removeFromIndex = async (path: recordPath = '', key: keyDefinition = null, value: any = undefined, fileName: string = ''): Promise<indexEntry[] | null> => {
18
- if (!key || !key.lookup) {
19
- return null
20
- }
21
- const databasePath = gulpConfig.get('databasePath', 'database/')
22
- const indexPath = `${databasePath}__indexes/${path}/${key.lookup}`
23
- let index: indexEntry[] = []
24
- try {
25
- index = JSON.parse(await readFile(indexPath, 'utf8'))
26
- } catch (err) {
27
- return null
28
- }
29
- index = index
30
- .map(entry => entry.value == value ? { value: entry.value, record: entry.record.filter(record => record !== fileName) } : entry)
31
- .filter(entry => entry.record.length)
32
- await writeFile(indexPath, JSON.stringify(index, null, 2))
33
- return index
34
- }