Skip to content

Commit

Permalink
Replace block executor registry with dependency injection (#532)
Browse files Browse the repository at this point in the history
* Replace block executor registry by dependency injection
* Refactor ConstraintExecutorRegistry to JayveeConstraintExtension
  • Loading branch information
georg-schwarz authored Mar 4, 2024
1 parent c4d1e0c commit f144c8c
Show file tree
Hide file tree
Showing 31 changed files with 202 additions and 234 deletions.
6 changes: 3 additions & 3 deletions apps/docs/docs/dev/04-guides/06-jayvee-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
JayveeExecExtension,
} from '@jvalue/jayvee-execution';

export class MyExecExtension implements JayveeExecExtension {
export class MyExecExtension extends JayveeExecExtension {
getBlockExecutors(): BlockExecutorClass[] {
return [];
}
Expand All @@ -72,7 +72,7 @@ In `libs/extensions/std/exec/src/extension.ts`:

import { MyExecExtension } from '@jvalue/jayvee-extensions/<extension-name>/exec';

export class StdExecExtension implements JayveeExecExtension {
export class StdExecExtension extends JayveeExecExtension {
private readonly wrappedExtensions: JayveeExecExtension[] = [
// ...
// Register your execution extension here:
Expand Down Expand Up @@ -177,7 +177,7 @@ In `libs/extensions/<extension-name>/exec/src/extension.ts`:

import { MyExtractorExecutor } from './lib/my-extractor-executor';

export class MyExecExtension implements JayveeExecExtension {
export class MyExecExtension extends JayveeExecExtension {
getBlockExecutors(): BlockExecutorClass[] {
return [
// ...
Expand Down
33 changes: 11 additions & 22 deletions apps/docs/docs/dev/12-jayvee-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ These kind of tests are mainly located inside the [language-server](https://gith
The testing utils are located inside the `language-server` in a dedicated [test folder](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/test).
These utils can be imported using `@jvalue/jayvee-language-server/test` and contain the following parts:

[**langium-utils.ts**](https://github.com/jvalue/jayvee/blob/main/libs/language-server/src/test/langium-utils.ts):
[**langium-utils.ts**](https://github.com/jvalue/jayvee/blob/main/libs/language-server/src/test/langium-utils.ts):
This utils file contains two functions:
- `parseHelper` to simplify parsing the input (content of a *.jv file) and returning the corresponding `LangiumDocument`, and
- `validationHelper` parse and validate the created document.
Expand Down Expand Up @@ -100,34 +100,23 @@ pipeline Pipeline {
### Existing tests
Currently there are already tests for the following parts:
- Language-server validation checks (located [here](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/lib/validation))
- Language-server constraint validation (located [here](https://github.com/jvalue/jayvee/tree/dev/libs/language-server/src/lib/constraint))
- Custom block (property) validation of the three existing extensions (std extension located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src))
- Grammar validation tests for all official full examples from the [/example](https://github.com/jvalue/jayvee/tree/main/example) folder (located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src/example-validation.spec.ts))
- Grammar validation tests for all block examples of the std extension (located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts))
- Language-server constraint validation (located [here](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/lib/constraint))
- Custom block (property) validation of the three existing extensions (std extension located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src))
- Grammar validation tests for all official full examples from the [/example](https://github.com/jvalue/jayvee/tree/main/example) folder (located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src/example-validation.spec.ts))
- Grammar validation tests for all block examples of the std extension (located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts))

## Execution tests
These kind of tests are mainly located inside the [interpreter](https://github.com/jvalue/jayvee/tree/main/libs/language-server), the [interpreter-lib](https://github.com/jvalue/jayvee/tree/dev/libs/interpreter-lib), the [execution lib](https://github.com/jvalue/jayvee/tree/dev/libs/execution) as well as the execution parts of each extension (for example [std/exec](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec)).
These kind of tests are mainly located inside the [interpreter](https://github.com/jvalue/jayvee/tree/main/libs/language-server), the [interpreter-lib](https://github.com/jvalue/jayvee/tree/main/libs/interpreter-lib), the [execution lib](https://github.com/jvalue/jayvee/tree/main/libs/execution) as well as the execution parts of each extension (for example [std/exec](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec)).

### Testing utils
The testing utils for execution tests are spread between the extensions, with the interfaces and base utils located inside the [execution lib](https://github.com/jvalue/jayvee/tree/dev/libs/execution).
The testing utils for execution tests are spread between the extensions, with the interfaces and base utils located inside the [execution lib](https://github.com/jvalue/jayvee/tree/main/libs/execution).
They can be imported using `@jvalue/jayvee-extensions/rdbms/test`, `@jvalue/jayvee-extensions/std/test` and `@jvalue/jayvee-execution/test`.

[**utils.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/utils.ts):
At the moment this only contains two functions:
- `clearBlockExecutorRegistry` for clearing the registry containing all `BlockExecutor`s, and
- `clearConstraintExecutorRegistry` clearing the corresponding `ConstraintExecutor`s registry.
They are required in case the tested method initializes Jayvee itself (see [smoke test](#existing-tests-1)).

[**test-logger.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/test-logger.ts):
This contains a subclass of the [`DefaultLogger`](https://github.com/jvalue/jayvee/blob/dev/libs/execution/src/lib/logging/default-logger.ts) used for tests which require a `Logger` implementation. The `TestLogger` contains the following tests functionality:
- `getLogs`: retrieve the cached logs that the logger received.
- `clearLogs`: clear the cached logs.

[**block-executor-mocks.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/block-executor-mock.ts):
[**block-executor-mocks.ts**](https://github.com/jvalue/jayvee/blob/main/libs/execution/test/block-executor-mock.ts):
`BlockExecutorMock` interface for defining mocks for `AbstractBlockExecutor`. Generally only loader and executor blocks require mocks, because they interact with "the outside world" (i.e. `HttpExtractor` making http calls).
Due to how vastly different each `BlockExecutor` can be, this interface is very simple, containing only a `setup(...args: unknown[])` and a `restore()` method. See below for existing implementations.

[**rdbms/exec/test**](https://github.com/jvalue/jayvee/tree/dev/libs/extensions/rdbms/exec/test):
[**rdbms/exec/test**](https://github.com/jvalue/jayvee/tree/main/libs/extensions/rdbms/exec/test):
Contains the implementation of `BlockExecutorMock` for `PostgresLoaderExecutor` and `SQLiteLoaderExecutor`.
Both of these executors are mocked using `jest.mock` to mock the corresponding libraries (`pg` and `sqlite3`)
**Usage:**
Expand Down Expand Up @@ -187,7 +176,7 @@ describe('Dummy describe', () => {
});
```

[**std/exec/test/mocks**](https://github.com/jvalue/jayvee/tree/dev/libs/extensions/std/exec/test):
[**std/exec/test/mocks**](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec/test):
Contains the implementation of `BlockExecutorMock` for `HttpExtractorExecutorMock`.
This implementation uses [nock](https://www.npmjs.com/package/nock) for mocking HTTP(S) responses.
The `setup` method is further specified requiring one parameter `registerMocks: () => Array<nock.Scope>`, which returns all used `nock.Scope` (i.e. the return value of `nock('<URL>')`), see usage below:
Expand Down Expand Up @@ -251,4 +240,4 @@ describe('Dummy describe', () => {

### Existing tests
Currently there are already tests for the following parts:
- Smoke test for official examples (located [here](https://github.com/jvalue/jayvee/blob/dev/apps/interpreter/src/examples-smoke-test.spec.ts))
- Smoke test for official examples (located [here](https://github.com/jvalue/jayvee/blob/main/apps/interpreter/src/examples-smoke-test.spec.ts))
10 changes: 1 addition & 9 deletions apps/interpreter/src/examples-smoke-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@

import * as path from 'path';

import {
clearBlockExecutorRegistry,
clearConstraintExecutorRegistry,
processExitMockImplementation,
} from '@jvalue/jayvee-execution/test';
import { processExitMockImplementation } from '@jvalue/jayvee-execution/test';
import {
PostgresLoaderExecutorMock,
SQLiteLoaderExecutorMock,
Expand Down Expand Up @@ -72,10 +68,6 @@ describe('jv example smoke tests', () => {
httpExtractorMock.restore();
postgresLoaderMock.restore();
sqliteLoaderMock.restore();

// Clear registries
clearBlockExecutorRegistry();
clearConstraintExecutorRegistry();
});

it('should have no errors when executing cars.jv example', async () => {
Expand Down
8 changes: 0 additions & 8 deletions apps/interpreter/src/parse-only.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import * as fs from 'node:fs';
import * as path from 'path';
import * as process from 'process';

import {
clearBlockExecutorRegistry,
clearConstraintExecutorRegistry,
} from '@jvalue/jayvee-execution/test';
import {
RunOptions,
interpretModel,
Expand Down Expand Up @@ -52,10 +48,6 @@ describe('Parse Only', () => {
jest.spyOn(process, 'exit').mockImplementation(() => {
throw new Error();
});

// Reset jayvee specific stuff
clearBlockExecutorRegistry();
clearConstraintExecutorRegistry();
});

it('should exit with 0 on a valid option', async () => {
Expand Down
7 changes: 3 additions & 4 deletions libs/execution/src/lib/blocks/block-execution-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import {
PipelineWrapper,
} from '@jvalue/jayvee-language-server';

import { ExecutionContext } from '../execution-context';
import { type ExecutionContext } from '../execution-context';
import { Logger } from '../logging/logger';
import { IOTypeImplementation, NONE } from '../types';

// eslint-disable-next-line import/no-cycle
import { createBlockExecutor } from './block-executor-registry';
import * as R from './execution-result';

export interface ExecutionOrderItem {
Expand Down Expand Up @@ -94,7 +92,8 @@ export async function executeBlock(
return R.ok(null);
}

const blockExecutor = createBlockExecutor(block);
const blockExecutor =
executionContext.executionExtension.createBlockExecutor(block);

const startTime = new Date();

Expand Down
57 changes: 0 additions & 57 deletions libs/execution/src/lib/blocks/block-executor-registry.ts

This file was deleted.

2 changes: 1 addition & 1 deletion libs/execution/src/lib/blocks/block-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IOType, isBlockDefinition } from '@jvalue/jayvee-language-server';

import { isBlockTargetedForDebugLogging } from '../debugging/debug-configuration';
import { DebugLogVisitor } from '../debugging/debug-log-visitor';
import { ExecutionContext } from '../execution-context';
import { type ExecutionContext } from '../execution-context';
import { IOTypeImplementation } from '../types/io-types/io-type-implementation';

import * as R from './execution-result';
Expand Down
5 changes: 2 additions & 3 deletions libs/execution/src/lib/blocks/composite-block-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import {
isCompositeBlocktypeDefinition,
} from '@jvalue/jayvee-language-server';

import { ExecutionContext } from '../execution-context';
import { IOTypeImplementation } from '../types';
import { type ExecutionContext } from '../execution-context';
import { type IOTypeImplementation } from '../types';

// eslint-disable-next-line import/no-cycle
import { executeBlocks } from './block-execution-util';
import { AbstractBlockExecutor, BlockExecutor } from './block-executor';
import { BlockExecutorClass } from './block-executor-class';
Expand Down
1 change: 0 additions & 1 deletion libs/execution/src/lib/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@

export * from './block-executor';
export * from './block-executor-class';
export * from './block-executor-registry';
export * from './execution-result';
export * from './block-execution-util';
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only

import { strict as assert } from 'assert';

import {
ConstraintDefinition,
Registry,
isExpressionConstraintDefinition,
isTypedConstraintDefinition,
} from '@jvalue/jayvee-language-server';
import { assertUnreachable } from 'langium';

import { ConstraintExecutor } from './constraint-executor';
import { AllowlistConstraintExecutor } from './executors/allowlist-constraint-executor';
import { DenylistConstraintExecutor } from './executors/denylist-constraint-executor';
import { ExpressionConstraintExecutor } from './executors/expression-constraint-executor';
import { LengthConstraintExecutor } from './executors/length-constraint-executor';
import { RangeConstraintExecutor } from './executors/range-constraint-executor';
import { RegexConstraintExecutor } from './executors/regex-constraint-executor';
import { TypedConstraintExecutorClass } from './typed-constraint-executor-class';

export interface JayveeConstraintExtension {
registerConstraintExecutor(executorClass: TypedConstraintExecutorClass): void;

getConstraintExecutors(): TypedConstraintExecutorClass<ConstraintExecutor>[];

createConstraintExecutor(
constraint: ConstraintDefinition,
): ConstraintExecutor;
}

export class DefaultConstraintExtension
extends Registry<TypedConstraintExecutorClass>
implements JayveeConstraintExtension
{
constructor() {
super();

this.registerConstraintExecutor(AllowlistConstraintExecutor);
this.registerConstraintExecutor(DenylistConstraintExecutor);
this.registerConstraintExecutor(RegexConstraintExecutor);
this.registerConstraintExecutor(LengthConstraintExecutor);
this.registerConstraintExecutor(RangeConstraintExecutor);
}

registerConstraintExecutor(executorClass: TypedConstraintExecutorClass) {
this.register(executorClass.type, executorClass);
}

getConstraintExecutors() {
return this.getAll();
}

createConstraintExecutor(
constraint: ConstraintDefinition,
): ConstraintExecutor {
if (isTypedConstraintDefinition(constraint)) {
const constraintType = constraint.type.ref?.name;
assert(
constraintType !== undefined,
`Could not resolve reference to constraint type of ${constraint.name}`,
);
const constraintExecutor = this.get(constraintType);
assert(
constraintExecutor !== undefined,
`No executor was registered for constraint type ${constraintType}`,
);

return new constraintExecutor();
} else if (isExpressionConstraintDefinition(constraint)) {
return new ExpressionConstraintExecutor(constraint);
}
assertUnreachable(constraint);
}
}
65 changes: 0 additions & 65 deletions libs/execution/src/lib/constraints/constraint-executor-registry.ts

This file was deleted.

Loading

0 comments on commit f144c8c

Please sign in to comment.