diff --git a/README.md b/README.md
index 4b684e8..ba1baa0 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ const client = await new LibDashStore(pool); // runs initialize() (ensure schema
SQL lives in `src/sql/
.js`. Schema DDL: `src/schema.js` / `import 'libdashstore/schema'`.
+ID fields in the JS API use camelCase `…Id` (DB columns stay snake_case).
+
---
## Schema
@@ -27,11 +29,10 @@ SQL lives in `src/sql/.js`. Schema DDL: `src/schema.js` / `import 'libdas
| Method | Signature | Returns |
| --- | --- | --- |
-| `create` | `({ iso639, name, taxrate, reducedtaxrate })` | `{ id, root_category_id, language_id, taxrate_id, reducedtaxrate_id, taxfreerate_id }` |
-| `update` | `(id, { iso639, name, taxrate, reducedtaxrate })` | `{ id, root_category_id, language_id, taxrate_id, reducedtaxrate_id, taxfreerate_id }` |
+| `create` | `({ iso639, name, taxrate, reducedtaxrate })` | `{ id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId }` |
+| `update` | `(id, { iso639, name, taxrate, reducedtaxrate })` | `{ id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId }` |
| `delete` | `(companyId)` | `void` |
-| `list` | `()` | `{ id, root_category_id, language_id, taxrate_id, reducedtaxrate_id, taxfreerate_id }[]` |
-
+| `list` | `()` | `{ id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId }[]` |
### `create` (transaction)
@@ -39,8 +40,8 @@ For `POST /api/company`:
1. Fails if `name` is taken (`Company name not available`)
2. Ensures language by `iso639` (get or create)
-3. Ensures tax rows for `taxrate`, `reducedtaxrate`, and `0` → `taxfreerate_id`
-4. Creates root category (`parent_id = null`)
+3. Ensures tax rows for `taxrate`, `reducedtaxrate`, and `0` → `taxfreerateId`
+4. Creates root category (`parentId = null`)
5. Inserts company with all FKs set
### `update` (transaction)
@@ -50,7 +51,7 @@ For `PATCH /api/company/:id`:
1. Fails if company missing / name taken by another company
2. Ensures lang + tax rates
3. Updates `name`, `default_language_id`, `taxrate`, `reducedtaxrate`
- (`taxfreerate_id` / root category unchanged)
+ (`taxfreerateId` / root category unchanged)
---
@@ -58,28 +59,16 @@ For `PATCH /api/company/:id`:
| Method | Signature | Returns |
| --- | --- | --- |
-| `add` | `(email)` | `number` (auth id) |
-| `getById` | `(id)` | `row \| undefined` |
-| `getByEmail` | `(email)` | `row \| undefined` |
+| `add` | `(email)` | `id` |
+| `getByEmail` | `(email)` | `{ id, email, createdAt, selectedCompanyId } \| undefined` |
+| `listAllowedEmails` | `()` | `{ id, email, createdAt, selectedCompanyId }[]` |
+| `removeAllowedEmail` | `(email)` | `void` |
| `setSelectedCompany` | `(authId, companyId)` | `void` |
-| `list` | `()` | `row[]` |
-| `del` | `(id)` | `void` |
-
-### Row shape
-
-```ts
-{
- id: number
- email: string
- created_at: Date
- selected_company: number | null
-}
-```
Backend mapping:
-- Login: `getByEmail(email)` ← `getAllowedEmail`
-- Auth middleware: `getById(id)` ← `getAllowedEmailById`
+- Login: `getByEmail(email)`
+- CLI user manager: `listAllowedEmails()` / `removeAllowedEmail(email)` / `add(email)`
- `PUT /api/auth/selected-company`: `setSelectedCompany(authId, companyId)`
---
@@ -88,8 +77,8 @@ Backend mapping:
| Method | Signature | Returns |
| --- | --- | --- |
-| `add` | `(companyId, authId)` | `number` (companyuser id) |
-| `getByEmail` | `(email)` | `number[]` (companyuser ids) |
+| `add` | `(companyId, authId)` | `id` |
+| `getByEmail` | `(email)` | `id[]` |
| `delete` | `(id)` | `void` |
---
@@ -98,9 +87,9 @@ Backend mapping:
| Method | Signature | Returns |
| --- | --- | --- |
-| `create` | `(iso639)` | `number` |
+| `create` | `(iso639)` | `id` |
| `getByIso639` | `(iso639)` | `{ id, iso639 } \| undefined` |
-| `ensure` | `(iso639, tx?)` | `number` (existing or new id) |
+| `ensure` | `(iso639, tx?)` | `id` |
| `list` | `()` | `{ id, iso639 }[]` |
| `delete` | `(id)` | `void` |
@@ -110,9 +99,9 @@ Backend mapping:
| Method | Signature | Returns |
| --- | --- | --- |
-| `create` | `(rate)` | `number` |
+| `create` | `(rate)` | `id` |
| `getByRate` | `(rate)` | `{ id, rate } \| undefined` |
-| `ensure` | `(rate, tx?)` | `number` (existing or new id) |
+| `ensure` | `(rate, tx?)` | `id` |
| `list` | `()` | `{ id, rate }[]` |
---
@@ -121,10 +110,10 @@ Backend mapping:
| Method | Signature | Returns |
| --- | --- | --- |
-| `create` | `({ parent_id, sort })` | `number` |
+| `create` | `({ parentId, sort })` | `id` |
| `updateParentId` | `(id, parentId)` | `void` |
| `delete` | `(id)` | `void` |
-| `getTree` | `(rootId)` | `{ id, parent_id, sort }[]` (flat CTE result) |
+| `getTree` | `(rootId)` | `{ id, parentId, sort }[]` |
---
diff --git a/scripts/test-api.js b/scripts/test-api.js
index 074d407..9ed89d9 100644
--- a/scripts/test-api.js
+++ b/scripts/test-api.js
@@ -95,7 +95,7 @@ const MENU = {
category: {
label: 'category',
items: [
- { value: 'category.create', label: 'create', hint: '{parent_id, sort} → id' },
+ { value: 'category.create', label: 'create', hint: '{parentId, sort} → id' },
{ value: 'category.updateParentId', label: 'updateParentId', hint: 'id, parentId' },
{ value: 'category.delete', label: 'delete', hint: 'id' },
{ value: 'category.getTree', label: 'getTree', hint: 'rootId → rows' },
@@ -112,12 +112,11 @@ const MENU = {
google_auth: {
label: 'google_auth',
items: [
- { value: 'google_auth.add', label: 'add', hint: 'email → authId' },
- { value: 'google_auth.getById', label: 'getById', hint: 'id → row' },
+ { value: 'google_auth.add', label: 'add', hint: 'email → id' },
{ value: 'google_auth.getByEmail', label: 'getByEmail', hint: 'email → row' },
+ { value: 'google_auth.listAllowedEmails', label: 'listAllowedEmails', hint: '→ rows' },
+ { value: 'google_auth.removeAllowedEmail', label: 'removeAllowedEmail', hint: 'email' },
{ value: 'google_auth.setSelectedCompany', label: 'setSelectedCompany', hint: 'authId, companyId' },
- { value: 'google_auth.list', label: 'list', hint: '→ rows' },
- { value: 'google_auth.del', label: 'del', hint: 'id' },
],
},
schema: {
@@ -186,13 +185,10 @@ async function runMethod(client, action) {
reducedtaxrate,
});
const companyId = created.id;
-
- const auths = await client.google_auth.list();
- const existingAuth = auths.find((row) => row.email === email);
- const authId = existingAuth
- ? existingAuth.id
+ const existing = await client.google_auth.getByEmail(email);
+ const authId = existing
+ ? existing.id
: await client.google_auth.add(email);
-
const companyUserId = await client.companyuser.add(companyId, authId);
await client.google_auth.setSelectedCompany(authId, companyId);
@@ -207,7 +203,6 @@ async function runMethod(client, action) {
iso639,
taxrate,
reducedtaxrate,
- authCreated: !existingAuth,
},
];
}
@@ -298,7 +293,7 @@ async function runMethod(client, action) {
return ['ok', true];
}
case 'category.create': {
- const parentRaw = await askText('parent_id (null as empty)', {
+ const parentRaw = await askText('parentId (null as empty)', {
placeholder: '',
validate: (v) =>
v?.trim() && !/^\d+$/.test(v.trim()) ? 'Integer or empty' : undefined,
@@ -306,13 +301,13 @@ async function runMethod(client, action) {
if (parentRaw == null) return;
const sortRaw = await askInt('sort', '0');
if (sortRaw == null) return;
- const parent_id = parentRaw === '' ? null : Number(parentRaw);
- return ['id', await client.category.create({ parent_id, sort: Number(sortRaw) })];
+ const parentId = parentRaw === '' ? null : Number(parentRaw);
+ return ['id', await client.category.create({ parentId, sort: Number(sortRaw) })];
}
case 'category.updateParentId': {
const id = await askInt('Category id');
if (id == null) return;
- const parentRaw = await askText('parent_id (null as empty)', {
+ const parentRaw = await askText('parentId (null as empty)', {
placeholder: '',
validate: (v) =>
v?.trim() && !/^\d+$/.test(v.trim()) ? 'Integer or empty' : undefined,
@@ -360,12 +355,7 @@ async function runMethod(client, action) {
validate: (v) => (!v?.trim() ? 'Required' : undefined),
});
if (email == null) return;
- return ['authId', await client.google_auth.add(email)];
- }
- case 'google_auth.getById': {
- const id = await askInt('Auth id');
- if (id == null) return;
- return ['row', await client.google_auth.getById(Number(id))];
+ return ['id', await client.google_auth.add(email)];
}
case 'google_auth.getByEmail': {
const email = await askText('Email', {
@@ -375,6 +365,18 @@ async function runMethod(client, action) {
if (email == null) return;
return ['row', await client.google_auth.getByEmail(email)];
}
+ case 'google_auth.listAllowedEmails': {
+ return ['rows', await client.google_auth.listAllowedEmails()];
+ }
+ case 'google_auth.removeAllowedEmail': {
+ const email = await askText('Email', {
+ placeholder: 'user@example.com',
+ validate: (v) => (!v?.trim() ? 'Required' : undefined),
+ });
+ if (email == null) return;
+ await client.google_auth.removeAllowedEmail(email);
+ return ['ok', true];
+ }
case 'google_auth.setSelectedCompany': {
const id = await askInt('Auth id');
if (id == null) return;
@@ -383,15 +385,6 @@ async function runMethod(client, action) {
await client.google_auth.setSelectedCompany(Number(id), Number(companyId));
return ['ok', true];
}
- case 'google_auth.list': {
- return ['rows', await client.google_auth.list()];
- }
- case 'google_auth.del': {
- const id = await askInt('Auth id');
- if (id == null) return;
- await client.google_auth.del(Number(id));
- return ['ok', true];
- }
case 'initialize': {
await client.initialize();
return ['ok', true];
diff --git a/src/index.js b/src/index.js
index 7b9a10b..5cc423a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -19,11 +19,10 @@ import taxGetByRate from './store/tax/getByRate.js';
import taxEnsure from './store/tax/ensure.js';
import taxList from './store/tax/list.js';
import googleAuthAdd from './store/google_auth/add.js';
-import googleAuthGetById from './store/google_auth/getById.js';
import googleAuthGetByEmail from './store/google_auth/getByEmail.js';
+import googleAuthListAllowedEmails from './store/google_auth/listAllowedEmails.js';
+import googleAuthRemoveAllowedEmail from './store/google_auth/removeAllowedEmail.js';
import googleAuthSetSelectedCompany from './store/google_auth/setSelectedCompany.js';
-import googleAuthList from './store/google_auth/list.js';
-import googleAuthDel from './store/google_auth/del.js';
import storePurge from './store/purge.js';
import storeInitialize from './store/initialize.js';
@@ -68,11 +67,10 @@ export default class LibDashStore {
this.google_auth = {
add: googleAuthAdd(pool),
- getById: googleAuthGetById(pool),
getByEmail: googleAuthGetByEmail(pool),
+ listAllowedEmails: googleAuthListAllowedEmails(pool),
+ removeAllowedEmail: googleAuthRemoveAllowedEmail(pool),
setSelectedCompany: googleAuthSetSelectedCompany(pool),
- list: googleAuthList(pool),
- del: googleAuthDel(pool),
};
this.purge = storePurge(pool);
diff --git a/src/sql/category.js b/src/sql/category.js
index 57f6b97..eac2e22 100644
--- a/src/sql/category.js
+++ b/src/sql/category.js
@@ -10,7 +10,7 @@ WITH tree AS (
FROM category c
INNER JOIN tree t ON c.parent_id = t.id
)
-SELECT id, parent_id, sort
+SELECT id, parent_id AS parentId, sort
FROM tree
ORDER BY sort, id
`;
diff --git a/src/sql/company.js b/src/sql/company.js
index 188938b..61c9537 100644
--- a/src/sql/company.js
+++ b/src/sql/company.js
@@ -43,11 +43,11 @@ WHERE id = @id
export const LIST = `
SELECT
id,
- root_category_id,
- default_language_id AS language_id,
- taxrate AS taxrate_id,
- reducedtaxrate AS reducedtaxrate_id,
- taxfreerate AS taxfreerate_id
+ root_category_id AS rootCategoryId,
+ default_language_id AS languageId,
+ taxrate AS taxrateId,
+ reducedtaxrate AS reducedtaxrateId,
+ taxfreerate AS taxfreerateId
FROM company
`;
diff --git a/src/sql/google_auth.js b/src/sql/google_auth.js
index b63e991..53adbac 100644
--- a/src/sql/google_auth.js
+++ b/src/sql/google_auth.js
@@ -4,27 +4,21 @@ OUTPUT INSERTED.id
VALUES (@email)
`;
-export const GET_BY_ID = `
-SELECT id, email, created_at, selected_company
-FROM google_auth
-WHERE id = @id
-`;
-
export const GET_BY_EMAIL = `
-SELECT id, email, created_at, selected_company
+SELECT id, email, created_at AS createdAt, selected_company AS selectedCompanyId
FROM google_auth
WHERE email = @email
`;
-export const LIST = `
-SELECT id, email, created_at, selected_company
+export const LIST_ALLOWED_EMAILS = `
+SELECT id, email, created_at AS createdAt, selected_company AS selectedCompanyId
FROM google_auth
-ORDER BY id
+ORDER BY email
`;
-export const DEL = `
+export const REMOVE_ALLOWED_EMAIL = `
DELETE FROM google_auth
-WHERE id = @id
+WHERE email = @email
`;
export const SET_SELECTED_COMPANY = `
diff --git a/src/store/category/create.js b/src/store/category/create.js
index 2a0c748..64794ec 100644
--- a/src/store/category/create.js
+++ b/src/store/category/create.js
@@ -2,10 +2,10 @@ import sql from 'mssql';
import { CREATE } from '../../sql/category.js';
export default function create(pool) {
- return async ({ parent_id, sort }) => {
+ return async ({ parentId, sort }) => {
const result = await pool
.request()
- .input('parentId', sql.Int, parent_id)
+ .input('parentId', sql.Int, parentId)
.input('sort', sql.Int, sort)
.query(CREATE);
diff --git a/src/store/company/create.js b/src/store/company/create.js
index 7f46975..b7063bb 100644
--- a/src/store/company/create.js
+++ b/src/store/company/create.js
@@ -46,11 +46,11 @@ export default function create(pool) {
return {
id: result.recordset[0].id,
- root_category_id: rootCategoryId,
- language_id: languageId,
- taxrate_id: taxrateId,
- reducedtaxrate_id: reducedtaxrateId,
- taxfreerate_id: taxfreerateId,
+ rootCategoryId,
+ languageId,
+ taxrateId,
+ reducedtaxrateId,
+ taxfreerateId,
};
} catch (err) {
try {
diff --git a/src/store/company/update.js b/src/store/company/update.js
index c39b9b5..5d3fee0 100644
--- a/src/store/company/update.js
+++ b/src/store/company/update.js
@@ -45,11 +45,11 @@ export default function update(pool) {
return {
id,
- root_category_id: company.root_category_id,
- language_id: languageId,
- taxrate_id: taxrateId,
- reducedtaxrate_id: reducedtaxrateId,
- taxfreerate_id: company.taxfreerate,
+ rootCategoryId: company.root_category_id,
+ languageId,
+ taxrateId,
+ reducedtaxrateId,
+ taxfreerateId: company.taxfreerate,
};
} catch (err) {
try {
diff --git a/src/store/google_auth/del.js b/src/store/google_auth/del.js
deleted file mode 100644
index 9bf3f79..0000000
--- a/src/store/google_auth/del.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import sql from 'mssql';
-import { DEL } from '../../sql/google_auth.js';
-
-export default function del(pool) {
- return async (id) => {
- await pool
- .request()
- .input('id', sql.Int, id)
- .query(DEL);
- };
-}
diff --git a/src/store/google_auth/getById.js b/src/store/google_auth/getById.js
deleted file mode 100644
index 96c6fac..0000000
--- a/src/store/google_auth/getById.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import sql from 'mssql';
-import { GET_BY_ID } from '../../sql/google_auth.js';
-
-export default function getById(pool) {
- return async (id) => {
- const result = await pool
- .request()
- .input('id', sql.Int, id)
- .query(GET_BY_ID);
-
- return result.recordset[0];
- };
-}
diff --git a/src/store/google_auth/list.js b/src/store/google_auth/list.js
deleted file mode 100644
index 7f9e765..0000000
--- a/src/store/google_auth/list.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { LIST } from '../../sql/google_auth.js';
-
-export default function list(pool) {
- return async () => {
- const result = await pool.request().query(LIST);
- return result.recordset;
- };
-}
diff --git a/src/store/google_auth/listAllowedEmails.js b/src/store/google_auth/listAllowedEmails.js
new file mode 100644
index 0000000..34bd0fe
--- /dev/null
+++ b/src/store/google_auth/listAllowedEmails.js
@@ -0,0 +1,8 @@
+import { LIST_ALLOWED_EMAILS } from '../../sql/google_auth.js';
+
+export default function listAllowedEmails(pool) {
+ return async () => {
+ const result = await pool.request().query(LIST_ALLOWED_EMAILS);
+ return result.recordset;
+ };
+}
diff --git a/src/store/google_auth/removeAllowedEmail.js b/src/store/google_auth/removeAllowedEmail.js
new file mode 100644
index 0000000..f40baf7
--- /dev/null
+++ b/src/store/google_auth/removeAllowedEmail.js
@@ -0,0 +1,11 @@
+import sql from 'mssql';
+import { REMOVE_ALLOWED_EMAIL } from '../../sql/google_auth.js';
+
+export default function removeAllowedEmail(pool) {
+ return async (email) => {
+ await pool
+ .request()
+ .input('email', sql.NVarChar(320), email)
+ .query(REMOVE_ALLOWED_EMAIL);
+ };
+}