Giter Site home page Giter Site logo

map-factory's People

Contributors

blacksun1 avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jmac105 avatar lbodor avatar maherma-adg avatar midknight41 avatar singhs020 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

map-factory's Issues

alwaysSet not working for missing Array

Hello again,
I think I found a bug with the way alwaysSet interacts with a non existant array on the source object:

const createMapper = require("map-factory");

const srcWorking = [{ name: "Peter" }, { name: "Stevie" }];
const srcBroken = [];

const mapper = createMapper({ alwaysSet: true });
mapper.map("[].name").to("names");

const mappedWorking = mapper.execute(srcWorking);
const mappedBroken = mapper.execute(srcBroken);

// Expected+Actual Result: { names: [ 'Peter', 'Stevie' ] }
console.log(mappedWorking);

// Expected Result: { names: [] }
// Actual Result: {}
console.log(mappedBroken);

As I understood the setting, it should always set the target attribute, even if the source structure is not there at all:

alwaysSet: boolean
if true then nested structure will be created even if the source value was not available on the source object.

Anyway, kudos to you for providing this package and the quick support/fixes !

A chained mapper is not reusable

When using the chain method it seems that you cant reuse the mapper again.

  describe("when chain is called twice", () => {
    it("one call should not effect the other", done => {
      secondaryMapper.map("foo").to("bar");
      const actual1 = mapper("foo").chain(secondaryMapper).execute(source);
      expect(actual1).to.equal(expected);
      const actual2 = mapper("foo").chain(secondaryMapper).execute(source);
      expect(actual2).to.equal(expected);
      done();
    });
  });

the line expect(actual2).to.equal(expected); fails with the error:

Expected {} to equal specified value: { bar: 'bar' }
at /mnt/c/_stuff/code/github/map-factory/dist/test/chain-test.js:67:37

It was my understanding that you should be able to create a mapper then use it multiple times, unless im doing something wrong it looks like you cant do that when using the chain method.

Transformation gets triggered for missing field

Example Code:

const createMapper = require('map-factory');

const map = createMapper();

map
  .map("foo").to("foo")
  .map("foo").to("baz", foo => "val: " + foo);

const testObject = {
}

const result = map.execute(testObject);

console.dir(result); // { baz: 'val: null' }

IMHO, it feels a bit weird that a usual rule is not triggered for a missing field, but a transformation is.

The documentation also does not specify the expected behaviour, only thing i could find was:

Mapping is explicit so unmapped fields are discarded.

Array of undefined values should be not trigger a set or call a transform.

const map = createMapper();

const source = {
  "unit": {
  "levels": [{
    "name": "notEmpty",
    "number": 10,
    "size": {
      "measurement": "SqM",
      "value": 122
    }
  }, {
    "name": "notEmpty",
    "number": 10,
    "size": {
      "measurement": "SqM",
      "value": 122
    }
  }]
}
};

map("unit.levels[].useType").to("[].useType");

// This should return an empty array but it returns [null]
map.execute(src);

Parent object with null subfields

I have a scenario where the source data can return an object that has null subfields. Additionally, the source can return null parent objects. For example "injury":{ "subfield1": null, "subfield2" null }

"injury": null
I need the ability to map the null fields only if the "parent" object is not null. For example if injury: null then the subfields shouldn't be mapped because the parent object is null. Is there a way to accomplish this?

An in-range update of code is breaking the build 🚨

The devDependency code was updated from 5.2.2 to 5.2.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

code is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Commits

The new version differs by 2 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

TypeError: map_factory_1.default is not a function

I'm gettting this error while working with typescript

import createMapper from "map-factory";

const map = createMapper();

map("items[].items[].name")
.to("[].salesOrderLines[].lineType")
.set("[].salesOrderLines[].lineType", "Item");

const dest = map.execute(src);

console.log(dest);
`

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Array of array issue

var createMapper = require("map-factory")

var source = {
    foo: [
        {"name": "a", "things": ["a1", "a2"]},
        {"name": "b", "things": ["b1", "b2"]}
    ]
}
const mapper = createMapper();

mapper
  .map("foo[].name").to("bar[].label")
  .map("foo[].things[]").to("bar[].values[]");
 
const result = mapper.execute(source);

...which gives us this:

bar: [{
        label: "a",
        values: [
            ["a1", "a2", "b1", "b2"]
        ]
    },
    {
        label: "b"
    }
]

...but what's required is this:

bar: [{
        label: "a",
        values: ["a1", "a2"]
    },
    {
        label: "b",
        values: ["b1", "b2"]
    }
]

always property not working as expected

Hi,

In latest version of the map-factory, there is a support for calling transform even if its set to false at a global level. following is the code mentioned in docs:

const createMapper = require("map-factory");
 
const mapper = createMapper(options);
 
mapper
  .map("a").always.to("b")

This does not seems to work. Could you please verify this?

Regards
Simranjeet Singh

Improve Documentation

  • Better descriptions
  • Summary of features
  • Define best way to deal with multiple input objects.

ref parent's property inside array

Hi, assume i have this mapper

var mapFactory = require("map-factory")

const options = {
  alwaysTransform: false,
  alwaysSet: true,
  flatten: false
};

const source = {
        my: {
            deep : {
                object: {name: 'john'},
                value : 'abc',
                parentId: 'xxx',
                array : [
                    {
                        value: 1,
                        name : 'a',
                        skus : [
                            {name: 'sku-1'},
                            {name: 'sku-2'}
                        ]
                    },
                    {
                        value: 2, 
                        name: 'b',
                        skus : [
                            {name: 'sku-3'},
                            {name: 'sku-4'}
                        ]
                    }
                ]
            },
            other: {
                array: [4, 5, 6]
            }
        }
    };

const mapper = mapFactory(options);

mapper
  .map("my.deep.value").to("example.basic.value")
  .map("my.deep.object").to("example.basic.object")
  .map("my.deep.array[0]").to("example.complex.first")
  .map("my.deep.array[].name").to("example.complex.items[].x")
  .map("my.deep.array[].value").to("example.complex.items[].y")
  .map("my.deep.array[].skus[].name").to("example.complex.items[].sku")
  .map("my.deep.parentId").to("example.complex.items[].parentId")
  .map("my.other.array").to("example.complex.valueArray");
  
const actual = mapper.execute(source);

console.log(actual);

the result will be:

{
	example: {
		basic: {...},
		complex: {
			first: {...},
			items: [
				{x: "a", y: 1, sku: ["sku-1", "sku-2"], parentId: "xxx"},
				{x: "b", y: 2, sku: ["sku-3", "sku-4"]}
			]
			valueArray: [...]
		}		
	}
}

parentId only apply to first object in items

@singhs020
could you tech me how to apply parentId to all object in items ? like this:

{
	example: {
		basic: {...},
		complex: {
			first: {...},
			items: [
				{x: "a", y: 1, sku: ["sku-1", "sku-2"], parentId: "xxx"},
				{x: "b", y: 2, sku: ["sku-3", "sku-4"], parentId: "xxx"}
			]
			valueArray: [...]
		}		
	}
}

Thank you so much.

Proposals- Pipeline Transformation

Following are some proposals for pipeline transformations:-

  • sortAsc : Will sort the array in ascending order and returns the array
.map("foo").sortAsc();
// or
.map("foo").sortAsc(() => 1) // by passing in a comparator to sort
  • sortDsc: Will sort the array in descending order and returns the array
.map("foo").sortDsc();
// or
.map("foo").sortDsc(() => 1) // by passing in a comparator to sort
  • groupBy: Will group the results in the array and returns an object with the grouped property as key.
.map("foo").groupBy(() => 1); // by passing in the function to be utilised as an iterator for grouping.

@midknight41 : what are your thoughts on these?

Modify default behaviour of map-factory

The default behaviour of a mapper currently does a few things I don't like.

  • It creates structure even when no source value is found
  • It a transform is provided it will always call the transform.

I think the default behaviour should be:

  • transforms are not called if the source value is not available
  • structure is not created if the source value is not available

This is a breaking change so will be a semver major.

The existing behaviour will be supported by providing options to the createMapper() function.

const options = {
  alwaysTransform: true,
  alwaysSet: true
};

const mapper = createMapper(options);

Missing tag

It is usually good practice to add a tag with the version number of anything released. Could you add this for v0.1.1 please?

Reading the code with multiple readers feels a bit yucky.

The code reads well when you do a single map:

const map = new Mapper();

map("a").to("b");

const result = map.execute({a: "value"});

But not so good if you are using multiple mappers:

const postMapper = new Mapper();
const authorMapper = new Mapper();

// does read very nice without 'map'
postMapper("text").to("user.text");
authorMapper("name").to("user.name");

const posts = postMapper.execute({"text": "value"});
const result = authorMapper.execute({"name": "Tim the Enchanter"}, posts);

It would read better if we also supported:

const postMapper = new Mapper();
const authorMapper = new Mapper();

// does read very nice without 'map'
postMapper.map("text").to("user.text");
authorMapper.map("name").to("user.name");

const posts = postMapper.execute({"text": "value"});
const result = authorMapper.execute({"name": "Tim the Enchanter"}, posts);

inconsistent behaviour of Pipeline transformation for multiple sources

Consider following:

var mapFactory = require("map-factory")

var mapper = mapFactory();

mapper.map(["a", "b"]).compact().to("2", (a, b) => {
console.log(a);
console.log(b);
}).execute({
"a": [null, null],
"b": ["q", null]
});

The expected should be either it should work on both the sources or it should throw an error for multiple sources.

transform arguments are not passed correctly

When I execute the following code:

var createMapper = require("map-factory")

const testObject = {
    item: [
        {foo: true, bar: null},
        {foo: null, bar: null}
    `]`
}

function transform(input) {
    console.log(input)
}

const map = createMapper({alwaysTransform: true})
map('item.foo').to('foo', transform)
map('item.bar').to('bar', transform)
map.execute(testObject)

I would expect to get [true, null] as a transform argument for the foo mapping and [null, null] for the bar mapping. The problem is, I noticed when all the occurrences of an object's property in an array are null, we instead get undefined. So in this case we get [true, null] and undefined.

This way, using my custom transform I cannot transform the value of bar, as I cannot infer the length of the array from undefined. I think just passing the [null, null] array would be a better solution, as it gives more possibilities to map the null value in the custom transform.

The reason for this seems to be this part of the ./src/lib/object-mapper/get-key-value.js :

function scanArrayForValue_(arrayToScan, defaultValue) {

  for (const item of arrayToScan) {
    if (item !== undefined && item !== null) {
      return defaultValue;
    }
  }

  return undefined;

}

Allow for chaining

This should work:

const mapper = createMapper();

mapper
   .map("a")
   .map("b").to("c")
   .execute(source);

It would improve the readability in cases where you need to reference the mapper like inside a class.

Feature Request: Allow generation and multiple use of Mapper Schema

Hey,

Would be great to be able to use something like this

function pointSchemaFactory() {

  const map = CreateMapper() // No source object goes in here
  map("x").to("point.x");
  map("y").to("point.y");

  return map;
}

const pointMapper = pointSchemaFactory();
assert.deepEqual(pointMapper({x: 100, y: 100}, {point: {x: 100, y: 100});
assert.deepEqual(pointMapper({x: 50, y: 100}, {point: {x: 50, y: 100});
assert.deepEqual(pointMapper({x: 50, y: 50}, {point: {x: 50, y: 50});
assert.deepEqual(pointMapper({x: 100 y: 50}, {point: {x: 100, y: 50});

Where the mapping is reusable rather than having a function that creates the mapping before executing it every time the source is different.

Field with getter function is not mapped

When trying to map a field with a getter property, map-factory does not properly return the field.

Reproduction

const map = require("map-factory")();

const objectWithGetter = {
  get field() {
    console.log("getter called");
    return "foo";
  }
};

map("field");
console.log("mapped:", map.execute(objectWithGetter));

Expected Result

Console Output

executed getter
mapped: { field: "foo" }

Actual Result

Console Output

executed getter
mapped: {}

how to change?

const source = {
        "menu_options": [
            {
                "name": "optionnnnnnnnn",
                "items": [
                    {
                        "price": 0,
                        "quantity": 1,
                        "name": "item1"
                    },
                    {
                        "price": 0,
                        "quantity": 1,
                        "name": "item2"
                    }
                ]
            }
        ]
      };

const expected = {
        "options": [
            {
                "group": "optionnnnnnnnn",
                "name": "item1",
                "quantity": 1,
                "price": 0
            },
            {
                "group": "optionnnnnnnnn",
                "name": "item2",
                "quantity": 1,
                "price": 0
            }
          ]
      }

i want that 2 depth to 1 depth. But i don't get the property [menu_options.name] from 1 depth.
sorry. i can't speak English well.

I hope you solve this problem

Why should be mapped object always new?

Why don't we pass destination object as well, so that destination object can be enriched with mapped data? Practically it helps a lot in my use cases.

something like,
map.execute(source, destination);

However, keep supporting map.execute(source);

Mapping

How would you map the source to the result below? Any help would be appreciated.

Source:

Source = {
  "test": ["a","b","c"]
}

"a" maps to "johnny"
"b" maps to "mark"
"c" maps to "bobby"

Result = {
"result": [
{"test": "johnny"},
{"test": "mark"},
{"test": "bobby"}
]}

set is not allowed when used after the map method

mapper
        .map()
        .set("foo", "bar")
        .set("fooFunc", () => "bar");

The above code throws an error i.e. "set is not a function".

Expected behaviour: It should work like set works in other scenarios.

alwaysSet with empty Array only works as first specified mapping

Hi,

I am trying to copy an array between two objects. To works fine for Arrays with at least one object, if I understood the docs, to copy empty arrays I have to use the alwaysSet field.

This properly sets the field on the destination object, but only if the mapping was the first specified.

Code to Reproduce

const mapFactory = require("map-factory");

const mapFirst = mapFactory({ alwaysSet: true });
const mapLast = mapFactory({ alwaysSet: true });

const source = {
  foo: 0,
  bar: []
};

mapFirst
  .map("bar").to("bar[]")
  .map("foo");

mapLast
  .map("foo")
  .map("bar").to("bar[]");

console.log("Mapping First:", mapFirst.execute(source));
console.log("Mapping Last:", mapLast.execute(source));

Expected Output

Mapping First: { bar: [], foo: 0 }
Mapping Last: { foo: 0, bar: [] }

Actual Output

Mapping First: { bar: [], foo: 0 }
Mapping Last: { foo: 0 } // Missing bar

Mapping the same field twice

Hey,

I have this and I can't remember how to overcome it

const passMapper = CreateMapper();
passMapper.map('device.Id').to('device')
passMapper.map('device.id').to('deviceDetails.id');
const result = passMapper.execute({ device: { id: 1 }});
assert(result.deviceDetails.id); // Passes
assert(result.device); // Fails!!!!

I remember there was a hack to map the same thing twice but I can't remember what it was

Help me Obi Wan

Regarads,

throws an error when the path in source is not available

consider following: -

var mapFactory = require("map-factory")

var mapper = mapFactory();

mapper.map("a.b[0].c").to("c").execute({
    "a":  {
    "d": 2
  }
})

The above code throws an error: "TypeError: Cannot read property '0' of undefined".

Expected: it should not throw error and should not map anything as well like the usual behaviour of the package.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.