Skip to content

Instantly share code, notes, and snippets.

@wmakeev
Last active January 24, 2023 13:38
Show Gist options
  • Save wmakeev/901fb095643c64388c30b6a0c2929f0d to your computer and use it in GitHub Desktop.
Save wmakeev/901fb095643c64388c30b6a0c2929f0d to your computer and use it in GitHub Desktop.
[МойСклад - entity streams] #moysklad #stream #generator
/**
* Возвращает товары способом обычного листания
*
* @param {import('moysklad').Instance} ms
* @param {string} path
* @param {import('moysklad').Query} query
*/
export async function* getDocumentsStream(ms, path, query) {
/** @type {string | undefined} */
let nextHref = ms.buildUrl(path, query)
while (nextHref) {
/** @type {{ meta: { nextHref: string | undefined }; rows: any[] }} */
const coll = await ms.GET(nextHref)
nextHref = coll.meta.nextHref
for (const p of coll.rows) yield p
}
}
/**
* Возвращает товары способом обычного листания
*
* @param {Context} ctx
*/
export async function* getProductsStream({ moysklad: { instance: ms } }) {
/** @type {MoyskladQuery} */
const query = {
filter: {
isArchived: [true, false],
},
order: "updated,desc",
limit: 1000,
};
/** @type {string | undefined} */
let nextHref = ms.buildUrl("entity/product", query);
while (nextHref) {
/** @type {MoyskladCollection<MoyskladProduct>} */
const coll = await ms.GET(nextHref);
nextHref = coll.meta.nextHref;
for (const p of coll.rows) yield p;
}
}
// gist: https://gist.github.com/wmakeev/901fb095643c64388c30b6a0c2929f0d/#file-getproductsstream-updated-js
// source: /@vensi/vensi-moysklad-product-photo-miniature-upload/src/data/getProductsStream.js
import Moysklad from "moysklad";
import pRetry from "p-retry";
import { env } from "../env.js";
import { onFailedAttempt } from "../tools/onFailedAttempt.js";
const { getTimeString } = Moysklad;
/**
* Возвращает товары с перебором по дате обновления
*
* @param {Context} ctx
*/
export async function* getProductsStream({ moysklad: { instance: ms } }) {
const NOW = getTimeString(new Date());
/** До какого момента получать товары при обратной сотрировке по updated */
const DESC_ORDER_TO = getTimeString(
new Date(
Date.now() - 1000 * 3600 * 24 * 30 * (env.LONG_TIME_PERIOD_MONTHS + 1)
)
);
/** @type {string | undefined} */
let lastUpdated =
env.MOYSKLAD_ORDER === "asc" ? env.MOYSKLAD_ORDER_ASC_TIME_FROM : NOW;
while (lastUpdated) {
const logCaption = `getProductsStream ${env.MOYSKLAD_ORDER} from ${lastUpdated}`;
console.time(logCaption);
/** @type {import('moysklad').Query} */
const query = {
filter: {
archived: [true, false],
updated: {
...(env.MOYSKLAD_ORDER === "asc"
? { $gt: lastUpdated, $lt: NOW }
: { $gt: DESC_ORDER_TO, $lt: lastUpdated }),
},
},
order: `updated,${env.MOYSKLAD_ORDER}`,
limit: 1000,
};
/** @type {() => Promise<MoyskladCollection<MoyskladProduct>>} */
const task = () => ms.GET("entity/product", query);
const coll = await pRetry(task, { retries: 3, onFailedAttempt });
console.timeEnd(logCaption);
for (const p of coll.rows) yield p;
lastUpdated = coll.rows.at(env.MOYSKLAD_ORDER === "asc" ? -1 : 1)?.updated;
}
}
/**
* Обработчки ошибки
*
* @param {import('p-retry').FailedAttemptError} error
*/
export const onFailedAttempt = error => {
console.log(
`${error.message} (attempt ${error.attemptNumber} failed` +
` ${error.retriesLeft} retries left)`
)
}
type MoyskladQuery = import("moysklad").Query;
type MoyskladCollection<T> = import("moysklad-api-model").Collection<T>;
type MoyskladProduct = import("moysklad-api-model").Product;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment