Skip to content

Commit

Permalink
fix: use ServiceOperationError and remove context (#839)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
- Renamed exception to the error on useServiceQuery
- Requires packages:
  - @txo/service-prop@^3.0.0
  - @txo-peer-dep/service-error-handler-react@^2.0.0
  - @txo/service-error-handler-react@^2.0.0
---------

Co-authored-by: Rostislav Simonik <rostislav.simonik@technologystudio.sk>
  • Loading branch information
erik-slovak and rostislav-simonik authored Oct 29, 2024
1 parent 8a54b5d commit 256a8c0
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 119 deletions.
2 changes: 1 addition & 1 deletion .boilerplate-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4939fd0f79a2ffcc5c6b5e77aa52d5341257b597
813c05c22fe6ab819ad616e30ae2c8f86efadb35
6 changes: 1 addition & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ on:
push:
branches:
- main
- next
- next-major
- alpha
- beta

jobs:
release:
name: '/'
name: 'Release'
uses: technology-studio/github-workflows/.github/workflows/_release.yml@main
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/resolve-yarn-lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:

jobs:
resolve-yarn-lock-on-comment:
name: '/'
name: 'Resolve yarn.lock'
if: contains(github.event.comment.body, '/resolve yarn.lock')
uses: technology-studio/github-workflows/.github/workflows/_resolve-yarn-lock.yml@main
secrets: inherit
Expand Down
3 changes: 1 addition & 2 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
yarn git-hook

yarn -s lint-staged
1 change: 0 additions & 1 deletion .husky/prepare-commit-msg
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
yarn commitlint --edit || exec < /dev/tty && yarn txo-cz --hook > /dev/null 2>&1 || true

12 changes: 11 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@
"name": "Debug Jest Tests",
"type": "node",
"request": "launch",
"runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "--coverage", "false"],
"runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "--coverage", "false", "${file}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"name": "Debug Jest Tests with yarn",
"type": "node",
"request": "launch",
"runtimeExecutable": "yarn",
"args": ["test", "--runInBand", "--coverage=false", "${file}"],
"runtimeArgs": ["--inspect-brk"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
Expand Down
2 changes: 1 addition & 1 deletion __tests__/Setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @Copyright: Technology Studio
**/

import './Config/LogConfig'
import 'Config/LogConfig'

// Mock your external modules here if needed
// jest
Expand Down
9 changes: 9 additions & 0 deletions __tests__/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
"rootDir": "../",
"baseUrl": "../",
"paths": {
"Config/*": ["./__tests__/Config/*"],
"Data/*": ["./__tests__/Data/*"],
"Utils/*": ["./__tests__/Utils/*"],
"src": ["./src"],
"src/*": ["./src/*"]
}
},
"include": [
"./**/*.ts"
Expand Down
9 changes: 4 additions & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@
**/

const { pathsToModuleNameMapper } = require('ts-jest')
const { compilerOptions } = require('./tsconfig.json');
const { compilerOptions } = require('./__tests__/tsconfig.json');

const { defaults } = require('jest-config');

module.exports = {
preset: 'ts-jest',
cache: true,
cacheDirectory: '<rootDir>/node_modules/.cache/jest',
testEnvironment: 'node',
testMatch: [
'<rootDir>/__tests__/Tests/**/?(*.)(spec|test).ts'
],
transformIgnorePatterns: [
'/node_modules/(?!@txo).+\\.js$'
],
testPathIgnorePatterns: [
'/node_modules/'
],
Expand All @@ -29,7 +28,7 @@ module.exports = {
],
transform: {
'^.+\\.tsx?$': ['ts-jest', {
tsconfig: './__tests__/tsconfig.json'
tsconfig: '<rootDir>/__tests__/tsconfig.json'
}]
},
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths , { prefix: '<rootDir>/' } ),
Expand Down
25 changes: 12 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,46 @@
"license": "UNLICENSED",
"private": false,
"scripts": {
"build": "yarn build:clean && yarn build:lib",
"build:clean": "yarn rimraf lib",
"build:lib": "yarn tsc",
"build:watch": "yarn tsc --watch",
"test": "jest",
"test:watch": "concurrently \"yarn build:watch\" \"jest --watch\"",
"coverage": "jest --coverage && open coverage/lcov-report/index.html || xdg-open coverage/lcov-report/index.html",
"build": "yarn build:clean && yarn build:lib",
"compare-boilerplate-version": "./scripts/compare-boilerplate-version.sh",
"coverage": "jest --coverage && open coverage/lcov-report/index.html || xdg-open coverage/lcov-report/index.html",
"lint:ci": "yarn lint",
"lint:fix": "eslint . --fix",
"lint": "eslint --max-warnings 0 .",
"fixcode": "eslint . --fix",
"git-hook": "yarn -s lint-staged",
"prepare": "husky && yarn build",
"print-txo-packages": "yarn list 2> /dev/null|grep @txo|sed 's/.*\\(@txo[^@]*\\)@^*\\([^ ]*\\).*/\\1@\\2/g'|sort|uniq",
"sanity": "yarn lint:ci && yarn build && tsc --noEmit && yarn test --coverage && yarn compare-boilerplate-version && echo 'success'",
"semantic-release": "semantic-release",
"update-boilerplate-version": "./scripts/update-boilerplate-version.sh",
"lint:ci": "yarn lint",
"type-check": "tsc --noEmit"
"test:watch": "concurrently \"yarn build:watch\" \"yarn test --watch\"",
"test": "jest",
"type-check": "tsc --noEmit",
"update-boilerplate-version": "./scripts/update-boilerplate-version.sh"
},
"engines": {
"node": ">=18.0.0"
},
"dependencies": {
"@txo/hooks-react": "^2.3.21",
"@txo/service-graphql": "^4.4.6",
"@txo/service-prop": "^2.2.20",
"@txo/service-graphql": "^5.0.0",
"@txo/service-prop": "^3.0.2",
"@txo/types": "^1.7.0",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"type-fest": "^4.26.1"
},
"peerDependencies": {
"@apollo/client": "^3.11.8",
"@txo-peer-dep/service-error-handler-react": "^1.2.29",
"@txo-peer-dep/error-handler": "^3.0.0",
"@txo-peer-dep/service-graphql": "^3.3.3",
"graphql": "^16.9.0"
},
"devDependencies": {
"@apollo/client": "^3.11.8",
"@txo-peer-dep/error-handler": "^3.0.0",
"@txo-peer-dep/log": "^4.0.4",
"@txo-peer-dep/service-error-handler-react": "^1.2.29",
"@txo-peer-dep/service-graphql": "^3.3.3",
"@txo/commitlint": "^1.0.19",
"@txo/log-console": "^3.0.0",
Expand Down
11 changes: 11 additions & 0 deletions src/Api/VoidError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @Author: Erik Slovak <erik.slovak@technologystudio.sk>
* @Date: 2024-10-25T22:32:09+02:00
* @Copyright: Technology Studio
**/

export class VoidError extends Error {
constructor () {
super('Void validation error')
}
}
42 changes: 17 additions & 25 deletions src/Hooks/UseServiceMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
import type { DependencyList } from 'react'
import {
useCallback,
useContext,
useMemo,
useRef,
} from 'react'
import type {
CallAttributes,
ServiceProp,
ServiceErrorException,
ServiceOperationError,
} from '@txo/service-prop'
import { useMemoObject } from '@txo/hooks-react'
import type { Typify } from '@txo/types'
Expand All @@ -29,20 +27,20 @@ import type {
import {
useMutation,
} from '@apollo/client'
import { ErrorHandlerContext } from '@txo-peer-dep/service-error-handler-react'
import { operationPromiseProcessor } from '@txo/service-graphql'

import { serviceContext } from '../Api/ContextHelper'
import { getName } from '../Api/OperationHelper'
import type { ErrorMap } from '../Model/Types'
import { applyErrorMap } from '../Api/ErrorMapHelper'
import { VoidError } from '../Api/VoidError'

const calculateContext = (mutation: DocumentNode, variables?: Record<string, unknown>): string => (
serviceContext(getName(mutation), variables ?? {})
)

export type MutationServiceProp<ATTRIBUTES, DATA, CALL_ATTRIBUTES extends CallAttributes<ATTRIBUTES>> =
Omit<ServiceProp<ATTRIBUTES, DATA, CALL_ATTRIBUTES, FetchResult<DATA>>, 'clear' | 'options' | 'clearException' | 'exception'>
Omit<ServiceProp<ATTRIBUTES, DATA, CALL_ATTRIBUTES, FetchResult<DATA>>, 'options' | 'error'>
& {
mutation: MutationResult<DATA>,
}
Expand All @@ -62,10 +60,10 @@ export const useServiceMutation = <
ATTRIBUTES extends Record<string, unknown>,
DATA,
CALL_ATTRIBUTES extends CallAttributes<ATTRIBUTES>,
>(
mutationDocument: TypedDocumentNode<DATA, ATTRIBUTES>,
options?: MutationOptions<DATA, ATTRIBUTES>,
): MutationServiceProp<ATTRIBUTES, DATA, CALL_ATTRIBUTES> => {
> (
mutationDocument: TypedDocumentNode<DATA, ATTRIBUTES>,
options?: MutationOptions<DATA, ATTRIBUTES>,
): MutationServiceProp<ATTRIBUTES, DATA, CALL_ATTRIBUTES> => {
const {
onFieldErrors: defaultOnFieldErrors,
onFieldErrorsDependencyList,
Expand All @@ -74,7 +72,6 @@ export const useServiceMutation = <
options: mutationOptions,
mutateFactory,
} = options ?? {}
const exceptionRef = useRef<ServiceErrorException | null>(null)
const memoizedErrorMap = useMemo(
() => errorMap,
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -86,13 +83,9 @@ export const useServiceMutation = <
onFieldErrorsDependencyList ?? [],
)
const [mutate, mutation] = useMutation<
DATA,
ATTRIBUTES
DATA,
ATTRIBUTES
>(mutationDocument, mutationOptions)
const {
addServiceErrorException,
removeServiceErrorException,
} = useContext(ErrorHandlerContext)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const memoizedOptions = useMemoObject(mutationOptions!)
const wrappedCall = useCallback(async (
Expand All @@ -102,8 +95,6 @@ export const useServiceMutation = <
const attributes = { variables, mutation: mutationDocument, ...memoizedOptions }
const onFieldErrors = callAttributes?.onFieldErrors ?? memoizedDefaultOnFieldErrors
const context = calculateContext(mutationDocument, variables)
;(exceptionRef.current != null) && removeServiceErrorException(context)
exceptionRef.current = null
const operationName = getName(mutationDocument)
const mutateWithErrorProcessor: typeof mutate = async (options) => (
await operationPromiseProcessor(mutate(options), {
Expand All @@ -116,19 +107,20 @@ export const useServiceMutation = <
operationName,
context,
})
.catch(async (serviceErrorException: ServiceErrorException) => {
.catch(async (serviceOperationError: ServiceOperationError) => {
if (memoizedErrorMap != null) {
serviceErrorException.serviceErrorList = applyErrorMap(
serviceErrorException.serviceErrorList,
serviceOperationError.serviceErrorList = applyErrorMap(
serviceOperationError.serviceErrorList,
memoizedErrorMap,
onFieldErrors,
)
}
addServiceErrorException(serviceErrorException)
exceptionRef.current = serviceErrorException
throw serviceErrorException
if (serviceOperationError.serviceErrorList.length === 0) {
throw new VoidError()
}
throw serviceOperationError
})
}, [mutationDocument, memoizedOptions, memoizedDefaultOnFieldErrors, removeServiceErrorException, mutateFactory, mutate, memoizedErrorMap, addServiceErrorException])
}, [mutationDocument, memoizedOptions, memoizedDefaultOnFieldErrors, mutateFactory, mutate, memoizedErrorMap])

const memoizedMutation = useMemoObject<Typify<MutationResult<DATA>>>(mutation)

Expand Down
Loading

0 comments on commit 256a8c0

Please sign in to comment.