bentonam / fakeit

Generates JSON documents based on models defined in YAML and adds them to a Couchbase Bucket
MIT License
86 stars 21 forks source link

Allow array size to be dynamically defined #135

Open brantburnett opened 7 years ago

brantburnett commented 7 years ago

Currently, the pre_run function is only available at the top level of the model, not within the model on array types. Therefore, the only sizing option for arrays is count or min/max, it's not possible to dynamically set the size on a per-document basis based on some input.

For example, in my use case:

  1. Document A has an array B with some elements, random size using min/max
  2. Document C is related to document A, but also has an array D. Elements in D must be a subset of elements in B.
  3. I can't vary the size of array D based on the number of elements in array B of the linked Document A.

It seems like pre_run could be enabled on arrays:

name: documents
type: object
key: keyId
properties:
  mappings:
    type: array
    items:
      type: object
      data:
        pre_run: |
          this.data.count = someCalculationHere;
      properties:
        name:
          build: "someCalculationHere"

Within the pre_run function, the this context could be set to be the sub-context of the items model within the array. Also, some way to get data from the parent document would be helpful. Perhaps add document to the context to reference the current root document being generated.

mistersender commented 7 years ago

I am reasonably certain this is possible. In your example above your name field is set to documents, but i believe it should be set to a more understandable name. The documents namespace is available, and contains all documents as arrays in your collection, generated by the name field. so if you had

name: a
type: object
..

you could use documents.a[0] to retrieve the first document it generated for a along with the values it generated, therefore allowing you access to your array.

name: c
type: object
key: _id
data:
  dependencies:
    - a
  pre_run: |
    this.data.fixed = documents.a.length; // forces the same number of documents as "a" generated

  pre_build: |
    var current = documents.a[document_index]; // chooses the same "a" document
    var my_array_length = current.b.length // get the length of b index
..
brantburnett commented 7 years ago

@mistersender

Your approach works for basing the root document on the dependency, but not for an array within the document being defined.

I was able to get it to work using this approach:

name: passTypeMappings
type: object
key: keyId
seed: 165156
data:
  dependencies:
    - siteGroups.yml
  pre_run: |
    this.data.count = documents.siteGroups.length*2;
properties:
  keyId:
    data:
      post_build: `passTypeMapping-${this.siteGroupId}-${this.mappingId}`
  type:
    data:
      value: "passTypeMapping"
  siteGroupId:
    data:
      build: |
        globals.temp = documents.siteGroups[Math.floor(document_index/2)];
        return documents.siteGroups[Math.floor(document_index/2)].siteGroupId;
  mappingId:
    data:
      build: "chance.guid()"
  description:
    data:
      fake: "{{commerce.productName}}"
  mappings:
    data:
      build: |
        var mappings = [],
            locations = documents.siteGroups[Math.floor(document_index/2)].locations;
        for (var i=0; i<locations.length; i++) {
            mappings.push({
                locationId: locations[i],
                passTypeId: chance.guid()
            });
        }
        return mappings;

Basically, I have to use build on the array property directly, without an items definition. While this works, it seems cumbersome as you can't use any of the easier-to-read YAML syntax building the array.

Brant

tjbenton commented 7 years ago

I noticed this same issue when I was going through and refactoring to make this library testable. @brantburnett that is a cumbersome way to create a custom dynamic data length, but now it works as a temporary work around until we can get a fix out there for this.