diff --git a/API.brand.md b/API.brand.md index 50d1dce..65827d2 100644 --- a/API.brand.md +++ b/API.brand.md @@ -21,6 +21,37 @@ Adds an image to a brand, processing it into AVIF full and thumb variants. `Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array}>` +## `brand.create` + +*Source: `src/store/brand/create.js`* + +Creates a brand for the user's selected company. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `input` | `object` | The brand input. | +| `input.name` | `string` | The brand name. | +| `[input.gsprpinfo]` | `string` | Optional GSPRP info. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>` — The created brand. + +**Throws** + +`Error` — If the brand is invalid or already exists. + +**Example** + +```js +const brand = await store.brand.create(42, { name: 'Coca-Cola', gsprpinfo: 'x' }); +// => { id, name, gsprpinfo, pics: [] } +``` + ## `brand.delete` *Source: `src/store/brand/delete.js`* @@ -73,6 +104,38 @@ const brands = await store.brand.list(42); // => [{ id, name, gsprpinfo, pics: [{ sort, fullHash, thumbW, thumbH, thumbHash }] }] ``` +## `brand.update` + +*Source: `src/store/brand/update.js`* + +Renames/updates a brand for the user's selected company by id. Touching `article.updated_at` for all articles linked via `brand_id` when the name actually changes, so list caches invalidate. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `id` | `number` | The id of the brand to update. | +| `input` | `object` | The update input. | +| `[input.name]` | `string` | The new brand name. | +| `[input.gsprpinfo]` | `string` | The new GSPRP info. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>` — The updated brand plus the number of linked articles whose `updated_at` was bumped. + +**Throws** + +`Error` — If the brand is not found, invalid, or the name is already taken. + +**Example** + +```js +const brand = await store.brand.update(42, 3, { name: 'Coca-Cola GmbH' }); +// => { id: 3, name, gsprpinfo, touchedArticleCount: 2 } +``` + ## `brand.upsert` *Source: `src/store/brand/upsert.js`* diff --git a/API.md b/API.md index 4e1db4f..5714dcf 100644 --- a/API.md +++ b/API.md @@ -130,8 +130,10 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met - `set(googleAuthId: number, input: {key: string, value: string, frontend?: boolean, writeonly?: boolean}, tx?: object): Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}>` - [brand](API.brand.md) - `addImage(googleAuthId: number, brandId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array}>` + - `create(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>` - `delete(googleAuthId: number, id: number, tx?: object): Promise` - `list(googleAuthId: number, tx?: object): Promise}>>` + - `update(googleAuthId: number, id: number, input: {name?: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>` - `upsert(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>` - [customergroup](API.customergroup.md) - `create(googleAuthId: number, input: {name: string}, tx?: object): Promise<{id: number, name: string, sort: number}>` diff --git a/src/index.js b/src/index.js index 05a69d9..b39e3ab 100644 --- a/src/index.js +++ b/src/index.js @@ -47,6 +47,8 @@ import companysettingList from './store/companysetting/list.js'; import companysettingGet from './store/companysetting/get.js'; import companysettingSet from './store/companysetting/set.js'; import brandList from './store/brand/list.js'; +import brandCreate from './store/brand/create.js'; +import brandUpdate from './store/brand/update.js'; import brandUpsert from './store/brand/upsert.js'; import brandDelete from './store/brand/delete.js'; import brandAddImage from './store/brand/addImage.js'; @@ -326,6 +328,8 @@ export default class LibDashStore { this.brand = { list: brandList(provider), + create: brandCreate(provider), + update: brandUpdate(provider), upsert: brandUpsert(provider), delete: brandDelete(provider), addImage: brandAddImage(provider), diff --git a/src/providers/sqlite3/schema.js b/src/providers/sqlite3/schema.js index 10fb1d2..65d9714 100644 --- a/src/providers/sqlite3/schema.js +++ b/src/providers/sqlite3/schema.js @@ -10,14 +10,14 @@ INSERT OR IGNORE INTO meta ("key", value) VALUES ('version', '1'); export const INIT_LANGUAGE = ` CREATE TABLE IF NOT EXISTS language ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, iso639 TEXT NOT NULL COLLATE NOCASE UNIQUE ); `; export const INIT_TAX = ` CREATE TABLE IF NOT EXISTS tax ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, rate NUMERIC NOT NULL UNIQUE ); INSERT OR IGNORE INTO tax (rate) VALUES (0), (7), (19); @@ -25,7 +25,7 @@ INSERT OR IGNORE INTO tax (rate) VALUES (0), (7), (19); export const INIT_CATEGORY = ` CREATE TABLE IF NOT EXISTS category ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, parent_id INTEGER, sort INTEGER NOT NULL DEFAULT 0, updated_at TEXT NOT NULL DEFAULT (${UTC_NOW}), @@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS category ( export const INIT_PIC = ` CREATE TABLE IF NOT EXISTS pic ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, w INTEGER NOT NULL, h INTEGER NOT NULL, size INTEGER NOT NULL, @@ -49,7 +49,7 @@ CREATE TABLE IF NOT EXISTS pic ( export const INIT_COMPANY = ` CREATE TABLE IF NOT EXISTS company ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL COLLATE NOCASE UNIQUE, root_category_id INTEGER, default_language_id INTEGER, @@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS company ( export const INIT_GOOGLE_AUTH = ` CREATE TABLE IF NOT EXISTS google_auth ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL COLLATE NOCASE UNIQUE, picture TEXT, picturebinary BLOB, @@ -83,7 +83,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS UQ_google_auth_sub export const INIT_CUSTOMERGROUP = ` CREATE TABLE IF NOT EXISTS customergroup ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, sort INTEGER NOT NULL DEFAULT 0, company_id INTEGER, @@ -97,7 +97,7 @@ export const INIT_COMPANY_POS_CUSTOMERGROUP_FK = ''; export const INIT_ENTITY = ` CREATE TABLE IF NOT EXISTS entity ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, customergroup_id INTEGER NOT NULL, company_id INTEGER, first_name TEXT, @@ -140,7 +140,7 @@ END; export const INIT_ENTITYADDRESS = ` CREATE TABLE IF NOT EXISTS entityaddress ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, entity_id INTEGER NOT NULL, first_name TEXT, name TEXT, @@ -157,7 +157,7 @@ CREATE TABLE IF NOT EXISTS entityaddress ( export const INIT_ENTITYCONTACT = ` CREATE TABLE IF NOT EXISTS entitycontact ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, entity_id INTEGER NOT NULL, contacttype TEXT NOT NULL, contact TEXT NOT NULL, @@ -168,7 +168,7 @@ CREATE TABLE IF NOT EXISTS entitycontact ( export const INIT_UNIT = ` CREATE TABLE IF NOT EXISTS unit ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, si TEXT NOT NULL, basesi TEXT NOT NULL, @@ -180,7 +180,7 @@ CREATE TABLE IF NOT EXISTS unit ( export const INIT_UNITTEXT = ` CREATE TABLE IF NOT EXISTS unittext ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, unit_id INTEGER NOT NULL, language_id INTEGER NOT NULL, symbol TEXT NOT NULL, @@ -192,16 +192,16 @@ CREATE TABLE IF NOT EXISTS unittext ( `; export const INIT_OPTIONSLIST = ` -CREATE TABLE IF NOT EXISTS optionslist (id INTEGER PRIMARY KEY); +CREATE TABLE IF NOT EXISTS optionslist (id INTEGER PRIMARY KEY AUTOINCREMENT); `; export const INIT_ARTICLELIST = ` -CREATE TABLE IF NOT EXISTS articlelist (id INTEGER PRIMARY KEY); +CREATE TABLE IF NOT EXISTS articlelist (id INTEGER PRIMARY KEY AUTOINCREMENT); `; export const INIT_BRAND = ` CREATE TABLE IF NOT EXISTS brand ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, gsprpinfo TEXT, @@ -212,7 +212,7 @@ CREATE TABLE IF NOT EXISTS brand ( export const INIT_ARTICLE = ` CREATE TABLE IF NOT EXISTS article ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, sku TEXT COLLATE NOCASE, unit_id INTEGER NOT NULL, @@ -244,7 +244,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS UQ_article_parentarticle_parentsort export const INIT_ARTICLEEAN = ` CREATE TABLE IF NOT EXISTS articleean ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, ean TEXT NOT NULL, FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE @@ -257,7 +257,7 @@ CREATE INDEX IF NOT EXISTS IX_articleean_ean export const INIT_ARTICLEPIC = ` CREATE TABLE IF NOT EXISTS articlepic ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, pic_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -270,7 +270,7 @@ CREATE TABLE IF NOT EXISTS articlepic ( export const INIT_BRANDPIC = ` CREATE TABLE IF NOT EXISTS brandpic ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, brand_id INTEGER NOT NULL, pic_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -283,7 +283,7 @@ CREATE TABLE IF NOT EXISTS brandpic ( export const INIT_ARTICLELISTARTICLE = ` CREATE TABLE IF NOT EXISTS articlelistarticle ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, articlelist_id INTEGER NOT NULL, article_id INTEGER NOT NULL, count INTEGER NOT NULL DEFAULT 1, @@ -297,7 +297,7 @@ CREATE TABLE IF NOT EXISTS articlelistarticle ( export const INIT_OPTIONSLISTARTICLE = ` CREATE TABLE IF NOT EXISTS optionslistarticle ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, optionslist_id INTEGER NOT NULL, article_id INTEGER NOT NULL, count INTEGER NOT NULL DEFAULT 1, @@ -312,7 +312,7 @@ CREATE TABLE IF NOT EXISTS optionslistarticle ( export const INIT_CATEGORYARTICLE = ` CREATE TABLE IF NOT EXISTS categoryarticle ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, article_id INTEGER NOT NULL, UNIQUE (category_id, article_id), @@ -325,7 +325,7 @@ CREATE INDEX IF NOT EXISTS IX_categoryarticle_article_category export const INIT_CATEGORYPIC = ` CREATE TABLE IF NOT EXISTS categorypic ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, pic_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -338,7 +338,7 @@ CREATE TABLE IF NOT EXISTS categorypic ( export const INIT_CATEGORYTEXT = ` CREATE TABLE IF NOT EXISTS categorytext ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, language_id INTEGER NOT NULL, name TEXT NOT NULL, @@ -353,7 +353,7 @@ CREATE TABLE IF NOT EXISTS categorytext ( export const INIT_ARTICLENAME = ` CREATE TABLE IF NOT EXISTS articletext ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, language_id INTEGER NOT NULL, name TEXT NOT NULL, @@ -368,7 +368,7 @@ CREATE TABLE IF NOT EXISTS articletext ( export const INIT_PRICE = ` CREATE TABLE IF NOT EXISTS price ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, tax_id INTEGER NOT NULL, article_id INTEGER NOT NULL, minmultiplier NUMERIC NOT NULL DEFAULT 1, @@ -384,7 +384,7 @@ CREATE INDEX IF NOT EXISTS IX_price_article_cg_mult export const INIT_ARTICLE_SUPPLIER = ` CREATE TABLE IF NOT EXISTS articlesupplier ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, entity_id INTEGER NOT NULL, net REAL, @@ -405,7 +405,7 @@ CREATE INDEX IF NOT EXISTS IX_articlesupplier_article_entity export const INIT_MANIFEST = ` CREATE TABLE IF NOT EXISTS manifest ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, "number" TEXT NOT NULL, "type" TEXT NOT NULL, @@ -420,7 +420,7 @@ CREATE TABLE IF NOT EXISTS manifest ( export const INIT_MANIFESTARTICLE = ` CREATE TABLE IF NOT EXISTS manifestarticle ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, manifest_id INTEGER NOT NULL, sku TEXT, name TEXT, @@ -436,7 +436,7 @@ CREATE TABLE IF NOT EXISTS manifestarticle ( export const INIT_WAREHOUSE = ` CREATE TABLE IF NOT EXISTS warehouse ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, sort INTEGER NOT NULL DEFAULT 0, @@ -448,7 +448,7 @@ CREATE TABLE IF NOT EXISTS warehouse ( /* SQLite has no SQL Server ledger tables; constraints preserve the base shape. */ export const INIT_LEDGER = ` CREATE TABLE IF NOT EXISTS ledger ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, manifestarticle_id INTEGER NOT NULL, warehouse_id INTEGER, transaction_type TEXT NOT NULL, @@ -464,7 +464,7 @@ CREATE TABLE IF NOT EXISTS ledger ( export const INIT_NUMBERS = ` CREATE TABLE IF NOT EXISTS numbers ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, "type" TEXT NOT NULL, prefix TEXT NOT NULL DEFAULT '', @@ -477,7 +477,7 @@ CREATE TABLE IF NOT EXISTS numbers ( export const INIT_COMPANYUSER = ` CREATE TABLE IF NOT EXISTS companyuser ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, google_auth_id INTEGER NOT NULL, company_id INTEGER NOT NULL, UNIQUE (google_auth_id, company_id), @@ -488,7 +488,7 @@ CREATE TABLE IF NOT EXISTS companyuser ( export const INIT_MODELCONVERSATION = ` CREATE TABLE IF NOT EXISTS modelconversation ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, companyuser_id INTEGER NOT NULL, provider TEXT NOT NULL, model TEXT NOT NULL, @@ -503,7 +503,7 @@ CREATE INDEX IF NOT EXISTS IX_modelconversation_companyuser ON modelconversation export const INIT_MODELVFS = ` CREATE TABLE IF NOT EXISTS modelvfs ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL, mime TEXT NOT NULL, @@ -518,7 +518,7 @@ CREATE INDEX IF NOT EXISTS IX_modelvfs_company_name ON modelvfs (company_id, nam export const INIT_MODELMESSAGE = ` CREATE TABLE IF NOT EXISTS modelmessage ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, conversation_id INTEGER NOT NULL, created_at TEXT NOT NULL DEFAULT (${UTC_NOW}), role TEXT NOT NULL CHECK (role IN ('system', 'user', 'assistant', 'tool', 'reasoning', 'usage')), @@ -530,7 +530,7 @@ CREATE INDEX IF NOT EXISTS IX_modelmessage_conversation ON modelmessage (convers export const INIT_ARTICLEHISTORY = ` CREATE TABLE IF NOT EXISTS articlehistory ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, companyuser_id INTEGER, "date" TEXT NOT NULL DEFAULT (${UTC_NOW}), @@ -541,7 +541,7 @@ CREATE TABLE IF NOT EXISTS articlehistory ( `; export const INIT_COMPANYHISTORY = ` CREATE TABLE IF NOT EXISTS companyhistory ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, companyuser_id INTEGER, "date" TEXT NOT NULL DEFAULT (${UTC_NOW}), @@ -553,7 +553,7 @@ CREATE TABLE IF NOT EXISTS companyhistory ( export const INIT_ARTICLETOMBSTONE = ` CREATE TABLE IF NOT EXISTS articletombstone ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, article_id INTEGER, sku TEXT COLLATE NOCASE, @@ -570,7 +570,7 @@ CREATE INDEX IF NOT EXISTS IX_articletombstone_company_deleted export const INIT_ENTITYHISTORY = ` CREATE TABLE IF NOT EXISTS entityhistory ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, entity_id INTEGER NOT NULL, companyuser_id INTEGER, "date" TEXT NOT NULL DEFAULT (${UTC_NOW}), @@ -582,7 +582,7 @@ CREATE TABLE IF NOT EXISTS entityhistory ( export const INIT_COMPANYSETTING = ` CREATE TABLE IF NOT EXISTS companysetting ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, "key" TEXT NOT NULL, value TEXT NOT NULL, @@ -595,7 +595,7 @@ CREATE TABLE IF NOT EXISTS companysetting ( export const INIT_POSTERMINAL = ` CREATE TABLE IF NOT EXISTS posterminal ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL, token TEXT, @@ -616,7 +616,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS UQ_posterminal_token export const INIT_POSTERMINALCATEGORY = ` CREATE TABLE IF NOT EXISTS posterminalcategory ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, posterminal_id INTEGER NOT NULL, category_id INTEGER NOT NULL, UNIQUE (posterminal_id, category_id), @@ -627,7 +627,7 @@ CREATE TABLE IF NOT EXISTS posterminalcategory ( export const INIT_PRINTER = ` CREATE TABLE IF NOT EXISTS printer ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, address TEXT NOT NULL, type TEXT NOT NULL CHECK (type IN ('esc/pos', 'zpl', 'ipp')), @@ -642,7 +642,7 @@ CREATE TABLE IF NOT EXISTS printer ( export const INIT_LABELTEMPLATE = ` CREATE TABLE IF NOT EXISTS labeltemplate ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL, width INTEGER NOT NULL, @@ -657,7 +657,7 @@ CREATE TABLE IF NOT EXISTS labeltemplate ( export const INIT_FILE = ` CREATE TABLE IF NOT EXISTS "file" ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, mimetype TEXT NOT NULL, name TEXT NOT NULL, @@ -672,7 +672,7 @@ CREATE TABLE IF NOT EXISTS "file" ( export const INIT_MANIFESTATTACHMENT = ` CREATE TABLE IF NOT EXISTS manifestattachment ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, manifest_id INTEGER NOT NULL, file_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -696,7 +696,7 @@ END; export const INIT_PROPERTYNAME = ` CREATE TABLE IF NOT EXISTS propertyname ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -708,7 +708,7 @@ CREATE TABLE IF NOT EXISTS propertyname ( export const INIT_ARTICLEPROPERTY = ` CREATE TABLE IF NOT EXISTS articleproperty ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, property_id INTEGER NOT NULL, value TEXT NOT NULL, @@ -720,7 +720,7 @@ CREATE TABLE IF NOT EXISTS articleproperty ( export const INIT_ATTRIBUTENAME = ` CREATE TABLE IF NOT EXISTS attributename ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, name TEXT NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -732,7 +732,7 @@ CREATE TABLE IF NOT EXISTS attributename ( export const INIT_ATTRIBUTEVALUE = ` CREATE TABLE IF NOT EXISTS attributevalue ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, attribute_id INTEGER NOT NULL, value TEXT NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -743,7 +743,7 @@ CREATE TABLE IF NOT EXISTS attributevalue ( export const INIT_ARTICLEATTRIBUTEVALUE = ` CREATE TABLE IF NOT EXISTS articleattributevalue ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, article_id INTEGER NOT NULL, attributevalue_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -755,7 +755,7 @@ CREATE TABLE IF NOT EXISTS articleattributevalue ( export const INIT_CATEGORYPROPERTY = ` CREATE TABLE IF NOT EXISTS categoryproperty ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, property_id INTEGER NOT NULL, value TEXT NOT NULL, @@ -767,7 +767,7 @@ CREATE TABLE IF NOT EXISTS categoryproperty ( export const INIT_CATEGORYATTRIBUTEVALUE = ` CREATE TABLE IF NOT EXISTS categoryattributevalue ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, attributevalue_id INTEGER NOT NULL, sort INTEGER NOT NULL DEFAULT 0, @@ -779,7 +779,7 @@ CREATE TABLE IF NOT EXISTS categoryattributevalue ( export const INIT_ACCOUNT = ` CREATE TABLE IF NOT EXISTS account ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, company_id INTEGER NOT NULL, "type" TEXT NOT NULL, "name" TEXT NOT NULL, @@ -789,7 +789,7 @@ CREATE TABLE IF NOT EXISTS account ( export const INIT_PAYMENT = ` CREATE TABLE IF NOT EXISTS payment ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, account_id INTEGER NOT NULL, manifest_id INTEGER NOT NULL, "type" TEXT NOT NULL, @@ -801,7 +801,7 @@ CREATE TABLE IF NOT EXISTS payment ( export const INIT_SHIPPING = ` CREATE TABLE IF NOT EXISTS shipping ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, manifest_id INTEGER NOT NULL, "number" TEXT NOT NULL, "type" TEXT NOT NULL, @@ -812,7 +812,7 @@ CREATE TABLE IF NOT EXISTS shipping ( export const INIT_PACKAGE = ` CREATE TABLE IF NOT EXISTS package ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, shipping_id INTEGER NOT NULL, entityaddress_id INTEGER NOT NULL, "number" TEXT NOT NULL, diff --git a/src/store/brand/create.js b/src/store/brand/create.js new file mode 100644 index 0000000..6629e6a --- /dev/null +++ b/src/store/brand/create.js @@ -0,0 +1,78 @@ +import { + CREATE as MSSQL_CREATE, + GET_BY_COMPANY_AND_NAME as MSSQL_GET_BY_COMPANY_AND_NAME, +} from '../../providers/mssql/queries/brand.js'; +import { + CREATE as SQLITE_CREATE, + GET_BY_COMPANY_AND_NAME as SQLITE_GET_BY_COMPANY_AND_NAME, +} from '../../providers/sqlite3/queries/brand.js'; +import { isUniqueConstraintError } from '../../providers/provider.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; + +export default function create(provider) { + const access = resolveSelectedCompanyAccess(provider); + const isSqlite = provider?.dialect === 'sqlite3'; + const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE; + const getSql = isSqlite + ? SQLITE_GET_BY_COMPANY_AND_NAME + : MSSQL_GET_BY_COMPANY_AND_NAME; + + /** + * Creates a brand for the user's selected company. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {object} input - The brand input. + * @param {string} input.name - The brand name. + * @param {string} [input.gsprpinfo] - Optional GSPRP info. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>} The created brand. + * @throws {Error} If the brand is invalid or already exists. + * + * @example + * const brand = await store.brand.create(42, { name: 'Coca-Cola', gsprpinfo: 'x' }); + * // => { id, name, gsprpinfo, pics: [] } + */ + return async (googleAuthId, input = {}, tx) => { + const name = input.name?.trim(); + if (!name) { + throw new Error('Invalid brand'); + } + const gsprpinfo = input.gsprpinfo ?? null; + + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, tx); + + try { + const created = await runner.query(createSql, { + companyId, + name, + gsprpinfo, + }); + + const id = created.rows[0]?.id ?? created.insertId; + if (id == null) { + const fetched = await runner.query(getSql, { companyId, name }); + const row = fetched.rows[0]; + return { + id: row.id, + name, + gsprpinfo, + pics: [], + }; + } + + return { + id, + name, + gsprpinfo, + pics: [], + }; + } catch (err) { + if (isUniqueConstraintError(err)) { + throw new Error('Brand already exists'); + } + throw err; + } + }; +} diff --git a/src/store/brand/update.js b/src/store/brand/update.js new file mode 100644 index 0000000..d98f100 --- /dev/null +++ b/src/store/brand/update.js @@ -0,0 +1,90 @@ +import { + GET_BY_ID_AND_COMPANY as MSSQL_GET, + UPDATE_BY_ID as MSSQL_UPDATE, +} from '../../providers/mssql/queries/brand.js'; +import { + GET_BY_ID_AND_COMPANY as SQLITE_GET, + UPDATE_BY_ID as SQLITE_UPDATE, +} from '../../providers/sqlite3/queries/brand.js'; +import { isUniqueConstraintError } from '../../providers/provider.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; + +export default function update(provider) { + const access = resolveSelectedCompanyAccess(provider); + const isSqlite = provider?.dialect === 'sqlite3'; + const getSql = isSqlite ? SQLITE_GET : MSSQL_GET; + const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE; + + /** + * Renames/updates a brand for the user's selected company by id. + * Touching `article.updated_at` for all articles linked via `brand_id` + * when the name actually changes, so list caches invalidate. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {number} id - The id of the brand to update. + * @param {object} input - The update input. + * @param {string} [input.name] - The new brand name. + * @param {string} [input.gsprpinfo] - The new GSPRP info. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>} The updated brand plus the number of linked articles whose `updated_at` was bumped. + * @throws {Error} If the brand is not found, invalid, or the name is already taken. + * + * @example + * const brand = await store.brand.update(42, 3, { name: 'Coca-Cola GmbH' }); + * // => { id: 3, name, gsprpinfo, touchedArticleCount: 2 } + */ + return async (googleAuthId, id, input = {}, tx) => { + const numericId = Number(id); + if (!Number.isInteger(numericId) || numericId <= 0) { + throw new Error('Brand not found'); + } + + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, tx); + + const existing = await runner.query(getSql, { id: numericId, companyId }); + const current = existing.rows[0]; + if (!current) { + throw new Error('Brand not found'); + } + + const name = input.name !== undefined ? input.name?.trim() : current.name; + if (!name) { + throw new Error('Invalid brand'); + } + const gsprpinfo = input.gsprpinfo !== undefined ? input.gsprpinfo : current.gsprpinfo; + + try { + await runner.query(updateSql, { + id: numericId, + companyId, + name, + gsprpinfo, + }); + } catch (err) { + if (isUniqueConstraintError(err)) { + throw new Error('Brand already exists'); + } + throw err; + } + + let touchedArticleCount = 0; + if (name !== current.name) { + // Brand name is denormalized into article list views — bump + // updated_at so caches/incremental syncs pick up the rename. + const touchSql = isSqlite + ? "UPDATE article SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE brand_id = @brandId AND company_id = @companyId" + : 'UPDATE article SET updated_at = SYSUTCDATETIME() WHERE brand_id = @brandId AND company_id = @companyId'; + const touched = await runner.query(touchSql, { brandId: numericId, companyId }); + touchedArticleCount = touched.rowsAffected ?? 0; + } + + return { + id: numericId, + name, + gsprpinfo, + touchedArticleCount, + }; + }; +}