Skip to content

Commit

Permalink
[FEATURE] Context Referencing Shortcut (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
vojtechpavlu authored Apr 4, 2024
1 parent fa18185 commit 8f9c2ca
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 111 deletions.
9 changes: 2 additions & 7 deletions docs/docs/System-Documentation/Generators/09_ip_addresses.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@

This generator is responsible for generating random IP Address (v4) in a given range per each octet.


## Configuration


!!! example

```typescript linenums="1"
const config: IPAddressConfig = {
octet1: { min: 10, max: 12 },
octet2: { min: 1, max: 32 },
octet3: { min: 1, max: 254 },
octet4: { min: 1, max: 254 }
}
octet4: { min: 1, max: 254 },
};
```


## Examples

=== "Instance access"
Expand Down Expand Up @@ -89,5 +86,3 @@ const config: IPAddressConfig = {
```
{ value: '12.16.131.227' }
```


Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ generated by [Value Generators](../../Building-Blocks/03_value-generator.md).
Each Value Pipe can be described as this:

```typescript
type ValuePipe = (value: GeneratedValue) => GeneratedValue
type ValuePipe = (value: GeneratedValue) => GeneratedValue;
```

Simply put, it's technically just a function performing a modification
Expand Down Expand Up @@ -194,7 +194,6 @@ it will try to use it.
This example uses [Constant Value Generator](../../Generators/08_constants.md).
You may want to check it out :wink:

### Registration of Custom Value Pipes

However, at some places, you might think that some functions are kind of
Expand Down
7 changes: 4 additions & 3 deletions docs/docs/System-Documentation/Standards/00_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ To describe to the [Fabricator](../Building-Blocks/04_fabricator.md) you want to
generator in your schema, you only need to attach the standard's name to the field.

!!! example
``` typescript linenums="1"

````typescript linenums="1"
const schema: SchemaInput = {
fields: {
myStandardField: 'some-standard-name',
Expand Down Expand Up @@ -55,7 +56,7 @@ be sealed (can be a new one or an existing one).

This is just a simple generator always returning a value `'Hello World!'` - nothing useful but can show the basics.

``` typescript linenums="1"
```typescript linenums="1"
class HelloWorldStandard extends ConstantValue {
constructor(config: ValueGeneratorConfig) {
super({ ...config, value: "Hello World!" });
Expand All @@ -81,7 +82,7 @@ function. This is basically a function defined like this:

```typescript
export type StandardValueGeneratorBuilder = () => StandardValueGenerator;
```
````
This means the builder function is just returning your Standard Value Generator on demand (on invocation). To
actually perform the registration, pick a unique name and store it like this:
Expand Down
75 changes: 75 additions & 0 deletions docs/docs/System-Documentation/Standards/99_context-accessing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Context Accessing Shortcut

To simplify the context accessing and its definition, there's a shortcut notation defined.
This type of declaration was chosen to enable simplicity of the schema definition based on
more dynamic schema compilation approach.

Instead of somewhat statically typed names of standards, this approach lets you pass configuration
as a part of the name to your Field declaration.

This notation is based on two parts - `!ref-<<path>>`, where the `<<path>>` is the path in the
given context object using dots (`.`) as separators.

!!! example

In this example, you can see how you can access the desired value by specifying the path through the
Fabrication Context object.

```
const context = {
myField: {
myValue: 'some-value'
}
};

const valueGenerator = getStandard('!ref-myField.myValue');

const generatedValue = valueGenerator.generate(context);
```

!!! abstract "Output"

```
'some-value'
```

Here's a full demonstration of how the shortcut can be used:

!!! example

You can declare your schema with usage of identifiers [profile](../Profiles/00_introduction.md).
This profile passes pregenerated values into a context object accessible to each value generator,
so you can easily access it.

You can also specify other fields; in this case `addressId` field - to take a value from given
context object passed during the fabrication. This can be useful for example when you are generating
instances of multiple entities linked by foreign keys.

```typescript linenums="1"
// Declare your schema
const schema: SchemaInput = {
profiles: ['identifiers'],
fields: {
userId: '!ref-profiles.identifiers.uuid',
addressId: '!ref-addressId',

// ... another fields ...
}
};

// Create a Fabricator instance
const fabricator = new Fabricator(schema);

// Generate a Falsum object with specified context
const generated: Falsum = fabricator.generate({
addressId: 123456
});

console.log(generated);
```

!!! abstract "Output"

```
{ userId: 'f85d6bc3-1391-488b-90ad-8a114d1be5be', addressId: 123456 }
```
8 changes: 5 additions & 3 deletions src/generators/ValueGeneratorRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ import {
ConstantValue,
ConstantValueConfig,
ContextAccessor,
ContextAccessorConfig, IPAddressConfig, IPAddressValueGenerator,
ContextAccessorConfig,
IPAddressConfig,
IPAddressValueGenerator,
XORConfiguration,
XORGenerator
XORGenerator,
} from './other';
import {
ProbableBooleanGenerator,
Expand Down Expand Up @@ -76,7 +78,7 @@ interface ValueGeneratorRegistry<
/** Return all the registered Value Generator names */
export const getAllValueGeneratorNames = () => {
return Object.keys(VALUE_GENERATOR_REGISTRY);
}
};

/**
* Tries to find a builder for value generator by the given name and builds it
Expand Down
45 changes: 29 additions & 16 deletions src/generators/other/IPAddressGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import {
GeneratedValue,
ValueGenerator,
ValueGeneratorConfig
ValueGeneratorConfig,
} from '../ValueGenerator';
import { StringTemplateGenerator } from '../string';
import { IntegerGenerator } from '../numeric';

/** Definition of an octet */
interface OctetDefinition {
min: number,
max: number,
min: number;
max: number;
}

/** Helper for easier referencing */
interface IPAddressConfigHelper {
[octet: string]: OctetDefinition
[octet: string]: OctetDefinition;
}

/**
Expand All @@ -25,7 +25,8 @@ export type IPAddressConfig = {
octet2: OctetDefinition;
octet3: OctetDefinition;
octet4: OctetDefinition;
} & ValueGeneratorConfig & IPAddressConfigHelper;
} & ValueGeneratorConfig &
IPAddressConfigHelper;

/**
* This generator simply returns a string representing an IPv4 address.
Expand All @@ -34,20 +35,20 @@ export class IPAddressValueGenerator extends ValueGenerator<
GeneratedValue,
IPAddressConfig
> {

private readonly generator;

constructor(config: IPAddressConfig) {

const octetNames = ["octet1", "octet2", "octet3", "octet4"];
const octetNames = ['octet1', 'octet2', 'octet3', 'octet4'];

octetNames.forEach((octetName) => {
if (config[octetName]!.min < 0) {
throw new Error(`Every octet has to have minimum positive`)
throw new Error(`Every octet has to have minimum positive`);
} else if (config[octetName]!.max > 255) {
throw new Error(`Every octet has to have maximum <= 255`)
throw new Error(`Every octet has to have maximum <= 255`);
} else if (config[octetName]!.min > config[octetName]!.max) {
throw new Error(`Every octet's minimum value has to be less or equal to max`)
throw new Error(
`Every octet's minimum value has to be less or equal to max`,
);
}
});

Expand All @@ -62,11 +63,23 @@ export class IPAddressValueGenerator extends ValueGenerator<
this.generator = new StringTemplateGenerator({
template: '{o1}.{o2}.{o3}.{o4}',
variables: {
o1: new IntegerGenerator({ min: this.config.octet1.min, max: this.config.octet1.max }),
o2: new IntegerGenerator({ min: this.config.octet2.min, max: this.config.octet2.max }),
o3: new IntegerGenerator({ min: this.config.octet3.min, max: this.config.octet3.max }),
o4: new IntegerGenerator({ min: this.config.octet4.min, max: this.config.octet4.max })
}
o1: new IntegerGenerator({
min: this.config.octet1.min,
max: this.config.octet1.max,
}),
o2: new IntegerGenerator({
min: this.config.octet2.min,
max: this.config.octet2.max,
}),
o3: new IntegerGenerator({
min: this.config.octet3.min,
max: this.config.octet3.max,
}),
o4: new IntegerGenerator({
min: this.config.octet4.min,
max: this.config.octet4.max,
}),
},
});
}

Expand Down
38 changes: 18 additions & 20 deletions src/pipes/falsum/FalsumPipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Falsum, ObjectFalsum } from '../../schema';
import { fieldsToCamel, fieldsToSnake } from './fieldNameCasing';
import {
addGeneratedTimestampDate,
addGeneratedTimestampNumber
addGeneratedTimestampNumber,
} from './generatedTimestamp';
import { pruneEmptyArrays, pruneNulls, pruneUndefined } from './falsumCleaners';
import { stringify, stringifyWithIndentation } from './stringification';
Expand All @@ -20,25 +20,25 @@ export type FalsumPipeName =
| string
// Field names modifications
| (
| 'snake-case-props'
| 'camel-case-props'
| 'snake-case-props'
| 'camel-case-props'

// Timestamps
| 'generated-timestamp-date'
| 'generated-timestamp-number'
// Timestamps
| 'generated-timestamp-date'
| 'generated-timestamp-number'

// Pruners
| 'prune-undefined'
| 'prune-null'
| 'prune-empty-arrays'
// Pruners
| 'prune-undefined'
| 'prune-null'
| 'prune-empty-arrays'

// Stringification
| 'stringify'
| 'stringify-indented'
// Stringification
| 'stringify'
| 'stringify-indented'

// Object Manipulation
| 'object-to-list'
);
// Object Manipulation
| 'object-to-list'
);

/**
* Registry used to store the commonly used Falsum Pipes
Expand Down Expand Up @@ -87,7 +87,7 @@ export const registerFalsumPipe = (name: string, pipe: FalsumPipe) => {
throw new Error(`Falsum Pipe not provided`);
} else if (hasFalsumPipe(name)) {
throw new Error(
`There already is one Falsum Pipe assigned to name '${name}'`
`There already is one Falsum Pipe assigned to name '${name}'`,
);
}

Expand All @@ -100,9 +100,7 @@ export const registerFalsumPipe = (name: string, pipe: FalsumPipe) => {
* @param name Name to be checked if is or is not already reserved.
*/
export const hasFalsumPipe = (name: string): boolean => {
return !!getAllFalsumPipeNames().find(
(pipeName) => pipeName === name
);
return !!getAllFalsumPipeNames().find((pipeName) => pipeName === name);
};

// Falsum field names modifications
Expand Down
30 changes: 15 additions & 15 deletions src/pipes/value/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ export type ValuePipeName =
| string
// String value pipes
| (
| 'stringify'
| 'trim'
| 'single-space'
| 'uppercase'
| 'lowercase'
| 'space-split'

// Sorting
| 'sort-ascending'
| 'sort-descending'

// Object manipulation
| 'object-to-list'
);
| 'stringify'
| 'trim'
| 'single-space'
| 'uppercase'
| 'lowercase'
| 'space-split'

// Sorting
| 'sort-ascending'
| 'sort-descending'

// Object manipulation
| 'object-to-list'
);

/**
* Declaration of Value Pipes Registry type
Expand Down Expand Up @@ -92,7 +92,7 @@ export const registerValuePipe = (name: ValuePipeName, pipe: ValuePipe) => {
throw new Error(`Name is required`);
} else if (hasValuePipe(name)) {
throw new Error(
`There already is one Value Pipe registered with name '${name}'`
`There already is one Value Pipe registered with name '${name}'`,
);
} else if (!pipe) {
throw new Error(`Pipe must be defined`);
Expand Down
11 changes: 8 additions & 3 deletions src/plugins/Plugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import {
GeneratedValue, registerStandard, registerValueGenerator,
GeneratedValue,
registerStandard,
registerValueGenerator,
StandardValueGeneratorBuilder,
ValueGeneratorBuilder,
ValueGeneratorConfig
ValueGeneratorConfig,
} from '../generators';
import { Charset, registerCharset } from '../utils';
import { ProfileFabricatorBuilder, registerProfileFabricator } from '../profiles/ProfileFabricatorRegistry';
import {
ProfileFabricatorBuilder,
registerProfileFabricator,
} from '../profiles/ProfileFabricatorRegistry';
import { FalsumPipe, registerFalsumPipe } from '../pipes';
import { registerValuePipe, ValuePipe } from '../pipes/value';

Expand Down
Loading

0 comments on commit 8f9c2ca

Please sign in to comment.