Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use ServiceOperationError and remove context #839

Merged
merged 14 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading