diff --git a/packages/cubejs-api-gateway/package.json b/packages/cubejs-api-gateway/package.json index 1d5215526c583..660bbc23df3a4 100644 --- a/packages/cubejs-api-gateway/package.json +++ b/packages/cubejs-api-gateway/package.json @@ -36,6 +36,7 @@ "express-graphql": "^0.12.0", "graphql": "^15.8.0", "graphql-scalars": "^1.10.0", + "joi": "^17.8.3", "jsonwebtoken": "^8.3.0", "jwk-to-pem": "^2.0.4", "moment": "^2.24.0", @@ -49,7 +50,6 @@ "devDependencies": { "@cubejs-backend/linter": "^0.32.0", "@types/express": "^4.17.9", - "@types/hapi__joi": "^15.0.4", "@types/jest": "^26.0.20", "@types/jsonwebtoken": "^8.5.0", "@types/jwk-to-pem": "^2.0.0", diff --git a/packages/cubejs-api-gateway/src/query.js b/packages/cubejs-api-gateway/src/query.js index 4d3909af29ce9..7532da3390b21 100644 --- a/packages/cubejs-api-gateway/src/query.js +++ b/packages/cubejs-api-gateway/src/query.js @@ -1,6 +1,6 @@ import R from 'ramda'; import moment from 'moment'; -import Joi from '@hapi/joi'; +import Joi from 'joi'; import { UserError } from './UserError'; import { dateParser } from './dateParser'; @@ -68,13 +68,13 @@ const operators = [ const oneFilter = Joi.object().keys({ dimension: id, member: id, - operator: Joi.valid(operators).required(), - values: Joi.array().items(Joi.string().allow('', null), Joi.lazy(() => oneFilter)) + operator: Joi.valid(...operators).required(), + values: Joi.array().items(Joi.string().allow('', null), Joi.link('...')) }).xor('dimension', 'member'); const oneCondition = Joi.object().keys({ - or: Joi.array().items(oneFilter, Joi.lazy(() => oneCondition).description('oneCondition schema')), - and: Joi.array().items(oneFilter, Joi.lazy(() => oneCondition).description('oneCondition schema')), + or: Joi.array().items(oneFilter, Joi.link('...').description('oneCondition schema')), + and: Joi.array().items(oneFilter, Joi.link('...').description('oneCondition schema')), }).xor('or', 'and'); const querySchema = Joi.object().keys({ @@ -167,7 +167,7 @@ const validatePostRewrite = (query) => { * @returns {NormalizedQuery} */ const normalizeQuery = (query) => { - const { error } = Joi.validate(query, querySchema); + const { error } = querySchema.validate(query); if (error) { throw new UserError(`Invalid query format: ${error.message || error.toString()}`); } @@ -246,7 +246,7 @@ const queryPreAggregationsSchema = Joi.object().keys({ }); const normalizeQueryPreAggregations = (query, defaultValues) => { - const { error } = Joi.validate(query, queryPreAggregationsSchema); + const { error } = queryPreAggregationsSchema.validate(query); if (error) { throw new UserError(`Invalid query format: ${error.message || error.toString()}`); } @@ -272,7 +272,7 @@ const queryPreAggregationPreviewSchema = Joi.object().keys({ }); const normalizeQueryPreAggregationPreview = (query) => { - const { error } = Joi.validate(query, queryPreAggregationPreviewSchema); + const { error } = queryPreAggregationPreviewSchema.validate(query); if (error) { throw new UserError(`Invalid query format: ${error.message || error.toString()}`); } @@ -286,7 +286,7 @@ const queryCancelPreAggregationPreviewSchema = Joi.object().keys({ }); const normalizeQueryCancelPreAggregations = query => { - const { error } = Joi.validate(query, queryCancelPreAggregationPreviewSchema); + const { error } = queryCancelPreAggregationPreviewSchema.validate(query); if (error) { throw new UserError(`Invalid query format: ${error.message || error.toString()}`); } diff --git a/packages/cubejs-schema-compiler/package.json b/packages/cubejs-schema-compiler/package.json index d6c6ecefa88cb..c67d0b9537b3b 100644 --- a/packages/cubejs-schema-compiler/package.json +++ b/packages/cubejs-schema-compiler/package.json @@ -41,12 +41,12 @@ "@babel/traverse": "^7.12.10", "@babel/types": "^7.12.12", "@cubejs-backend/shared": "^0.32.0", - "@hapi/joi": "^17.1.1", "antlr4ts": "0.5.0-alpha.4", "camelcase": "^6.2.0", "cron-parser": "^3.5.0", "humps": "^2.0.1", "inflection": "^1.12.0", + "joi": "^17.8.3", "js-yaml": "^4.1.0", "lru-cache": "^5.1.1", "moment-range": "^4.0.1", @@ -63,7 +63,6 @@ "@types/babel__generator": "^7.6.2", "@types/babel__parser": "^7.1.1", "@types/babel__traverse": "^7.11.0", - "@types/hapi__joi": "^17.1.1", "@types/inflection": "^1.5.28", "@types/jest": "^26.0.20", "@types/lru-cache": "^5.1.0", diff --git a/packages/cubejs-schema-compiler/src/compiler/CubeValidator.js b/packages/cubejs-schema-compiler/src/compiler/CubeValidator.js index 8240bf2d7a97c..1862fd4fc0d06 100644 --- a/packages/cubejs-schema-compiler/src/compiler/CubeValidator.js +++ b/packages/cubejs-schema-compiler/src/compiler/CubeValidator.js @@ -1,4 +1,4 @@ -const Joi = require('@hapi/joi'); +const Joi = require('joi'); const cronParser = require('cron-parser'); /* ***************************** diff --git a/packages/cubejs-server-core/package.json b/packages/cubejs-server-core/package.json index c6f6557154b5f..f44768b90297c 100644 --- a/packages/cubejs-server-core/package.json +++ b/packages/cubejs-server-core/package.json @@ -37,11 +37,11 @@ "@cubejs-backend/schema-compiler": "^0.32.0", "@cubejs-backend/shared": "^0.32.0", "@cubejs-backend/templates": "^0.32.0", - "@hapi/joi": "^15.1.1", "codesandbox-import-utils": "^2.1.12", "cross-spawn": "^7.0.1", "fs-extra": "^8.1.0", "is-docker": "^2.1.1", + "joi": "^17.8.3", "jsonwebtoken": "^8.4.0", "lodash.clonedeep": "^4.5.0", "lru-cache": "^5.1.1", @@ -63,7 +63,6 @@ "@types/cross-spawn": "^6.0.2", "@types/express": "^4.17.9", "@types/fs-extra": "^9.0.8", - "@types/hapi__joi": "^15.0.4", "@types/jest": "^26.0.20", "@types/jsonwebtoken": "^8.5.0", "@types/lru-cache": "^5.1.0", diff --git a/packages/cubejs-server-core/src/core/optionsValidate.ts b/packages/cubejs-server-core/src/core/optionsValidate.ts index cd1561f4f6944..4205fd1599c8d 100644 --- a/packages/cubejs-server-core/src/core/optionsValidate.ts +++ b/packages/cubejs-server-core/src/core/optionsValidate.ts @@ -1,4 +1,4 @@ -import Joi from '@hapi/joi'; +import Joi from 'joi'; import DriverDependencies from './DriverDependencies'; const schemaQueueOptions = Joi.object().keys({ @@ -151,7 +151,7 @@ const schemaOptions = Joi.object().keys({ }); export default (options: any) => { - const { error } = Joi.validate(options, schemaOptions, { abortEarly: false, }); + const { error } = schemaOptions.validate(options, { abortEarly: false }); if (error) { throw new Error(`Invalid cube-server-core options: ${error.message || error.toString()}`); } diff --git a/packages/cubejs-server-core/test/unit/OptsHandler.test.ts b/packages/cubejs-server-core/test/unit/OptsHandler.test.ts index 2373f52720d82..7b10ae177c30b 100644 --- a/packages/cubejs-server-core/test/unit/OptsHandler.test.ts +++ b/packages/cubejs-server-core/test/unit/OptsHandler.test.ts @@ -74,7 +74,7 @@ describe('OptsHandler class', () => { dbType: undefined, driverFactory: undefined, }); - + expect(core.options.dbType).toBeDefined(); expect(typeof core.options.dbType).toEqual('function'); expect(await core.options.dbType({} as DriverContext)) @@ -160,7 +160,7 @@ describe('OptsHandler class', () => { type: process.env.CUBEJS_DB_TYPE, }), }); - + expect(core.options.dbType).toBeDefined(); expect(typeof core.options.dbType).toEqual('function'); expect(await core.options.dbType({} as DriverContext)) @@ -180,7 +180,7 @@ describe('OptsHandler class', () => { type: process.env.CUBEJS_DB_TYPE, }), }); - + expect(core.options.dbType).toBeDefined(); expect(typeof core.options.dbType).toEqual('function'); expect(await core.options.dbType({} as DriverContext)) @@ -200,7 +200,7 @@ describe('OptsHandler class', () => { type: process.env.CUBEJS_DB_TYPE, }), }); - + expect(core.options.dbType).toBeDefined(); expect(typeof core.options.dbType).toEqual('function'); expect(await core.options.dbType({} as DriverContext)) @@ -220,7 +220,7 @@ describe('OptsHandler class', () => { type: process.env.CUBEJS_DB_TYPE, }), }); - + expect(core.options.dbType).toBeDefined(); expect(typeof core.options.dbType).toEqual('function'); expect(await core.options.dbType({} as DriverContext)) @@ -260,8 +260,7 @@ describe('OptsHandler class', () => { }); await core.options.driverFactory({ dataSource: 'default' }); }).rejects.toThrow( - 'Invalid cube-server-core options: child "driverFactory" fails because ' + - '["driverFactory" must be a Function]' + 'Invalid cube-server-core options: "driverFactory" must be of type function' ); // Case 3 -- need to be restored after assertion will be restored. @@ -303,8 +302,7 @@ describe('OptsHandler class', () => { }); await core.options.dbType({ dataSource: 'default' }); }).rejects.toThrow( - 'Invalid cube-server-core options: child "dbType" fails because ' + - '["dbType" must be a string, "dbType" must be a Function]' + 'Invalid cube-server-core options: "dbType" does not match any of the allowed types' ); // Case 6 @@ -402,7 +400,7 @@ describe('OptsHandler class', () => { const opts = oapi.options; const testDriverConnectionSpy = jest.spyOn(oapi, 'testDriverConnection'); oapi.seenDataSources = ['default']; - + expect(core.optsHandler.configuredForScheduledRefresh()).toBe(true); expect(opts.rollupOnlyMode).toBe(false); expect(opts.preAggregationsOptions.externalRefresh).toBe(false); @@ -503,7 +501,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -533,7 +531,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -563,7 +561,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -593,7 +591,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -623,7 +621,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -667,7 +665,7 @@ describe('OptsHandler class', () => { }); const opts = (core.getOrchestratorApi({})).options; - + expect(opts.queryCacheOptions.queueOptions).toBeDefined(); expect(typeof opts.queryCacheOptions.queueOptions).toEqual('function'); expect(await opts.queryCacheOptions.queueOptions()).toEqual({ @@ -713,7 +711,7 @@ describe('OptsHandler class', () => { }); opts = (core.getOrchestratorApi({})).options; driver = (await core.resolveDriver({}, opts)); - + expect(driver.pool.options.max).toEqual(2 * (concurrency1 + concurrency2)); // Case 2 @@ -736,7 +734,7 @@ describe('OptsHandler class', () => { }); opts = (core.getOrchestratorApi({})).options; driver = (await core.resolveDriver({})); - + expect(driver.pool.options.max).toEqual(8); }); diff --git a/packages/cubejs-server-core/test/unit/index.test.ts b/packages/cubejs-server-core/test/unit/index.test.ts index 0cf733419f9af..c2849b806014b 100644 --- a/packages/cubejs-server-core/test/unit/index.test.ts +++ b/packages/cubejs-server-core/test/unit/index.test.ts @@ -32,7 +32,7 @@ const repositoryWithoutPreAggregations: SchemaFileRepository = { fileName: 'main.js', content: ` cube('Bar', { sql: 'select * from bar', - + measures: { count: { type: 'count' @@ -61,7 +61,7 @@ const repositoryWithDataSource: SchemaFileRepository = { dataSchemaFiles: () => Promise.resolve([{ fileName: 'main.js', content: ` cube('Bar', { sql: 'select * from bar', - + measures: { count: { type: 'count' @@ -72,7 +72,7 @@ cube('Bar', { sql: 'timestamp', type: 'time' } - }, + }, dataSource: 'main' }); ` }]), @@ -124,7 +124,7 @@ describe('index.test', () => { }; expect(() => new CubejsServerCore(options)) - .toThrowError(/"compilerCacheSize" must be larger than or equal to 0/); + .toThrowError(/"compilerCacheSize" must be greater than or equal to 0/); }); test('Should create instance of CubejsServerCore, orchestratorOptions as func', () => { @@ -397,7 +397,7 @@ describe('index.test', () => { expect(dataSources.dataSources).toEqual([]); }); }); - + describe('CompilerApi dataSources method', () => { const logger = jest.fn(() => {}); const compilerApi = new CompilerApi( diff --git a/yarn.lock b/yarn.lock index 991cc1892de48..9c06d5b18e6d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4142,23 +4142,11 @@ resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== -"@hapi/address@^4.0.1": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.1.0.tgz#d60c5c0d930e77456fdcde2598e77302e2955e1d" - integrity sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/bourne@1.x.x": version "1.3.2" resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== -"@hapi/formula@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128" - integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A== - "@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": version "8.5.1" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" @@ -4169,7 +4157,7 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== -"@hapi/joi@^15.0.1", "@hapi/joi@^15.1.0", "@hapi/joi@^15.1.1": +"@hapi/joi@^15.0.1", "@hapi/joi@^15.1.0": version "15.1.1" resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== @@ -4179,22 +4167,6 @@ "@hapi/hoek" "8.x.x" "@hapi/topo" "3.x.x" -"@hapi/joi@^17.1.1": - version "17.1.1" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-17.1.1.tgz#9cc8d7e2c2213d1e46708c6260184b447c661350" - integrity sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg== - dependencies: - "@hapi/address" "^4.0.1" - "@hapi/formula" "^2.0.0" - "@hapi/hoek" "^9.0.0" - "@hapi/pinpoint" "^2.0.0" - "@hapi/topo" "^5.0.0" - -"@hapi/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df" - integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw== - "@hapi/topo@3.x.x": version "3.1.6" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" @@ -6291,6 +6263,23 @@ "@angular-devkit/schematics" "12.2.14" jsonc-parser "3.0.0" +"@sideway/address@^4.1.3": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -6732,18 +6721,6 @@ dependencies: "@types/node" "*" -"@types/hapi__joi@*", "@types/hapi__joi@^17.1.1": - version "17.1.7" - resolved "https://registry.yarnpkg.com/@types/hapi__joi/-/hapi__joi-17.1.7.tgz#a479bc593823fb7bd5600fea37917c8e5c71629c" - integrity sha512-byC9slpuqyDeEKegl/ViT8PCQRSp0CYkhLzz0cPxqxV6QC53Ht1cr2jG5iwOvtt/RxylUbTpXNqpgbf9Qu8QFw== - -"@types/hapi__joi@^15.0.4": - version "15.0.4" - resolved "https://registry.yarnpkg.com/@types/hapi__joi/-/hapi__joi-15.0.4.tgz#49e2e1e6da15ade0fdd6db4daf94aecb07bb391b" - integrity sha512-VSS6zc7AIOdHVXmqKaGNPYl8eGrMvWi0R5pt3evJL3UdxO8XS28/XAkBXNyLQoymHxhMd4bF3o1U9mZkWDeN8w== - dependencies: - "@types/hapi__joi" "*" - "@types/history@*": version "4.7.9" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724" @@ -18120,6 +18097,17 @@ jmespath@0.15.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= +joi@^17.8.3: + version "17.8.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.3.tgz#d772fe27a87a5cda21aace5cf11eee8671ca7e6f" + integrity sha512-q5Fn6Tj/jR8PfrLrx4fpGH4v9qM6o+vDUfD4/3vxxyg34OmKcNqYZ1qn2mpLza96S8tL0p0rIw2gOZX+/cTg9w== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + jpeg-js@^0.3.4: version "0.3.7" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.3.7.tgz#471a89d06011640592d314158608690172b1028d"