diff --git a/.github/workflows/node.js.yaml b/.github/workflows/node.js.yaml index 3b61978..27ddefd 100644 --- a/.github/workflows/node.js.yaml +++ b/.github/workflows/node.js.yaml @@ -5,6 +5,11 @@ name: Node.js CI on: [push, pull_request] +env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_DB: test + jobs: test: runs-on: ubuntu-latest @@ -12,6 +17,16 @@ jobs: matrix: node-version: [20.x, 22.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + services: + postgres: + image: postgres:17 + env: + POSTGRES_USER: ${{ env.POSTGRES_USER }} + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + POSTGRES_DB: ${{ env.POSTGRES_DB }} + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 @@ -29,6 +44,16 @@ jobs: coverage: name: coverage runs-on: ubuntu-latest + services: + postgres: + image: postgres:17 + env: + POSTGRES_USER: ${{ env.POSTGRES_USER }} + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + POSTGRES_DB: ${{ env.POSTGRES_DB }} + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 7084f34..b977bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -123,3 +123,5 @@ docs/.vitepress/cache .cache .temp + +.env \ No newline at end of file diff --git a/package.json b/package.json index db2c262..ee2f9ac 100644 --- a/package.json +++ b/package.json @@ -58,8 +58,8 @@ "@feathersjs/errors": "^5.0.34", "@feathersjs/feathers": "^5.0.34", "@feathersjs/transport-commons": "^5.0.34", - "feathers-hooks-common": "^8.2.1", "@fratzinger/feathers-utils": "^7.0.1", + "feathers-hooks-common": "^8.2.1", "lodash": "^4.17.21" }, "devDependencies": { @@ -75,12 +75,15 @@ "@feathersjs/mongodb": "^5.0.34", "@feathersjs/socketio": "^5.0.34", "@feathersjs/socketio-client": "^5.0.34", + "@fratzinger/feathers-kysely": "^0.0.2", "@seald-io/nedb": "^4.1.2", "@tsconfig/node22": "^22.0.2", "@types/lodash": "^4.17.20", "@types/node": "^24.3.1", + "@types/pg": "^8.15.5", "@vitest/coverage-v8": "^3.2.4", "cors": "^2.8.5", + "dotenv": "^17.2.2", "eslint": "^9.34.0", "feathers-fletching": "^2.0.7", "feathers-knex": "^8.0.1", @@ -91,11 +94,13 @@ "get-port": "^7.1.0", "helmet": "^8.1.0", "knex": "^3.1.0", + "kysely": "^0.28.7", "mongodb": "^6.19.0", "mongodb-memory-server": "^10.2.0", "mongoose": "^8.18.0", "np": "^10.2.0", "objection": "^3.1.5", + "pg": "^8.16.3", "prettier": "^3.6.2", "sequelize": "^6.37.7", "socket.io-client": "^4.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c87744e..818cc5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,7 +50,7 @@ importers: version: 5.0.34(typescript@5.9.2) '@feathersjs/knex': specifier: ^5.0.34 - version: 5.0.34(knex@3.1.0(sqlite3@5.1.7)) + version: 5.0.34(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7)) '@feathersjs/memory': specifier: ^5.0.34 version: 5.0.34 @@ -63,6 +63,9 @@ importers: '@feathersjs/socketio-client': specifier: ^5.0.34 version: 5.0.34 + '@fratzinger/feathers-kysely': + specifier: ^0.0.2 + version: 0.0.2(@feathersjs/feathers@5.0.34)(kysely@0.28.7) '@seald-io/nedb': specifier: ^4.1.2 version: 4.1.2 @@ -75,12 +78,18 @@ importers: '@types/node': specifier: ^24.3.1 version: 24.3.1 + '@types/pg': + specifier: ^8.15.5 + version: 8.15.5 '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.3.1)(jiti@2.5.1)) cors: specifier: ^2.8.5 version: 2.8.5 + dotenv: + specifier: ^17.2.2 + version: 17.2.2 eslint: specifier: ^9.34.0 version: 9.34.0(jiti@2.5.1) @@ -98,7 +107,7 @@ importers: version: 7.0.1(@seald-io/nedb@4.1.2) feathers-objection: specifier: ^7.6.0 - version: 7.6.0(objection@3.1.5(knex@3.1.0(sqlite3@5.1.7))) + version: 7.6.0(objection@3.1.5(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7))) feathers-sequelize: specifier: ^7.0.3 version: 7.0.3 @@ -110,7 +119,10 @@ importers: version: 8.1.0 knex: specifier: ^3.1.0 - version: 3.1.0(sqlite3@5.1.7) + version: 3.1.0(pg@8.16.3)(sqlite3@5.1.7) + kysely: + specifier: ^0.28.7 + version: 0.28.7 mongodb: specifier: ^6.19.0 version: 6.19.0(socks@2.8.3) @@ -125,13 +137,16 @@ importers: version: 10.2.0(@types/node@24.3.1)(typescript@5.9.2) objection: specifier: ^3.1.5 - version: 3.1.5(knex@3.1.0(sqlite3@5.1.7)) + version: 3.1.5(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7)) + pg: + specifier: ^8.16.3 + version: 8.16.3 prettier: specifier: ^3.6.2 version: 3.6.2 sequelize: specifier: ^6.37.7 - version: 6.37.7(sqlite3@5.1.7) + version: 6.37.7(pg@8.16.3)(sqlite3@5.1.7) socket.io-client: specifier: ^4.8.1 version: 4.8.1 @@ -827,6 +842,10 @@ packages: resolution: {integrity: sha512-wc0HAZ0uov68p1ytBR5npyAePdNbFrRqr1fINSpLvIkrUkKDEcC6I/lOpk1TBpoI8so5IO/seZhkl25pqKM43A==} engines: {node: '>= 12'} + '@feathersjs/adapter-commons@5.0.35': + resolution: {integrity: sha512-pQ0hR2scLpOm2cti5XMTgubrhLEZWIlchODrO2sPOwMS6FNpsbm7aOxKXtaFfMKHBVAyTJN1yjmfgbCT96Xb5w==} + engines: {node: '>= 12'} + '@feathersjs/authentication-local@5.0.34': resolution: {integrity: sha512-3swHyoz/kW3lTAoGRNT1Y49PXy+wx1/bgw5AQpExLanLuXipevuKHapLvlDUh914bz8vw6FmC/5TnFwxrx8OOQ==} engines: {node: '>= 12'} @@ -847,6 +866,10 @@ packages: resolution: {integrity: sha512-UfHzq7taVJx++TXxX5pmDSR72xRp+h5nler4xcUlcJWLLykCOYo8YCeW03S7T1p1NuFdy0qBmU+B+G89bjyGmg==} engines: {node: '>= 12'} + '@feathersjs/commons@5.0.35': + resolution: {integrity: sha512-YYk3SRLGcM9TPHsd2mGmTdFeZORmv5wa1MRCvmEUwzcsFIPWbq4F6ddFgqKUely216RvPumwyjV9U+MasROesQ==} + engines: {node: '>= 12'} + '@feathersjs/configuration@5.0.34': resolution: {integrity: sha512-5mn9k9ueJOpcl4x54h5ZBf5WtaIdKplc/rqxntolObw1dF/V0BvOX7S6cVypkPH0tQnf1GLvc1ag/rk015eSQw==} engines: {node: '>= 12'} @@ -859,6 +882,10 @@ packages: resolution: {integrity: sha512-C0t+pONnMvwlDW6iczcYmxaHzGvaGn3+BLhwlySEVYRciWOURIO8Eo5JVdN7cSM3Z7AxS3Dpk4DEhyFU/D2w6w==} engines: {node: '>= 12'} + '@feathersjs/errors@5.0.35': + resolution: {integrity: sha512-J8ulAndEPUFTcPiGR0zO3VfnZqw1nL5BBEmFERRMlxYRCvBVwXPruOGpSEA/x2BY463UYTHD9j9Rj5lfGT62OQ==} + engines: {node: '>= 12'} + '@feathersjs/express@5.0.34': resolution: {integrity: sha512-TNy8vEIYnjB9eEwancP07C5wYnv5i1vXctKH9HhtIfa1xJ7KnGgIDT9LNO4gX0OeURzDcE+zFEB9Xnto6zKh4g==} engines: {node: '>= 12'} @@ -871,6 +898,10 @@ packages: resolution: {integrity: sha512-jgeqKq/Uhsfeld42F8uimqzPv/uhtohkenpaWeD+NudJp2YZNYfA6gDZAL5UTpAvrTJFmK3QR1q1CnuL1mJdHg==} engines: {node: '>= 12'} + '@feathersjs/feathers@5.0.35': + resolution: {integrity: sha512-1T6DSQ97LJGmgS5NTu1Oe/Ef1zLgoqYDNAdj67UMNC5Vk7I0F8rohgQcaOOUp8DlKNkXPFWX/z+AXJM4DhkCHQ==} + engines: {node: '>= 12'} + '@feathersjs/hooks@0.9.0': resolution: {integrity: sha512-kLfWnuhbC25CPkR1/TDcVs0rSiv0JLNxrpUivLwc7FUnkyeciRi5VOmC1SOzL2SOagcozu3+m4VQiONyzgfY7w==} engines: {node: '>= 14'} @@ -909,6 +940,13 @@ packages: resolution: {integrity: sha512-l+oQm1oIvfrxNUlidcqCtKfdWdKn1zHXGhEa13xIKiU5m2LFz1EYeMuq5vh/1pU0iECq3Oi+KdW53YnGl446cw==} engines: {node: '>= 12'} + '@fratzinger/feathers-kysely@0.0.2': + resolution: {integrity: sha512-qtFzoyGx4LjCVhk6he5yUHqaInBr64pLYMj7WS4/GHuo18gIhAUOPp9idKeX+KAFoVQRYB60O0M56dR6FPS4NQ==} + engines: {node: '>= 14'} + peerDependencies: + '@feathersjs/feathers': ^5.0.0 + kysely: ^0.28.0 + '@fratzinger/feathers-utils@7.0.1': resolution: {integrity: sha512-gRXeQ5p34+ge4PkVbgn8zaE7LXcacfdFIGi4i084t3PXsFAwOorWCMcix8x3hpT4tGOPUA01U8xLvvjcRkZvIQ==} engines: {node: '>= 18'} @@ -1541,6 +1579,9 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/pg@8.15.5': + resolution: {integrity: sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==} + '@types/qs@6.9.14': resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==} @@ -2602,6 +2643,10 @@ packages: resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} engines: {node: '>=18'} + dotenv@17.2.2: + resolution: {integrity: sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==} + engines: {node: '>=12'} + dottie@2.0.6: resolution: {integrity: sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==} @@ -3805,6 +3850,10 @@ packages: resolution: {integrity: sha512-2IM3VssHfG2zYz2FsHRUqIp8chhLc9uxDMcK2THxgFfv8pQhnMfN8L0ul+iW4RdBl5AglF8ooPIflRm3yNH0IA==} engines: {node: '>=18'} + kysely@0.28.7: + resolution: {integrity: sha512-u/cAuTL4DRIiO2/g4vNGRgklEKNIj5Q3CG7RoUB5DV5SfEC2hMvPxKi0GWPmnzwL2ryIeud2VTcEEmqzTzEPNw==} + engines: {node: '>=20.0.0'} + latest-version@9.0.0: resolution: {integrity: sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==} engines: {node: '>=18'} @@ -4510,12 +4559,46 @@ packages: perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + pg-cloudflare@1.2.7: + resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + pg-connection-string@2.6.2: resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} pg-connection-string@2.6.4: resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + pg-connection-string@2.9.1: + resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.10.1: + resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.10.3: + resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.16.3: + resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4740,6 +4823,22 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + preact@10.20.2: resolution: {integrity: sha512-S1d1ernz3KQ+Y2awUxKakpfOg2CEmJmwOP+6igPx6dgr6pgDvenqYviyokWso2rhHvGtTlWWnJDa7RaPbQerTg==} @@ -5169,6 +5268,10 @@ packages: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -5821,6 +5924,10 @@ packages: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -6376,6 +6483,12 @@ snapshots: '@feathersjs/errors': 5.0.34 '@feathersjs/feathers': 5.0.34 + '@feathersjs/adapter-commons@5.0.35': + dependencies: + '@feathersjs/commons': 5.0.35 + '@feathersjs/errors': 5.0.35 + '@feathersjs/feathers': 5.0.35 + '@feathersjs/authentication-local@5.0.34(typescript@5.9.2)': dependencies: '@feathersjs/authentication': 5.0.34(typescript@5.9.2) @@ -6409,6 +6522,8 @@ snapshots: '@feathersjs/commons@5.0.34': {} + '@feathersjs/commons@5.0.35': {} + '@feathersjs/configuration@5.0.34(typescript@5.9.2)': dependencies: '@feathersjs/commons': 5.0.34 @@ -6427,6 +6542,8 @@ snapshots: '@feathersjs/errors@5.0.34': {} + '@feathersjs/errors@5.0.35': {} + '@feathersjs/express@5.0.34(typescript@5.9.2)': dependencies: '@feathersjs/authentication': 5.0.34(typescript@5.9.2) @@ -6460,15 +6577,21 @@ snapshots: '@feathersjs/hooks': 0.9.0 events: 3.3.0 + '@feathersjs/feathers@5.0.35': + dependencies: + '@feathersjs/commons': 5.0.35 + '@feathersjs/hooks': 0.9.0 + events: 3.3.0 + '@feathersjs/hooks@0.9.0': {} - '@feathersjs/knex@5.0.34(knex@3.1.0(sqlite3@5.1.7))': + '@feathersjs/knex@5.0.34(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7))': dependencies: '@feathersjs/adapter-commons': 5.0.34 '@feathersjs/commons': 5.0.34 '@feathersjs/errors': 5.0.34 '@feathersjs/feathers': 5.0.34 - knex: 3.1.0(sqlite3@5.1.7) + knex: 3.1.0(pg@8.16.3)(sqlite3@5.1.7) '@feathersjs/memory@5.0.34': dependencies: @@ -6522,6 +6645,14 @@ snapshots: encodeurl: 2.0.0 lodash: 4.17.21 + '@fratzinger/feathers-kysely@0.0.2(@feathersjs/feathers@5.0.34)(kysely@0.28.7)': + dependencies: + '@feathersjs/adapter-commons': 5.0.35 + '@feathersjs/commons': 5.0.35 + '@feathersjs/errors': 5.0.35 + '@feathersjs/feathers': 5.0.34 + kysely: 0.28.7 + '@fratzinger/feathers-utils@7.0.1(@feathersjs/feathers@5.0.34)': dependencies: '@feathersjs/adapter-commons': 5.0.34 @@ -7088,6 +7219,12 @@ snapshots: '@types/normalize-package-data@2.4.4': {} + '@types/pg@8.15.5': + dependencies: + '@types/node': 24.3.1 + pg-protocol: 1.10.3 + pg-types: 2.2.0 + '@types/qs@6.9.14': {} '@types/range-parser@1.2.7': {} @@ -8228,6 +8365,8 @@ snapshots: dependencies: type-fest: 4.41.0 + dotenv@17.2.2: {} + dottie@2.0.6: {} eastasianwidth@0.2.0: {} @@ -8873,11 +9012,11 @@ snapshots: '@feathersjs/errors': 5.0.34 '@seald-io/nedb': 4.1.2 - feathers-objection@7.6.0(objection@3.1.5(knex@3.1.0(sqlite3@5.1.7))): + feathers-objection@7.6.0(objection@3.1.5(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7))): dependencies: '@feathersjs/adapter-commons': 4.5.17 '@feathersjs/errors': 4.5.17 - objection: 3.1.5(knex@3.1.0(sqlite3@5.1.7)) + objection: 3.1.5(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7)) transitivePeerDependencies: - supports-color @@ -9640,7 +9779,7 @@ snapshots: kind-of@6.0.3: {} - knex@3.1.0(sqlite3@5.1.7): + knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -9657,6 +9796,7 @@ snapshots: tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: + pg: 8.16.3 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color @@ -9665,6 +9805,8 @@ snapshots: ky@1.2.3: {} + kysely@0.28.7: {} + latest-version@9.0.0: dependencies: package-json: 10.0.1 @@ -10270,12 +10412,12 @@ snapshots: es-object-atoms: 1.0.0 optional: true - objection@3.1.5(knex@3.1.0(sqlite3@5.1.7)): + objection@3.1.5(knex@3.1.0(pg@8.16.3)(sqlite3@5.1.7)): dependencies: ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) db-errors: 0.2.3 - knex: 3.1.0(sqlite3@5.1.7) + knex: 3.1.0(pg@8.16.3)(sqlite3@5.1.7) on-finished@2.4.1: dependencies: @@ -10427,10 +10569,45 @@ snapshots: perfect-debounce@1.0.0: {} + pg-cloudflare@1.2.7: + optional: true + pg-connection-string@2.6.2: {} pg-connection-string@2.6.4: {} + pg-connection-string@2.9.1: {} + + pg-int8@1.0.1: {} + + pg-pool@3.10.1(pg@8.16.3): + dependencies: + pg: 8.16.3 + + pg-protocol@1.10.3: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.16.3: + dependencies: + pg-connection-string: 2.9.1 + pg-pool: 3.10.1(pg@8.16.3) + pg-protocol: 1.10.3 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.2.7 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -10641,6 +10818,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.0: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + preact@10.20.2: {} prebuild-install@7.1.2: @@ -10959,7 +11146,7 @@ snapshots: sequelize-pool@7.1.0: {} - sequelize@6.37.7(sqlite3@5.1.7): + sequelize@6.37.7(pg@8.16.3)(sqlite3@5.1.7): dependencies: '@types/debug': 4.1.12 '@types/validator': 13.11.9 @@ -10978,6 +11165,7 @@ snapshots: validator: 13.11.0 wkx: 0.5.0 optionalDependencies: + pg: 8.16.3 sqlite3: 5.1.7 transitivePeerDependencies: - supports-color @@ -11152,6 +11340,8 @@ snapshots: speakingurl@14.0.1: {} + split2@4.2.0: {} + sprintf-js@1.1.3: optional: true @@ -11925,6 +12115,8 @@ snapshots: xmlhttprequest-ssl@2.1.2: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yallist@4.0.0: {} diff --git a/src/types.ts b/src/types.ts index 4bbb218..81b7c5b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,6 +13,7 @@ export type Adapter = // | "feathers-nedb" // | "feathers-objection" | 'feathers-sequelize' + | 'feathers-kysely' export interface ServiceCaslOptions { availableFields: string[] diff --git a/test/hooks/authorize/adapters/@feathersjs/knex.test.ts b/test/hooks/authorize/adapters/@feathersjs/knex.test.ts index e350976..dcb4ad2 100644 --- a/test/hooks/authorize/adapters/@feathersjs/knex.test.ts +++ b/test/hooks/authorize/adapters/@feathersjs/knex.test.ts @@ -20,12 +20,6 @@ const db = knex({ useNullAsDefault: true, }) -// Create the schema -db.schema.createTable('messages', (table) => { - table.increments('id') - table.string('text') -}) - const makeService = () => { return new KnexService({ Model: db, diff --git a/test/hooks/authorize/adapters/feathers-kysely.test.ts b/test/hooks/authorize/adapters/feathers-kysely.test.ts new file mode 100644 index 0000000..8f8694b --- /dev/null +++ b/test/hooks/authorize/adapters/feathers-kysely.test.ts @@ -0,0 +1,107 @@ +import { PostgresDialect, Kysely } from 'kysely' +import type { PoolConfig } from 'pg' +import { Pool } from 'pg' +import makeTests from './makeTests/index.js' +import type { Adapter, ServiceCaslOptions } from '../../../../src/types.js' +import { KyselyService } from '@fratzinger/feathers-kysely' +import { getItemsIsArray } from '@fratzinger/feathers-utils' +import type { HookContext } from '@feathersjs/feathers' + +declare module '@fratzinger/feathers-kysely' { + interface KyselyAdapterOptions { + casl: ServiceCaslOptions + } +} + +const config: PoolConfig = { + host: 'localhost', + user: process.env.POSTGRES_USER ?? 'postgres', + password: + 'POSTGRES_PASSWORD' in process.env + ? process.env.POSTGRES_PASSWORD + : 'password', + database: process.env.POSTGRES_DB ?? 'test', + port: process.env.POSTGRES_PORT ? Number(process.env.POSTGRES_PORT) : 5432, + max: 10, +} + +const db = new Kysely({ + dialect: new PostgresDialect({ + pool: new Pool(config), + }), +}) + +const makeService = () => { + return new KyselyService({ + Model: db, + name: 'tests', + multi: true, + casl: { + availableFields: [ + 'id', + 'userId', + 'hi', + 'test', + 'published', + 'supersecret', + 'hidden', + ], + }, + paginate: { + default: 10, + max: 50, + }, + }) +} + +const boolFields = ['test', 'published', 'supersecret', 'hidden'] + +const afterHooks = [ + (context: HookContext) => { + const { items, isArray } = getItemsIsArray(context) + + const result = items + + result.forEach((item, i) => { + const keys = Object.keys(item) + keys.forEach((key) => { + if (item[key] === null) { + delete item[key] + return + } + if (boolFields.includes(key)) { + item[key] = !!item[key] + } + }) + + result[i] = { ...item } + }) + + context.result = isArray ? result : result[0] + }, +] + +const adapter: Adapter = 'feathers-kysely' + +makeTests( + adapter, + makeService, + async () => { + await db.schema.dropTable('tests').ifExists().execute() + + await db.schema + .createTable('tests') + .addColumn('id', 'serial', (col) => col.primaryKey()) + .addColumn('userId', 'integer') + .addColumn('hi', 'varchar') + .addColumn('test', 'boolean') + .addColumn('published', 'boolean') + .addColumn('supersecret', 'boolean') + .addColumn('hidden', 'boolean') + .execute() + }, + { adapter }, + { + afterHooks, + }, +) diff --git a/test/hooks/authorize/adapters/makeTests/_makeTests.types.ts b/test/hooks/authorize/adapters/makeTests/_makeTests.types.ts index 0010ea9..b37bd1b 100644 --- a/test/hooks/authorize/adapters/makeTests/_makeTests.types.ts +++ b/test/hooks/authorize/adapters/makeTests/_makeTests.types.ts @@ -1,5 +1,6 @@ export type MakeTestsOptions = { around?: boolean + beforeHooks?: unknown[] afterHooks?: unknown[] actionBefore?: () => Promise | void } diff --git a/test/hooks/authorize/adapters/makeTests/index.ts b/test/hooks/authorize/adapters/makeTests/index.ts index 1d253ed..82b464c 100644 --- a/test/hooks/authorize/adapters/makeTests/index.ts +++ b/test/hooks/authorize/adapters/makeTests/index.ts @@ -19,6 +19,7 @@ export default async function ( authorizeHookOptions: Partial, makeTestsOptions: MakeTestsOptions = { around: false, + beforeHooks: [], afterHooks: [], actionBefore: () => {}, }, diff --git a/test/hooks/authorize/adapters/makeTests/update.ts b/test/hooks/authorize/adapters/makeTests/update.ts index 27410e0..6bd89f4 100644 --- a/test/hooks/authorize/adapters/makeTests/update.ts +++ b/test/hooks/authorize/adapters/makeTests/update.ts @@ -14,7 +14,11 @@ export default ( makeService: () => any, clean: (app, service) => Promise, authorizeHookOptions: Partial, - { around, afterHooks }: MakeTestsOptions = { around: false, afterHooks: [] }, + { around, beforeHooks, afterHooks }: MakeTestsOptions = { + around: false, + beforeHooks: [], + afterHooks: [], + }, ): void => { let app: Application let service @@ -62,6 +66,9 @@ export default ( around: { all: [authorize(options)], }, + before: { + all: [...(beforeHooks ?? [])], + }, after: { all: afterHooks, }, @@ -69,7 +76,7 @@ export default ( } else { service.hooks({ before: { - all: [authorize(options)], + all: [authorize(options), ...(beforeHooks ?? [])], }, after: { all: [...afterHooks, authorize(options)], diff --git a/vite.config.ts b/vite.config.ts index 95a721e..f747be0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,7 @@ import { defineConfig } from 'vitest/config' +import dotenv from 'dotenv' + +dotenv.config() export default defineConfig({ test: {