function from(columns, objects) {
if (Array.isArray(columns)) [columns, objects] = [objects, columns];
const atleastOneArgumentGiven = !!columns || !!objects;
const columnsIsRightType =
!columns || (columns instanceof Object && !Array.isArray(columns));
const objectsIsRightType = !objects || Array.isArray(objects);
if (!(atleastOneArgumentGiven && columnsIsRightType && objectsIsRightType))
throw new TypeError(
"Bad arguments, should be one array of objects or one object of columns or both in any order"
);
const length = (objects ?? Object.values(columns).at(0))?.length;
const marker = Symbol();
return {
length,
*[Symbol.iterator]() {
let i = 0;
const proxy = new Proxy(
{},
{
get(_, prop) {
if (prop === marker) return true;
return columns && prop in columns
? columns[prop]?.[i]
: objects?.[i]?.[prop];
},
ownKeys(_) {
return (columns ? Object.getOwnPropertyNames(columns) : []).concat(
objects && objects[i]
? Object.getOwnPropertyNames(objects[i])
: []
);
},
has(_, prop) {
return this.ownKeys().includes(prop);
},
getOwnPropertyDescriptor(_, prop) {
return {
enumerable: true,
configurable: true,
value: this.get(0, prop)
};
}
}
);
for (; i < length; ++i) yield proxy;
},
where(predicate) {
const prev = this;
return {
...this,
*[Symbol.iterator]() {
for (const it of prev) if (predicate(it)) yield it;
}
};
},
select(selector) {
const prev = this;
return {
...this,
*[Symbol.iterator]() {
for (const it of prev) yield selector(it);
}
};
},
array(type = Array) {
return type.from(this, (it) => (it[marker] ? { ...it } : it));
},
map(f) {
return this.select(f);
},
filter(p) {
return this.where(p);
}
};
}