json-fs-query 0.1.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.
- package/.browserslistrc +1 -0
- package/.nvmrc +1 -0
- package/LICENSE +674 -0
- package/MAIN.md +15 -0
- package/README.md +63 -0
- package/babel.config.js +3 -0
- package/build-tools.config.json +30 -0
- package/dist/data/introspect/create.d.ts +11 -0
- package/dist/data/introspect/create.js +45 -0
- package/dist/data/introspect/create.min.js +1 -0
- package/dist/data/introspect/definitions/field.d.ts +28 -0
- package/dist/data/introspect/definitions/field.js +36 -0
- package/dist/data/introspect/definitions/field.min.js +1 -0
- package/dist/data/introspect/definitions/key.d.ts +26 -0
- package/dist/data/introspect/definitions/key.js +53 -0
- package/dist/data/introspect/definitions/key.min.js +1 -0
- package/dist/data/introspect/definitions/keyReference.d.ts +18 -0
- package/dist/data/introspect/definitions/keyReference.js +20 -0
- package/dist/data/introspect/definitions/keyReference.min.js +1 -0
- package/dist/data/introspect/definitions/record.d.ts +26 -0
- package/dist/data/introspect/definitions/record.js +32 -0
- package/dist/data/introspect/definitions/record.min.js +1 -0
- package/dist/data/introspect/describe.d.ts +2 -0
- package/dist/data/introspect/describe.js +15 -0
- package/dist/data/introspect/describe.min.js +1 -0
- package/dist/data/introspect/drop.d.ts +2 -0
- package/dist/data/introspect/drop.js +37 -0
- package/dist/data/introspect/drop.min.js +1 -0
- package/dist/data/introspect/index.d.ts +8 -0
- package/dist/data/introspect/index.js +30 -0
- package/dist/data/introspect/index.min.js +1 -0
- package/dist/data/introspect/policies/foreignKeyExists.d.ts +9 -0
- package/dist/data/introspect/policies/foreignKeyExists.js +25 -0
- package/dist/data/introspect/policies/foreignKeyExists.min.js +1 -0
- package/dist/data/introspect/policies/keyGenerate.d.ts +2 -0
- package/dist/data/introspect/policies/keyGenerate.js +17 -0
- package/dist/data/introspect/policies/keyGenerate.min.js +1 -0
- package/dist/data/introspect/policies/keyUnique.d.ts +2 -0
- package/dist/data/introspect/policies/keyUnique.js +21 -0
- package/dist/data/introspect/policies/keyUnique.min.js +1 -0
- package/dist/data/introspect/policies/typeCheck.d.ts +12 -0
- package/dist/data/introspect/policies/typeCheck.js +57 -0
- package/dist/data/introspect/policies/typeCheck.min.js +1 -0
- package/dist/data/introspect/policies/typeEnum.d.ts +2 -0
- package/dist/data/introspect/policies/typeEnum.js +14 -0
- package/dist/data/introspect/policies/typeEnum.min.js +1 -0
- package/dist/data/introspect/policies/useDefault.d.ts +2 -0
- package/dist/data/introspect/policies/useDefault.js +13 -0
- package/dist/data/introspect/policies/useDefault.min.js +1 -0
- package/dist/data/queries/deleteEntity.d.ts +2 -0
- package/dist/data/queries/deleteEntity.js +79 -0
- package/dist/data/queries/deleteEntity.min.js +1 -0
- package/dist/data/queries/groupBy.d.ts +2 -0
- package/dist/data/queries/groupBy.js +22 -0
- package/dist/data/queries/groupBy.min.js +1 -0
- package/dist/data/queries/insertEntity.d.ts +2 -0
- package/dist/data/queries/insertEntity.js +115 -0
- package/dist/data/queries/insertEntity.min.js +1 -0
- package/dist/data/queries/joinEntity.d.ts +2 -0
- package/dist/data/queries/joinEntity.js +27 -0
- package/dist/data/queries/joinEntity.min.js +1 -0
- package/dist/data/queries/mergeJoins.d.ts +2 -0
- package/dist/data/queries/mergeJoins.js +19 -0
- package/dist/data/queries/mergeJoins.min.js +1 -0
- package/dist/data/queries/parser.d.ts +2 -0
- package/dist/data/queries/parser.js +30 -0
- package/dist/data/queries/parser.min.js +1 -0
- package/dist/data/queries/query.d.ts +2 -0
- package/dist/data/queries/query.js +18 -0
- package/dist/data/queries/query.min.js +1 -0
- package/dist/data/queries/readEntity.d.ts +2 -0
- package/dist/data/queries/readEntity.js +14 -0
- package/dist/data/queries/readEntity.min.js +1 -0
- package/dist/data/queries/sortBy.d.ts +2 -0
- package/dist/data/queries/sortBy.js +25 -0
- package/dist/data/queries/sortBy.min.js +1 -0
- package/dist/data/queries/updateEntity.d.ts +2 -0
- package/dist/data/queries/updateEntity.js +164 -0
- package/dist/data/queries/updateEntity.min.js +1 -0
- package/dist/data/queries/where.d.ts +7 -0
- package/dist/data/queries/where.js +56 -0
- package/dist/data/queries/where.min.js +1 -0
- package/dist/data/utilities/deregisterRecord.d.ts +8 -0
- package/dist/data/utilities/deregisterRecord.js +34 -0
- package/dist/data/utilities/deregisterRecord.min.js +1 -0
- package/dist/data/utilities/getConditionIndexedList.d.ts +3 -0
- package/dist/data/utilities/getConditionIndexedList.js +47 -0
- package/dist/data/utilities/getConditionIndexedList.min.js +1 -0
- package/dist/data/utilities/getJoinIndexedList.d.ts +3 -0
- package/dist/data/utilities/getJoinIndexedList.js +59 -0
- package/dist/data/utilities/getJoinIndexedList.min.js +1 -0
- package/dist/data/utilities/getMatchingIndexes.d.ts +2 -0
- package/dist/data/utilities/getMatchingIndexes.js +28 -0
- package/dist/data/utilities/getMatchingIndexes.min.js +1 -0
- package/dist/data/utilities/matchIndexedJoins.d.ts +2 -0
- package/dist/data/utilities/matchIndexedJoins.js +61 -0
- package/dist/data/utilities/matchIndexedJoins.min.js +1 -0
- package/dist/data/utilities/mergeJoin.d.ts +2 -0
- package/dist/data/utilities/mergeJoin.js +44 -0
- package/dist/data/utilities/mergeJoin.min.js +1 -0
- package/dist/data/utilities/parsers/findCommand.d.ts +10 -0
- package/dist/data/utilities/parsers/findCommand.js +25 -0
- package/dist/data/utilities/parsers/findCommand.min.js +1 -0
- package/dist/data/utilities/parsers/findConditions.d.ts +15 -0
- package/dist/data/utilities/parsers/findConditions.js +28 -0
- package/dist/data/utilities/parsers/findConditions.min.js +1 -0
- package/dist/data/utilities/parsers/findGroupBy.d.ts +9 -0
- package/dist/data/utilities/parsers/findGroupBy.js +22 -0
- package/dist/data/utilities/parsers/findGroupBy.min.js +1 -0
- package/dist/data/utilities/parsers/findInsertValues.d.ts +13 -0
- package/dist/data/utilities/parsers/findInsertValues.js +34 -0
- package/dist/data/utilities/parsers/findInsertValues.min.js +1 -0
- package/dist/data/utilities/parsers/findJoinClauses.d.ts +13 -0
- package/dist/data/utilities/parsers/findJoinClauses.js +27 -0
- package/dist/data/utilities/parsers/findJoinClauses.min.js +1 -0
- package/dist/data/utilities/parsers/findJoinEntity.d.ts +9 -0
- package/dist/data/utilities/parsers/findJoinEntity.js +22 -0
- package/dist/data/utilities/parsers/findJoinEntity.min.js +1 -0
- package/dist/data/utilities/parsers/findLimit.d.ts +9 -0
- package/dist/data/utilities/parsers/findLimit.js +22 -0
- package/dist/data/utilities/parsers/findLimit.min.js +1 -0
- package/dist/data/utilities/parsers/findMergeJoins.d.ts +12 -0
- package/dist/data/utilities/parsers/findMergeJoins.js +26 -0
- package/dist/data/utilities/parsers/findMergeJoins.min.js +1 -0
- package/dist/data/utilities/parsers/findOffset.d.ts +9 -0
- package/dist/data/utilities/parsers/findOffset.js +22 -0
- package/dist/data/utilities/parsers/findOffset.min.js +1 -0
- package/dist/data/utilities/parsers/findSelects.d.ts +12 -0
- package/dist/data/utilities/parsers/findSelects.js +30 -0
- package/dist/data/utilities/parsers/findSelects.min.js +1 -0
- package/dist/data/utilities/parsers/findSortClauses.d.ts +12 -0
- package/dist/data/utilities/parsers/findSortClauses.js +30 -0
- package/dist/data/utilities/parsers/findSortClauses.min.js +1 -0
- package/dist/data/utilities/parsers/findUpdateValues.d.ts +15 -0
- package/dist/data/utilities/parsers/findUpdateValues.js +34 -0
- package/dist/data/utilities/parsers/findUpdateValues.min.js +1 -0
- package/dist/data/utilities/parsers/isEntityProperty.d.ts +2 -0
- package/dist/data/utilities/parsers/isEntityProperty.js +8 -0
- package/dist/data/utilities/parsers/isEntityProperty.min.js +1 -0
- package/dist/data/utilities/parsers/parseLiteralValue.d.ts +12 -0
- package/dist/data/utilities/parsers/parseLiteralValue.js +34 -0
- package/dist/data/utilities/parsers/parseLiteralValue.min.js +1 -0
- package/dist/data/utilities/parsers/parseQuery.d.ts +33 -0
- package/dist/data/utilities/parsers/parseQuery.js +51 -0
- package/dist/data/utilities/parsers/parseQuery.min.js +1 -0
- package/dist/data/utilities/parsers/removeFromQuery.d.ts +2 -0
- package/dist/data/utilities/parsers/removeFromQuery.js +8 -0
- package/dist/data/utilities/parsers/removeFromQuery.min.js +1 -0
- package/dist/data/utilities/parsers/splitEntityProperty.d.ts +5 -0
- package/dist/data/utilities/parsers/splitEntityProperty.js +23 -0
- package/dist/data/utilities/parsers/splitEntityProperty.min.js +1 -0
- package/dist/data/utilities/parsers/splitQueries.d.ts +2 -0
- package/dist/data/utilities/parsers/splitQueries.js +11 -0
- package/dist/data/utilities/parsers/splitQueries.min.js +1 -0
- package/dist/data/utilities/reconcileJoin.d.ts +2 -0
- package/dist/data/utilities/reconcileJoin.js +26 -0
- package/dist/data/utilities/reconcileJoin.min.js +1 -0
- package/dist/data/utilities/reconcileJoins.d.ts +2 -0
- package/dist/data/utilities/reconcileJoins.js +27 -0
- package/dist/data/utilities/reconcileJoins.min.js +1 -0
- package/dist/data/utilities/registerRecord.d.ts +8 -0
- package/dist/data/utilities/registerRecord.js +67 -0
- package/dist/data/utilities/registerRecord.min.js +1 -0
- package/dist/data/utilities/removeFromIndex.d.ts +14 -0
- package/dist/data/utilities/removeFromIndex.js +46 -0
- package/dist/data/utilities/removeFromIndex.min.js +1 -0
- package/dist/data/utilities/restrictIndexedList.d.ts +2 -0
- package/dist/data/utilities/restrictIndexedList.js +45 -0
- package/dist/data/utilities/restrictIndexedList.min.js +1 -0
- package/dist/data/utilities/retrieveFile.d.ts +2 -0
- package/dist/data/utilities/retrieveFile.js +28 -0
- package/dist/data/utilities/retrieveFile.min.js +1 -0
- package/dist/data/utilities/retrieveIndexes.d.ts +2 -0
- package/dist/data/utilities/retrieveIndexes.js +24 -0
- package/dist/data/utilities/retrieveIndexes.min.js +1 -0
- package/dist/data/utilities/retrieveRecord.d.ts +2 -0
- package/dist/data/utilities/retrieveRecord.js +9 -0
- package/dist/data/utilities/retrieveRecord.min.js +1 -0
- package/dist/data/utilities/retrieveRecords.d.ts +2 -0
- package/dist/data/utilities/retrieveRecords.js +21 -0
- package/dist/data/utilities/retrieveRecords.min.js +1 -0
- package/dist/data/utilities/runQuery.d.ts +2 -0
- package/dist/data/utilities/runQuery.js +72 -0
- package/dist/data/utilities/runQuery.min.js +1 -0
- package/dist/data/utilities/updateIndex.d.ts +17 -0
- package/dist/data/utilities/updateIndex.js +56 -0
- package/dist/data/utilities/updateIndex.min.js +1 -0
- package/dist/data/utilities/useJoinClause.d.ts +6 -0
- package/dist/data/utilities/useJoinClause.js +51 -0
- package/dist/data/utilities/useJoinClause.min.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +35 -0
- package/dist/index.min.js +1 -0
- package/gulpfile.mjs +15 -0
- package/package.json +44 -0
- package/src/data/introspect/create.test.js +67 -0
- package/src/data/introspect/create.ts +29 -0
- package/src/data/introspect/definitions/field.test.js +23 -0
- package/src/data/introspect/definitions/field.ts +48 -0
- package/src/data/introspect/definitions/key.test.js +100 -0
- package/src/data/introspect/definitions/key.ts +64 -0
- package/src/data/introspect/definitions/keyReference.test.js +8 -0
- package/src/data/introspect/definitions/keyReference.ts +23 -0
- package/src/data/introspect/definitions/record.ts +42 -0
- package/src/data/introspect/describe.test.js +36 -0
- package/src/data/introspect/describe.ts +9 -0
- package/src/data/introspect/drop.test.js +77 -0
- package/src/data/introspect/drop.ts +20 -0
- package/src/data/introspect/index.ts +8 -0
- package/src/data/introspect/policies/foreignKeyExists.test.js +44 -0
- package/src/data/introspect/policies/foreignKeyExists.ts +15 -0
- package/src/data/introspect/policies/keyGenerate.ts +11 -0
- package/src/data/introspect/policies/keyUnique.ts +11 -0
- package/src/data/introspect/policies/typeCheck.test.js +84 -0
- package/src/data/introspect/policies/typeCheck.ts +49 -0
- package/src/data/introspect/policies/typeEnum.ts +6 -0
- package/src/data/introspect/policies/useDefault.ts +6 -0
- package/src/data/queries/deleteEntity.test.js +86 -0
- package/src/data/queries/deleteEntity.ts +56 -0
- package/src/data/queries/groupBy.test.js +135 -0
- package/src/data/queries/groupBy.ts +16 -0
- package/src/data/queries/insertEntity.test.js +156 -0
- package/src/data/queries/insertEntity.ts +113 -0
- package/src/data/queries/joinEntity.test.js +109 -0
- package/src/data/queries/joinEntity.ts +20 -0
- package/src/data/queries/mergeJoins.test.js +174 -0
- package/src/data/queries/mergeJoins.ts +13 -0
- package/src/data/queries/parser.test.js +343 -0
- package/src/data/queries/parser.ts +24 -0
- package/src/data/queries/query.test.js +233 -0
- package/src/data/queries/query.ts +12 -0
- package/src/data/queries/readEntity.test.js +85 -0
- package/src/data/queries/readEntity.ts +8 -0
- package/src/data/queries/sortBy.test.js +131 -0
- package/src/data/queries/sortBy.ts +18 -0
- package/src/data/queries/updateEntity.test.js +228 -0
- package/src/data/queries/updateEntity.ts +162 -0
- package/src/data/queries/where.test.js +129 -0
- package/src/data/queries/where.ts +54 -0
- package/src/data/utilities/deregisterRecord.test.js +26 -0
- package/src/data/utilities/deregisterRecord.ts +24 -0
- package/src/data/utilities/getConditionIndexedList.ts +43 -0
- package/src/data/utilities/getJoinIndexedList.ts +53 -0
- package/src/data/utilities/getMatchingIndexes.ts +21 -0
- package/src/data/utilities/matchIndexedJoins.ts +45 -0
- package/src/data/utilities/mergeJoin.test.js +102 -0
- package/src/data/utilities/mergeJoin.ts +28 -0
- package/src/data/utilities/parsers/findCommand.ts +25 -0
- package/src/data/utilities/parsers/findConditions.test.js +38 -0
- package/src/data/utilities/parsers/findConditions.ts +32 -0
- package/src/data/utilities/parsers/findGroupBy.ts +20 -0
- package/src/data/utilities/parsers/findInsertValues.test.js +26 -0
- package/src/data/utilities/parsers/findInsertValues.ts +32 -0
- package/src/data/utilities/parsers/findJoinClauses.ts +29 -0
- package/src/data/utilities/parsers/findJoinEntity.ts +20 -0
- package/src/data/utilities/parsers/findLimit.ts +20 -0
- package/src/data/utilities/parsers/findMergeJoins.ts +27 -0
- package/src/data/utilities/parsers/findOffset.ts +20 -0
- package/src/data/utilities/parsers/findSelects.ts +31 -0
- package/src/data/utilities/parsers/findSortClauses.ts +31 -0
- package/src/data/utilities/parsers/findUpdateValues.test.js +37 -0
- package/src/data/utilities/parsers/findUpdateValues.ts +32 -0
- package/src/data/utilities/parsers/isEntityProperty.ts +1 -0
- package/src/data/utilities/parsers/parseLiteralValue.test.js +41 -0
- package/src/data/utilities/parsers/parseLiteralValue.ts +29 -0
- package/src/data/utilities/parsers/parseQuery.ts +73 -0
- package/src/data/utilities/parsers/removeFromQuery.ts +1 -0
- package/src/data/utilities/parsers/splitEntityProperty.test.js +8 -0
- package/src/data/utilities/parsers/splitEntityProperty.ts +17 -0
- package/src/data/utilities/parsers/splitQueries.test.js +33 -0
- package/src/data/utilities/parsers/splitQueries.ts +4 -0
- package/src/data/utilities/reconcileJoin.test.js +38 -0
- package/src/data/utilities/reconcileJoin.ts +23 -0
- package/src/data/utilities/reconcileJoins.test.js +160 -0
- package/src/data/utilities/reconcileJoins.ts +15 -0
- package/src/data/utilities/registerRecord.test.js +44 -0
- package/src/data/utilities/registerRecord.ts +44 -0
- package/src/data/utilities/removeFromIndex.test.js +44 -0
- package/src/data/utilities/removeFromIndex.ts +34 -0
- package/src/data/utilities/restrictIndexedList.ts +38 -0
- package/src/data/utilities/retrieveFile.test.js +49 -0
- package/src/data/utilities/retrieveFile.ts +19 -0
- package/src/data/utilities/retrieveIndexes.ts +17 -0
- package/src/data/utilities/retrieveRecord.ts +3 -0
- package/src/data/utilities/retrieveRecords.test.js +223 -0
- package/src/data/utilities/retrieveRecords.ts +16 -0
- package/src/data/utilities/runQuery.test.js +88 -0
- package/src/data/utilities/runQuery.ts +75 -0
- package/src/data/utilities/updateIndex.test.js +44 -0
- package/src/data/utilities/updateIndex.ts +45 -0
- package/src/data/utilities/useJoinClause.test.js +94 -0
- package/src/data/utilities/useJoinClause.ts +44 -0
- package/src/global.d.ts +1 -0
- package/src/index.test.js +52 -0
- package/src/index.ts +17 -0
- package/test-data/__RECORDS.json +32 -0
- package/test-data/__indexes/exercise_muscle/fk_exercise_id.json +14 -0
- package/test-data/__indexes/exercise_muscle/fk_muscle_id.json +14 -0
- package/test-data/__indexes/exercise_muscle/pk__id.json +14 -0
- package/test-data/__indexes/exercises/pk__id.json +14 -0
- package/test-data/__indexes/muscles/pk__id.json +58 -0
- package/test-data/__indexes/workouts/fk_exercise_id.json +23 -0
- package/test-data/__indexes/workouts/index_date.json +18 -0
- package/test-data/__indexes/workouts/pk__id.json +26 -0
- package/test-data/copyDatabase.ts +64 -0
- package/test-data/exercise_muscle/bench_press_pectorals.json +6 -0
- package/test-data/exercise_muscle/deadlift_hamstrings.json +6 -0
- package/test-data/exercise_muscle/squat_quadriceps.json +6 -0
- package/test-data/exercise_muscle.json +69 -0
- package/test-data/exercises/bench_press.json +5 -0
- package/test-data/exercises/deadlift.json +5 -0
- package/test-data/exercises/squat.json +5 -0
- package/test-data/exercises.json +34 -0
- package/test-data/muscles/abdominal.json +6 -0
- package/test-data/muscles/biceps.json +6 -0
- package/test-data/muscles/calves.json +6 -0
- package/test-data/muscles/deltoids.json +6 -0
- package/test-data/muscles/erector_spinae.json +6 -0
- package/test-data/muscles/forearms.json +6 -0
- package/test-data/muscles/gluteus_maximus.json +6 -0
- package/test-data/muscles/hamstrings.json +6 -0
- package/test-data/muscles/latissimus_dorsi.json +6 -0
- package/test-data/muscles/obliques.json +6 -0
- package/test-data/muscles/pectorals.json +6 -0
- package/test-data/muscles/quadriceps.json +6 -0
- package/test-data/muscles/trapezius.json +6 -0
- package/test-data/muscles/triceps.json +6 -0
- package/test-data/muscles.json +50 -0
- package/test-data/workouts/2024-06-02-001.json +10 -0
- package/test-data/workouts/2024-06-02-002.json +10 -0
- package/test-data/workouts/2024-06-02-003.json +10 -0
- package/test-data/workouts/2024-06-05-001.json +10 -0
- package/test-data/workouts/2024-06-05-002.json +10 -0
- package/test-data/workouts/2024-06-05-003.json +10 -0
- package/test-data/workouts.json +84 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const isEntityProperty = (property: string): boolean => /^[a-z0-9_-]+\.([a-z0-9_-]+)$/i.test(property)
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const removeFromQuery = (substring: string, query: string): string => query.replace(substring, '').trim()
|
|
@@ -0,0 +1,8 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
}
|