@emartech/program-executor
Advanced tools
+1
-1
@@ -45,3 +45,3 @@ { | ||
| }, | ||
| "version": "3.4.0" | ||
| "version": "3.5.0" | ||
| } |
@@ -10,3 +10,6 @@ 'use strict'; | ||
| GraphQLString, | ||
| GraphQLInt | ||
| GraphQLInt, | ||
| GraphQLBoolean, | ||
| GraphQLInputObjectType, | ||
| GraphQLEnumType | ||
| } = require('graphql'); | ||
@@ -59,2 +62,38 @@ | ||
| const ProgramFilterInput = new GraphQLInputObjectType({ | ||
| name: 'ProgramFilter', | ||
| fields: { | ||
| inProgressOnly: { | ||
| type: GraphQLBoolean, | ||
| defaultValue: false | ||
| }, | ||
| stepRetryCountGte: { | ||
| type: GraphQLInt, | ||
| defaultValue: 0 | ||
| } | ||
| } | ||
| }); | ||
| const OrderByEnumType = new GraphQLEnumType({ | ||
| name: 'OrderByEnum', | ||
| values: { | ||
| ASC: { | ||
| value: 'ASC' | ||
| }, | ||
| DESC: { | ||
| value: 'DESC' | ||
| } | ||
| } | ||
| }); | ||
| const OrderByInput = new GraphQLInputObjectType({ | ||
| name: 'OrderByInput', | ||
| fields: { | ||
| id: { | ||
| type: OrderByEnumType, | ||
| defaultValue: OrderByEnumType.getValue('DESC') | ||
| } | ||
| } | ||
| }); | ||
| const schema = new GraphQLSchema({ | ||
@@ -68,8 +107,25 @@ query: new GraphQLObjectType({ | ||
| filter: { | ||
| type: GraphQLString | ||
| type: ProgramFilterInput | ||
| }, | ||
| orderBy: { | ||
| type: OrderByInput | ||
| } | ||
| }, | ||
| resolve: async (_root, _args, { knex, tableName }) => { | ||
| resolve: async (_root, args, { knex, tableName }) => { | ||
| let query = knex(tableName); | ||
| if (args.filter && args.filter.inProgressOnly) { | ||
| query = query.whereRaw('finished_at is null AND errored_at is null'); | ||
| } | ||
| if (args.filter && args.filter.stepRetryCountGte) { | ||
| query = query.where('step_retry_count', '>=', args.filter.stepRetryCountGte); | ||
| } | ||
| if (args.orderBy && args.orderBy.id) { | ||
| query = query.orderBy('id', args.orderBy.id); | ||
| } | ||
| try { | ||
| const programs = await knex(tableName).select(); | ||
| const programs = await query; | ||
| return programs.map(camelCaseAndStringify); | ||
@@ -76,0 +132,0 @@ } catch (err) { |
+145
-56
@@ -7,67 +7,156 @@ 'use strict'; | ||
| const QUERY = ` | ||
| { | ||
| programs { | ||
| id | ||
| runId | ||
| jobs | ||
| jobData | ||
| programData | ||
| step | ||
| finishedAt | ||
| erroredAt | ||
| errorMessage | ||
| stepRetryCount | ||
| createdAt, | ||
| updatedAt | ||
| } | ||
| }`; | ||
| describe('schema', function () { | ||
| describe('with empty database', () => { | ||
| it('returns with empty array when table does not exist (error code 42P01)', async function () { | ||
| const query = ` | ||
| { | ||
| programs { | ||
| id | ||
| } | ||
| }`; | ||
| describe('schema', function () { | ||
| it('returns with empty array when table does not exist (error code 42P01)', async function () { | ||
| const { data } = await graphql(schema, QUERY, {}, { knex: this.db, tableName: 'programs' }); | ||
| expect(data).to.eql({ programs: [] }); | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| expect(data).to.eql({ programs: [] }); | ||
| }); | ||
| }); | ||
| it('returns with programs inserted', async function () { | ||
| const repository = new ProgramsRepository(this.db, 'programs'); | ||
| const program1 = { | ||
| runId: '12345', | ||
| programData: { foo: 'bar' }, | ||
| jobs: ['a', 'b'] | ||
| }; | ||
| const program2 = { | ||
| runId: '12345', | ||
| programData: { foo: 'bar' }, | ||
| jobs: ['a', 'b'], | ||
| jobData: { data1: 1, data2: 2 }, | ||
| step: 0, | ||
| finishedAt: new Date(), | ||
| erroredAt: new Date(), | ||
| errorMessage: 'someErrorMessage', | ||
| stepRetryCount: 1 | ||
| }; | ||
| await repository.save(program1); | ||
| await repository.save(program2); | ||
| describe('with programs in database', () => { | ||
| const programs = [ | ||
| { | ||
| runId: '1', | ||
| programData: { foo: 'bar' }, | ||
| jobs: ['a', 'b'] | ||
| }, | ||
| { | ||
| runId: '2', | ||
| programData: { bar: 'baz' }, | ||
| jobs: ['errored_job'], | ||
| jobData: { data1: 1, data2: 2 }, | ||
| step: 0, | ||
| erroredAt: new Date(), | ||
| errorMessage: 'someErrorMessage', | ||
| stepRetryCount: 1 | ||
| }, | ||
| { | ||
| runId: '3', | ||
| programData: { bar: 'baz' }, | ||
| jobs: ['finished_job'], | ||
| jobData: { data1: 1, data2: 2 }, | ||
| step: 0, | ||
| finishedAt: new Date(), | ||
| errorMessage: 'someErrorMessage', | ||
| stepRetryCount: 5 | ||
| } | ||
| ]; | ||
| const { data } = await graphql(schema, QUERY, {}, { knex: this.db, tableName: 'programs' }); | ||
| beforeEach(async function () { | ||
| const programsRepository = new ProgramsRepository(this.db, 'programs'); | ||
| for (const program of programs) { | ||
| await programsRepository.save(program); | ||
| } | ||
| }); | ||
| expect(data.programs[0]).to.containSubset({ | ||
| ...program1, | ||
| jobData: JSON.stringify({}), | ||
| programData: JSON.stringify(program1.programData) | ||
| it('returns with programs inserted', async function () { | ||
| const query = `{ | ||
| programs { | ||
| id | ||
| runId | ||
| jobs | ||
| jobData | ||
| programData | ||
| step | ||
| finishedAt | ||
| erroredAt | ||
| errorMessage | ||
| stepRetryCount | ||
| createdAt, | ||
| updatedAt | ||
| } | ||
| }`; | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| expect(data.programs[0]).to.containSubset({ | ||
| ...programs[0], | ||
| jobData: JSON.stringify({}), | ||
| programData: JSON.stringify(programs[0].programData) | ||
| }); | ||
| expect(data.programs[0].createdAt).not.to.be.undefined; | ||
| expect(data.programs[0].updatedAt).not.to.be.undefined; | ||
| expect(data.programs[1]).to.containSubset({ | ||
| ...programs[1], | ||
| jobData: JSON.stringify(programs[1].jobData), | ||
| programData: JSON.stringify(programs[1].programData), | ||
| erroredAt: programs[1].erroredAt.getTime().toString() | ||
| }); | ||
| expect(data.programs[1].createdAt).not.to.be.undefined; | ||
| expect(data.programs[1].updatedAt).not.to.be.undefined; | ||
| expect(data.programs[2]).to.containSubset({ | ||
| ...programs[2], | ||
| jobData: JSON.stringify(programs[2].jobData), | ||
| programData: JSON.stringify(programs[2].programData), | ||
| finishedAt: programs[2].finishedAt.getTime().toString() | ||
| }); | ||
| expect(data.programs[2].createdAt).not.to.be.undefined; | ||
| expect(data.programs[2].updatedAt).not.to.be.undefined; | ||
| }); | ||
| expect(data.programs[0].createdAt).not.to.be.undefined; | ||
| expect(data.programs[0].updatedAt).not.to.be.undefined; | ||
| expect(data.programs[1]).to.containSubset({ | ||
| ...program2, | ||
| jobData: JSON.stringify(program2.jobData), | ||
| programData: JSON.stringify(program2.programData), | ||
| finishedAt: program2.finishedAt.getTime().toString(), | ||
| erroredAt: program2.erroredAt.getTime().toString() | ||
| describe('accepts orderBy input for `id` field', () => { | ||
| it('supports ordering by id ASC', async function () { | ||
| const query = `{ | ||
| programs(orderBy: {id: ASC}) { | ||
| id | ||
| } | ||
| }`; | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| const ids = data.programs.map((program) => program.id); | ||
| expect(ids).to.eql(['1', '2', '3']); | ||
| }); | ||
| it('supports ordering by id DESC', async function () { | ||
| const query = `{ | ||
| programs(orderBy: {id: DESC}) { | ||
| id | ||
| } | ||
| }`; | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| const ids = data.programs.map((program) => program.id); | ||
| expect(ids).to.eql(['3', '2', '1']); | ||
| }); | ||
| }); | ||
| expect(data.programs[1].createdAt).not.to.be.undefined; | ||
| expect(data.programs[1].updatedAt).not.to.be.undefined; | ||
| describe('accepts filters', () => { | ||
| it('supports filtering for in progress only', async function () { | ||
| const query = `{ | ||
| programs(filter: {inProgressOnly: true }) { | ||
| id | ||
| } | ||
| }`; | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| const ids = data.programs.map((program) => program.id); | ||
| expect(ids).to.eql(['1']); | ||
| }); | ||
| it('supports filtering for programs with step retry count greater than a given input', async function () { | ||
| const query = `{ | ||
| programs(filter: {stepRetryCountGte: 4 }) { | ||
| id | ||
| } | ||
| }`; | ||
| const { data } = await graphql(schema, query, {}, { knex: this.db, tableName: 'programs' }); | ||
| const ids = data.programs.map((program) => program.id); | ||
| expect(ids).to.eql(['3']); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
78573
5.3%1692
7.84%