diff --git a/API.md b/API.md index 0bd2b57..1f646f9 100644 --- a/API.md +++ b/API.md @@ -404,6 +404,11 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met - `create(googleAuthId: number, input: {accountId: number, manifestId: number, type: string, amount: number}, tx?: object): Promise<{id: number, accountId: number, manifestId: number, type: string, amount: number}>` - `delete(googleAuthId: number, id: number, tx?: object): Promise` - `listByManifestId(googleAuthId: number, manifestId: number, tx?: object): Promise>` +- [printeragent](API.printeragent.md) + - `create(googleAuthId: number, input: {name: string, pairingpin: string}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` + - `delete(googleAuthId: number, id: number, tx?: object): Promise` + - `list(googleAuthId: number, tx?: object): Promise>` + - `update(googleAuthId: number, input: {id: number, name: string}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` - [retoure](API.retoure.md) - `create(googleAuthId: number, body: {number?: string, date: string, entityId?: number, externalNumber?: string, lines?: Array}, tx?: object): Promise` - `createShipment(googleAuthId: number, retoureId: number, input: object, tx?: object): Promise` diff --git a/API.printeragent.md b/API.printeragent.md new file mode 100644 index 0000000..95386c3 --- /dev/null +++ b/API.printeragent.md @@ -0,0 +1,115 @@ +# printeragent + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `printeragent.create` + +*Source: `src/store/printeragent/create.js`* + +Creates an unpaired printer agent for the user's selected company. The agent registers itself later using the pairing pin. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `input` | `object` | The printer agent input. | +| `input.name` | `string` | The display name. | +| `input.pairingpin` | `string` | The pairing pin the agent uses to register. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` — The created printer agent. + +**Throws** + +`Error` — 'Invalid printeragent' if name or pairingpin is missing/blank. + +**Example** + +```js +const agent = await store.printeragent.create(42, { name: 'Bar printer', pairingpin: '123456' }); +``` + +## `printeragent.delete` + +*Source: `src/store/printeragent/delete.js`* + +Deletes a printer agent of the user's selected company. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `id` | `number` | The printer agent id. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise` + +**Throws** + +`Error` — 'Printeragent not found' if the id is unknown in the company. + +**Example** + +```js +await store.printeragent.delete(42, 5); +``` + +## `printeragent.list` + +*Source: `src/store/printeragent/list.js`* + +Lists the printer agents of the user's selected company. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise>` — The printer agents. + +**Example** + +```js +const agents = await store.printeragent.list(42); +// => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt }] +``` + +## `printeragent.update` + +*Source: `src/store/printeragent/update.js`* + +Renames a printer agent of the user's selected company. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `googleAuthId` | `number` | The id of the Google auth user. | +| `input` | `object` | The update input. | +| `input.id` | `number` | The printer agent id. | +| `input.name` | `string` | The new display name. | +| `[tx]` | `object` | Optional transaction to run within. | + +**Returns** + +`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` — The updated printer agent. + +**Throws** + +`Error` — 'Invalid printeragent' if name is blank; 'Printeragent not found' if id is unknown in the company. + +**Example** + +```js +const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer' }); +``` diff --git a/scripts/test-printeragent.js b/scripts/test-printeragent.js new file mode 100644 index 0000000..b6650d0 --- /dev/null +++ b/scripts/test-printeragent.js @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import LibDashStore from '../src/index.js'; +import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js'; + +const tempDir = mkdtempSync(join(tmpdir(), 'dash-printeragent-test-')); +const provider = new BetterSqlite3Provider({ filename: join(tempDir, 'test.db'), storageDir: join(tempDir, 'storage') }); +await provider.initialize(); +const store = await new LibDashStore(provider); + +try { + const googleAuthId = await store.google_auth.add('printeragent-tester@example.com'); + const company = await store.company.create({ name: 'PA GmbH', iso639: 'de', taxrate: 19, reducedtaxrate: 7, googleAuthId }); + await store.google_auth.setSelectedCompany(googleAuthId, company.id); + + assert.deepEqual(await store.printeragent.list(googleAuthId), []); + await assert.rejects(store.printeragent.create(googleAuthId, { name: ' ', pairingpin: '1' }), /Invalid printeragent/); + + const a = await store.printeragent.create(googleAuthId, { name: ' Bar ', pairingpin: '123456' }); + assert.equal(a.name, 'Bar'); + assert.equal(a.pairingpin, '123456'); + assert.equal(a.token, null); + assert.equal(a.companyId, company.id); + assert.ok(a.updatedAt); + + const b = await store.printeragent.update(googleAuthId, { id: a.id, name: 'Kitchen' }); + assert.equal(b.name, 'Kitchen'); + await assert.rejects(store.printeragent.update(googleAuthId, { id: 9999, name: 'x' }), /Printeragent not found/); + await assert.rejects(store.printeragent.update(googleAuthId, { id: a.id, name: '' }), /Invalid printeragent/); + + assert.equal((await store.printeragent.list(googleAuthId)).length, 1); + await store.printeragent.delete(googleAuthId, a.id); + await assert.rejects(store.printeragent.delete(googleAuthId, a.id), /Printeragent not found/); + assert.deepEqual(await store.printeragent.list(googleAuthId), []); + console.log('printeragent OK'); +} finally { + await provider.close?.(); + rmSync(tempDir, { recursive: true, force: true }); +} diff --git a/src/index.js b/src/index.js index 0711b9e..8393bbf 100644 --- a/src/index.js +++ b/src/index.js @@ -200,6 +200,10 @@ import printerList from './store/printer/list.js'; import printerUpdate from './store/printer/update.js'; import printerDelete from './store/printer/delete.js'; import printerOrder from './store/printer/order.js'; +import printeragentList from './store/printeragent/list.js'; +import printeragentCreate from './store/printeragent/create.js'; +import printeragentUpdate from './store/printeragent/update.js'; +import printeragentDelete from './store/printeragent/delete.js'; import modelconversationCreate from './store/modelconversation/create.js'; import modelconversationGet from './store/modelconversation/get.js'; import modelconversationList from './store/modelconversation/list.js'; @@ -637,6 +641,13 @@ export default class LibDashStore { order: printerOrder(provider), }; + this.printeragent = { + list: printeragentList(provider), + create: printeragentCreate(provider), + update: printeragentUpdate(provider), + delete: printeragentDelete(provider), + }; + this.modelconversation = { create: modelconversationCreate(provider), get: modelconversationGet(provider), diff --git a/src/providers/mssql/downgrade/3_to_2.js b/src/providers/mssql/downgrade/3_to_2.js new file mode 100644 index 0000000..8e05d09 --- /dev/null +++ b/src/providers/mssql/downgrade/3_to_2.js @@ -0,0 +1,11 @@ +/** + * Schema 3 → 2 (MSSQL): drops the `printeragent` table. + * @param {{ query: (sql: string, params?: object) => Promise, assertVersion: (v: number) => Promise, setVersion: (v: number) => Promise }} ctx + */ +export default async function downgrade({ query, assertVersion, setVersion }) { + await assertVersion(3); + + await query(`DROP TABLE IF EXISTS printeragent;`); + + await setVersion(2); +} diff --git a/src/providers/mssql/purgeSql.js b/src/providers/mssql/purgeSql.js index b4c9eff..df0e2f5 100644 --- a/src/providers/mssql/purgeSql.js +++ b/src/providers/mssql/purgeSql.js @@ -28,6 +28,7 @@ export const TABLES = [ 'posterminalobituary', 'posterminalcategory', 'posterminal', + 'printeragent', 'printer', 'numbers', 'ledger', diff --git a/src/providers/mssql/queries/printeragent.js b/src/providers/mssql/queries/printeragent.js new file mode 100644 index 0000000..7f54b94 --- /dev/null +++ b/src/providers/mssql/queries/printeragent.js @@ -0,0 +1,58 @@ +export const PRINTERAGENT_COLUMNS = ` + id, + company_id AS companyId, + name, + token, + pairingpin, + paired_at AS pairedAt, + clientserial, + clientmodel, + clientstate, + agentversion, + lastseen_at AS lastseenAt, + updated_at AS updatedAt +`; + +export const LIST_BY_COMPANY = ` +SELECT +${PRINTERAGENT_COLUMNS} +FROM printeragent +WHERE company_id = @companyId +ORDER BY name, id +`; + +export const GET_BY_COMPANY_AND_ID = ` +SELECT +${PRINTERAGENT_COLUMNS} +FROM printeragent +WHERE id = @id AND company_id = @companyId +`; + +export const CREATE = ` +INSERT INTO printeragent (company_id, name, pairingpin) +OUTPUT + INSERTED.id, + INSERTED.company_id AS companyId, + INSERTED.name, + INSERTED.token, + INSERTED.pairingpin, + INSERTED.paired_at AS pairedAt, + INSERTED.clientserial, + INSERTED.clientmodel, + INSERTED.clientstate, + INSERTED.agentversion, + INSERTED.lastseen_at AS lastseenAt, + INSERTED.updated_at AS updatedAt +VALUES (@companyId, @name, @pairingpin) +`; + +export const UPDATE_NAME = ` +UPDATE printeragent +SET name = @name, updated_at = SYSUTCDATETIME() +WHERE id = @id AND company_id = @companyId +`; + +export const DELETE_BY_COMPANY_AND_ID = ` +DELETE FROM printeragent +WHERE id = @id AND company_id = @companyId +`; diff --git a/src/providers/mssql/schema.js b/src/providers/mssql/schema.js index 1b7d973..0aad2c2 100644 --- a/src/providers/mssql/schema.js +++ b/src/providers/mssql/schema.js @@ -1011,6 +1011,29 @@ END `; +export const INIT_PRINTERAGENT = ` +IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'printeragent') +BEGIN + CREATE TABLE printeragent ( + id INT IDENTITY(1,1) PRIMARY KEY, + company_id INT NOT NULL, + name NVARCHAR(255) NOT NULL, + token NVARCHAR(255) NULL, + pairingpin NVARCHAR(50) NULL, + paired_at DATETIME2 NULL, + clientserial NVARCHAR(255) NULL, + clientmodel NVARCHAR(255) NULL, + clientstate NVARCHAR(255) NULL, + agentversion NVARCHAR(255) NULL, + lastseen_at DATETIME2 NULL, + updated_at DATETIME2 NOT NULL CONSTRAINT DF_printeragent_updated_at DEFAULT SYSUTCDATETIME(), + CONSTRAINT FK_printeragent_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE + ); + CREATE UNIQUE INDEX UQ_printeragent_token ON printeragent(token) WHERE token IS NOT NULL; + CREATE UNIQUE INDEX UQ_printeragent_pairingpin ON printeragent(pairingpin) WHERE pairingpin IS NOT NULL; +END +`; + export const INIT_LABELTEMPLATE = ` IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'labeltemplate') BEGIN @@ -1666,6 +1689,7 @@ export const SCHEMA_SCRIPTS = [ INIT_POSTERMINALOBITUARY, INIT_POSTERMINALSYNCQUEUE, INIT_PRINTER, + INIT_PRINTERAGENT, INIT_LABELTEMPLATE, INIT_FILE, INIT_MANIFESTATTACHMENT, diff --git a/src/providers/mssql/upgrade/2_to_3.js b/src/providers/mssql/upgrade/2_to_3.js new file mode 100644 index 0000000..f84f84b --- /dev/null +++ b/src/providers/mssql/upgrade/2_to_3.js @@ -0,0 +1,13 @@ +import { INIT_PRINTERAGENT } from '../schema.js'; + +/** + * Schema 2 → 3 (MSSQL): adds the `printeragent` table. + * @param {{ query: (sql: string, params?: object) => Promise, assertVersion: (v: number) => Promise, setVersion: (v: number) => Promise }} ctx + */ +export default async function upgrade({ query, assertVersion, setVersion }) { + await assertVersion(2); + + await query(INIT_PRINTERAGENT); + + await setVersion(3); +} diff --git a/src/providers/sqlite3/downgrade/3_to_2.js b/src/providers/sqlite3/downgrade/3_to_2.js new file mode 100644 index 0000000..9f578d6 --- /dev/null +++ b/src/providers/sqlite3/downgrade/3_to_2.js @@ -0,0 +1,11 @@ +/** + * Schema 3 → 2 (SQLite): drops the `printeragent` table. + * @param {{ exec: (sql: string) => void, assertVersion: (v: number) => Promise, setVersion: (v: number) => Promise }} ctx + */ +export default async function downgrade({ exec, assertVersion, setVersion }) { + await assertVersion(3); + + exec(`DROP TABLE IF EXISTS printeragent;`); + + await setVersion(2); +} diff --git a/src/providers/sqlite3/queries/printeragent.js b/src/providers/sqlite3/queries/printeragent.js new file mode 100644 index 0000000..71dee6f --- /dev/null +++ b/src/providers/sqlite3/queries/printeragent.js @@ -0,0 +1,12 @@ +import * as source from '../../mssql/queries/printeragent.js'; +import { translateQueries } from './translate.js'; + +const queries = translateQueries(source, 'printeragent'); +export const { + CREATE, + DELETE_BY_COMPANY_AND_ID, + GET_BY_COMPANY_AND_ID, + LIST_BY_COMPANY, + PRINTERAGENT_COLUMNS, + UPDATE_NAME, +} = queries; diff --git a/src/providers/sqlite3/schema.js b/src/providers/sqlite3/schema.js index 20934b5..009258b 100644 --- a/src/providers/sqlite3/schema.js +++ b/src/providers/sqlite3/schema.js @@ -692,6 +692,28 @@ CREATE TABLE IF NOT EXISTS printer ( `; +export const INIT_PRINTERAGENT = ` +CREATE TABLE IF NOT EXISTS printeragent ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + company_id INTEGER NOT NULL, + name TEXT NOT NULL, + token TEXT, + pairingpin TEXT, + paired_at TEXT, + clientserial TEXT, + clientmodel TEXT, + clientstate TEXT, + agentversion TEXT, + lastseen_at TEXT, + updated_at TEXT NOT NULL DEFAULT (${UTC_NOW}), + FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE +); +CREATE UNIQUE INDEX IF NOT EXISTS UQ_printeragent_token + ON printeragent(token) WHERE token IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS UQ_printeragent_pairingpin + ON printeragent(pairingpin) WHERE pairingpin IS NOT NULL; +`; + export const INIT_LABELTEMPLATE = ` CREATE TABLE IF NOT EXISTS labeltemplate ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -1225,6 +1247,7 @@ export const SCHEMA_SCRIPTS = [ INIT_POSTERMINALOBITUARY, INIT_POSTERMINALSYNCQUEUE, INIT_PRINTER, + INIT_PRINTERAGENT, INIT_LABELTEMPLATE, INIT_FILE, INIT_MANIFESTATTACHMENT, diff --git a/src/providers/sqlite3/upgrade/2_to_3.js b/src/providers/sqlite3/upgrade/2_to_3.js new file mode 100644 index 0000000..cff9df1 --- /dev/null +++ b/src/providers/sqlite3/upgrade/2_to_3.js @@ -0,0 +1,13 @@ +import { INIT_PRINTERAGENT } from '../schema.js'; + +/** + * Schema 2 → 3 (SQLite): adds the `printeragent` table. + * @param {{ exec: (sql: string) => void, assertVersion: (v: number) => Promise, setVersion: (v: number) => Promise }} ctx + */ +export default async function upgrade({ exec, assertVersion, setVersion }) { + await assertVersion(2); + + exec(INIT_PRINTERAGENT); + + await setVersion(3); +} diff --git a/src/store/printeragent/_shared.js b/src/store/printeragent/_shared.js new file mode 100644 index 0000000..fd2efa8 --- /dev/null +++ b/src/store/printeragent/_shared.js @@ -0,0 +1,19 @@ +export function shape(row) { + return { + id: row.id, + companyId: row.companyId, + name: row.name, + token: row.token ?? null, + pairingpin: row.pairingpin ?? null, + pairedAt: row.pairedAt ?? null, + clientserial: row.clientserial ?? null, + clientmodel: row.clientmodel ?? null, + clientstate: row.clientstate ?? null, + agentversion: row.agentversion ?? null, + lastseenAt: row.lastseenAt ?? null, + updatedAt: row.updatedAt, + }; +} + +export const PRINTERAGENT_TYPEDEF = + '{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}'; diff --git a/src/store/printeragent/create.js b/src/store/printeragent/create.js new file mode 100644 index 0000000..533b0b3 --- /dev/null +++ b/src/store/printeragent/create.js @@ -0,0 +1,43 @@ +import { + CREATE as MSSQL_CREATE, +} from '../../providers/mssql/queries/printeragent.js'; +import { + CREATE as SQLITE_CREATE, +} from '../../providers/sqlite3/queries/printeragent.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; +import { shape } from './_shared.js'; + +export default function create(provider) { + const access = resolveSelectedCompanyAccess(provider); + const sql = provider?.dialect === 'sqlite3' ? SQLITE_CREATE : MSSQL_CREATE; + + /** + * Creates an unpaired printer agent for the user's selected company. + * The agent registers itself later using the pairing pin. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {object} input - The printer agent input. + * @param {string} input.name - The display name. + * @param {string} input.pairingpin - The pairing pin the agent uses to register. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>} The created printer agent. + * @throws {Error} 'Invalid printeragent' if name or pairingpin is missing/blank. + * + * @example + * const agent = await store.printeragent.create(42, { name: 'Bar printer', pairingpin: '123456' }); + */ + return async (googleAuthId, input = {}, tx) => { + const name = typeof input.name === 'string' ? input.name.trim() : ''; + const pairingpin = input.pairingpin != null ? String(input.pairingpin).trim() : ''; + if (!name || !pairingpin) { + throw new Error('Invalid printeragent'); + } + + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, runner); + + const result = await runner.query(sql, { companyId, name, pairingpin }); + return shape(result.rows[0]); + }; +} diff --git a/src/store/printeragent/delete.js b/src/store/printeragent/delete.js new file mode 100644 index 0000000..b964609 --- /dev/null +++ b/src/store/printeragent/delete.js @@ -0,0 +1,36 @@ +import { DELETE_BY_COMPANY_AND_ID as MSSQL_DELETE } from '../../providers/mssql/queries/printeragent.js'; +import { DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE } from '../../providers/sqlite3/queries/printeragent.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; + +export default function del(provider) { + const access = resolveSelectedCompanyAccess(provider); + const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE; + + /** + * Deletes a printer agent of the user's selected company. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {number} id - The printer agent id. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise} + * @throws {Error} 'Printeragent not found' if the id is unknown in the company. + * + * @example + * await store.printeragent.delete(42, 5); + */ + return async (googleAuthId, id, tx) => { + const numericId = Number(id); + if (!Number.isInteger(numericId) || numericId <= 0) { + throw new Error('Printeragent not found'); + } + + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, runner); + + const result = await runner.query(sql, { id: numericId, companyId }); + if (!result.rowsAffected) { + throw new Error('Printeragent not found'); + } + }; +} diff --git a/src/store/printeragent/list.js b/src/store/printeragent/list.js new file mode 100644 index 0000000..db02e44 --- /dev/null +++ b/src/store/printeragent/list.js @@ -0,0 +1,29 @@ +import { LIST_BY_COMPANY as MSSQL_LIST } from '../../providers/mssql/queries/printeragent.js'; +import { LIST_BY_COMPANY as SQLITE_LIST } from '../../providers/sqlite3/queries/printeragent.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; +import { shape } from './_shared.js'; + +export default function list(provider) { + const access = resolveSelectedCompanyAccess(provider); + const sql = provider?.dialect === 'sqlite3' ? SQLITE_LIST : MSSQL_LIST; + + /** + * Lists the printer agents of the user's selected company. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise>} The printer agents. + * + * @example + * const agents = await store.printeragent.list(42); + * // => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt }] + */ + return async (googleAuthId, tx) => { + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, runner); + + const result = await runner.query(sql, { companyId }); + return result.rows.map(shape); + }; +} diff --git a/src/store/printeragent/update.js b/src/store/printeragent/update.js new file mode 100644 index 0000000..a2584a6 --- /dev/null +++ b/src/store/printeragent/update.js @@ -0,0 +1,54 @@ +import { + GET_BY_COMPANY_AND_ID as MSSQL_GET, + UPDATE_NAME as MSSQL_UPDATE_NAME, +} from '../../providers/mssql/queries/printeragent.js'; +import { + GET_BY_COMPANY_AND_ID as SQLITE_GET, + UPDATE_NAME as SQLITE_UPDATE_NAME, +} from '../../providers/sqlite3/queries/printeragent.js'; +import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js'; +import makeRunner from '../runner.js'; +import { shape } from './_shared.js'; + +export default function update(provider) { + const access = resolveSelectedCompanyAccess(provider); + const isSqlite = provider?.dialect === 'sqlite3'; + const getSql = isSqlite ? SQLITE_GET : MSSQL_GET; + const updateNameSql = isSqlite ? SQLITE_UPDATE_NAME : MSSQL_UPDATE_NAME; + + /** + * Renames a printer agent of the user's selected company. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {object} input - The update input. + * @param {number} input.id - The printer agent id. + * @param {string} input.name - The new display name. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>} The updated printer agent. + * @throws {Error} 'Invalid printeragent' if name is blank; 'Printeragent not found' if id is unknown in the company. + * + * @example + * const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer' }); + */ + return async (googleAuthId, input = {}, tx) => { + const id = Number(input.id); + if (!Number.isInteger(id) || id <= 0) { + throw new Error('Printeragent not found'); + } + const name = typeof input.name === 'string' ? input.name.trim() : ''; + if (!name) { + throw new Error('Invalid printeragent'); + } + + const runner = makeRunner(provider, tx); + const { companyId } = await access(googleAuthId, runner); + + const result = await runner.query(updateNameSql, { id, companyId, name }); + if (!result.rowsAffected) { + throw new Error('Printeragent not found'); + } + + const row = await runner.query(getSql, { id, companyId }); + return shape(row.rows[0]); + }; +}