-3

Can someone explain the part in the exports section, I seem to lost and stuck for a while. Starting from importPromise. It seems like there's a lot going on, such as arrow functions and map method. I can't see where the data flows from where to where.

const keystone = require('keystone');
const PostCategory = keystone.list('PostCategory');
const Post = keystone.list('Post');

const importData = [
    { name: 'A draft post', category: 'Keystone JS' },
    ...
];

exports = function (done) {
    const importPromise = importData.map(({ name, category }) => createPost({ name, category }));

    importPromise.then(() => done()).catch(done);
};

const categories = {};

const createPost = ({ name, category }) => {
    let postCategory = new PostCategory.model({ category });
    if (categories[category]) {
        postCategory = categories[category];
    }
    categories[category] = postCategory;
    const post = new Post.model({ name });
    post.category = postCategory._id.toString();
    return Promise.all([
        post.save(),
        postCategory.save()
    ]);
}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
nicerazer
  • 3
  • 5
  • 1
    Where did you find that code? It doesn't appear to work anyway - lacking a `Promise.all` call in that `exports` function – Bergi Jan 12 '19 at 10:39
  • So you know what an arrow function is and how it works, and you know what `map` is and does? Then what part of the line do you not understand, the destructuring and object literal? – Bergi Jan 12 '19 at 10:40
  • @Bergi It's a keystone appilcation and the code segment is from [link](https://keystonejs.com/documentation/database/application-updates/). I was pretty much lost because I'm pretty new to programming, that's why I don't really see where stuff goes to where. And yeah I learned the arrow function and map but combining all of them together made me quite confused. I am also not familiar with destructuring and object literal practices... – nicerazer Jan 14 '19 at 09:16

3 Answers3

0

Quite some ES6 magic involved :)

const importPromise = importData.map(({ name, category }) => createPost({ name, category }));

importdata is an array. What the map function on an array does is to take every item of the array and apply a function to it, then return a new array with all of the items in the original array, but modified. map function

Instead of writing .map(function(item) { ... } the preferred way of writing this in ES6 is with a fat arrow function, i.e. .map((item) => ...

The third bit of magic is called destructuring assignment. What it does is it takes an object in this case, and assigns the obj.name and obj.category to two new variables name and category. We can use those variables within our function as if we had called the function with two separate arguments.

Now remember our map function dictates we write a function that takes an array item as a parameter, and returns the modified item. So what we end up with is a map function looping through the arguments of importData, taking name and category of each item and calling another function createPost with them. The result of createPost is the new value of the item, and it all gets appended to an array of the same size as the old one, with the modified items.

importPromise.then(() => done()).catch(done);

createPost creates a promise out of each item. You can read more about Promise here. The .then method on a Promise takes functions as its argument; to be called when the promise returns (either with success or an error). The () => done() is simply a function in fat arrow syntax that takes no arguments and calls the done function. .catch takes a function as well (done is a function), and is executed when the promise returns an error. NB. this way the done function is called both on success and on error!

--and no, this code won't work because what we're creating on the first line with importPromise is not actually a promise, but an array of promises!

Good luck with reading up, and as Beri suggests it might be worthwhile translating the code to es5 to follow along.

D. Veen
  • 358
  • 3
  • 9
0

I don't know much about KeystoneJS. Anyway, here are my two cents:

const importData = [
  { name: 'A draft post', category: 'Keystone JS' },
  // ...
];

importData is an Array which holds a bunch of Object instances, each having a name and category key with String values. For me, it appears this is some "mock data", which is simply put there for testing purposes.

I shifted the next parts, because it makes the code more understandable.

This part:

const categories = {};

Looks to me like the person who wrote it tried to implement some form of "caching". The categories constant is a mere "container" to store posts in so they can be reused later instead of being recreated. The createPost function reveals the purpose of it if you read through it.

const createPost = ({ name, category }) => {
    let postCategory = new PostCategory.model({ category });
    if (categories[category]) {
        postCategory = categories[category];
    }
    categories[category] = postCategory;
    const post = new Post.model({ name });
    post.category = postCategory._id.toString();
    return Promise.all([
        post.save(),
        postCategory.save()
    ]);
}

The first if seems to be there to make use of the "caching" construct (const category), but the way it does it is a bit confusing. Here's how I'd refactor it:

const createPost = ({ name, category }) => {
    if (!categories[category]) {
        categories[category] = new PostCategory.model({ category });;
    }

    const post = new Post.model({ name });
    post.category = categories[category]._id.toString();

    return Promise.all([
        post.save(),
        categories[category].save()
    ]);
}

Finally for the exports part:

The module exports a function which awaits a callback as argument (done). It then tries to create a Promise from all the "posts" of the mock data (and - to my understanding - fails), by mapping the createPost function over it. The reason I think it fails is because Array.prototype.map doesn't return a Promise, it returns a new Array instance which doesn't have a then method (see next line). Instead of calling then, it should be a Promise.all again. When that final Promise succeeds (or fails), the callback is called with the result.

exports = function (done) {
    const importPromise = importData.map(({ name, category }) => createPost({ name, category }));

    importPromise.then(() => done()).catch(done);
};

Again, I'd rewrite it this way:

exports = function (done) {
    Promise.all(importData.map(createPost)).then(done).catch(done);
};

Or just return the final Promise and get rid of the done callback altogether.

David
  • 3,552
  • 1
  • 13
  • 24
-2

https://babeljs.io/repl

You can use this tool to translate.

Beri
  • 1