Initial import of zappier-edge from zapier monorepo
This commit is contained in:
commit
b8d239e759
120 changed files with 19867 additions and 0 deletions
112
src/db/customer-repo.ts
Normal file
112
src/db/customer-repo.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import Database from 'better-sqlite3';
|
||||
import { Customer, CustomerRepo } from '../auth';
|
||||
|
||||
export class SqliteCustomerRepo implements CustomerRepo {
|
||||
constructor(private db: Database.Database, seed: Customer[] = []) {
|
||||
this.db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS customers (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
tier_id TEXT NOT NULL,
|
||||
api_key TEXT NOT NULL UNIQUE,
|
||||
stripe_customer_id TEXT,
|
||||
multiplier_override REAL
|
||||
)
|
||||
`);
|
||||
// Idempotent migrations for pre-existing databases.
|
||||
this.ensureColumn('billing_type', `billing_type TEXT NOT NULL DEFAULT 'stripe'`);
|
||||
this.ensureColumn('email', 'email TEXT');
|
||||
this.ensureColumn('password_hash', 'password_hash TEXT');
|
||||
this.ensureColumn('totp_secret', 'totp_secret TEXT');
|
||||
this.ensureColumn('totp_enabled', 'totp_enabled INTEGER NOT NULL DEFAULT 0');
|
||||
this.ensureColumn('balance_cents', 'balance_cents INTEGER NOT NULL DEFAULT 0');
|
||||
this.ensureColumn('email_invoicing', 'email_invoicing INTEGER NOT NULL DEFAULT 0');
|
||||
const { n } = this.db.prepare('SELECT COUNT(*) AS n FROM customers').get() as { n: number };
|
||||
if (n === 0) {
|
||||
for (const c of seed) this.save(c);
|
||||
}
|
||||
}
|
||||
|
||||
private ensureColumn(name: string, ddl: string): void {
|
||||
const cols = this.db.prepare('PRAGMA table_info(customers)').all() as { name: string }[];
|
||||
if (!cols.some((c) => c.name === name)) {
|
||||
this.db.exec(`ALTER TABLE customers ADD COLUMN ${ddl}`);
|
||||
}
|
||||
}
|
||||
|
||||
findByApiKey(apiKey: string): Customer | undefined {
|
||||
const r = this.db.prepare('SELECT * FROM customers WHERE api_key = ?').get(apiKey) as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
return r ? toCustomer(r) : undefined;
|
||||
}
|
||||
|
||||
findByEmail(email: string): Customer | undefined {
|
||||
const r = this.db
|
||||
.prepare('SELECT * FROM customers WHERE lower(email) = lower(?)')
|
||||
.get(email) as Record<string, unknown> | undefined;
|
||||
return r ? toCustomer(r) : undefined;
|
||||
}
|
||||
|
||||
list(): Customer[] {
|
||||
const rows = this.db.prepare('SELECT * FROM customers ORDER BY id').all() as Record<
|
||||
string,
|
||||
unknown
|
||||
>[];
|
||||
return rows.map(toCustomer);
|
||||
}
|
||||
|
||||
save(customer: Customer): void {
|
||||
this.db
|
||||
.prepare(
|
||||
`INSERT INTO customers (id, name, tier_id, api_key, stripe_customer_id, multiplier_override, billing_type, email, password_hash, totp_secret, totp_enabled, balance_cents, email_invoicing)
|
||||
VALUES (@id, @name, @tierId, @apiKey, @stripeCustomerId, @multiplierOverride, @billingType, @email, @passwordHash, @totpSecret, @totpEnabled, @balanceCents, @emailInvoicing)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
name = @name,
|
||||
tier_id = @tierId,
|
||||
api_key = @apiKey,
|
||||
stripe_customer_id = @stripeCustomerId,
|
||||
multiplier_override = @multiplierOverride,
|
||||
billing_type = @billingType,
|
||||
email = @email,
|
||||
password_hash = @passwordHash,
|
||||
totp_secret = @totpSecret,
|
||||
totp_enabled = @totpEnabled,
|
||||
balance_cents = @balanceCents,
|
||||
email_invoicing = @emailInvoicing`,
|
||||
)
|
||||
.run({
|
||||
id: customer.id,
|
||||
name: customer.name,
|
||||
tierId: customer.tierId,
|
||||
apiKey: customer.apiKey,
|
||||
stripeCustomerId: customer.stripeCustomerId ?? null,
|
||||
multiplierOverride: customer.multiplierOverride ?? null,
|
||||
billingType: customer.billingType ?? 'stripe',
|
||||
email: customer.email ?? null,
|
||||
passwordHash: customer.passwordHash ?? null,
|
||||
totpSecret: customer.totpSecret ?? null,
|
||||
totpEnabled: customer.totpEnabled ? 1 : 0,
|
||||
balanceCents: customer.balanceCents ?? 0,
|
||||
emailInvoicing: customer.emailInvoicing ? 1 : 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toCustomer(r: Record<string, unknown>): Customer {
|
||||
return {
|
||||
id: r.id as string,
|
||||
name: r.name as string,
|
||||
tierId: r.tier_id as string,
|
||||
apiKey: r.api_key as string,
|
||||
stripeCustomerId: (r.stripe_customer_id as string | null) ?? undefined,
|
||||
multiplierOverride: (r.multiplier_override as number | null) ?? undefined,
|
||||
billingType: ((r.billing_type as string | null) ?? 'stripe') as Customer['billingType'],
|
||||
email: (r.email as string | null) ?? undefined,
|
||||
passwordHash: (r.password_hash as string | null) ?? undefined,
|
||||
totpSecret: (r.totp_secret as string | null) ?? undefined,
|
||||
totpEnabled: ((r.totp_enabled as number | null) ?? 0) === 1,
|
||||
balanceCents: (r.balance_cents as number | null) ?? 0,
|
||||
emailInvoicing: ((r.email_invoicing as number | null) ?? 0) === 1,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue