概要
前回の続き。
ハンズオン Node.jsの7章データストレージをtypescriptで試す。今回はsqlite。
環境
package.json
{"name":"node-app","version":"1.0.0","description":"","main":"index.js","scripts":{"start":"node ./bin/www","file-system":"node ./bin/www","sqlite":"node ./bin/www","tsc":"tsc","watch":"tsc --watch"},"keywords":[],"author":"","license":"MIT","engines":{"node":"14.x"},"dependencies":{"express":"^4.17.1","sqlite3":"^5.0.0","uuid":"^8.3.1"},"devDependencies":{"@types/express":"^4.17.9","@types/sqlite3":"^3.1.6","@types/uuid":"^8.3.0","@typescript-eslint/eslint-plugin":"^4.8.2","@typescript-eslint/parser":"^4.8.2","eslint":"^7.14.0","eslint-config-prettier":"^6.15.0","eslint-plugin-prettier":"^3.1.4","isomorphic-fetch":"^3.0.0","prettier":"^2.2.0","typescript":"^4.1.2"}}
ソース
promisify
したときの型をtype PromiseDbGet = <T>(arg: string, arg2?: any) => Promise<T>
としているが、もうちょっとよい方法ないだろうか
src/fqlite/index.ts
import{promisify}from'util'import{join}from'path'importtype{ID,Todo,DataStorage}from'../types'importtype{RunResult,sqlite3asSqlite3}from'sqlite3'interfaceTodoSQLite{id:IDtitle:stringcompleted:0|1}typeSQLiteArgs=[sql:string,...params:any[]]typePromiseDbGet=<T>(arg:string,arg2?:any)=>Promise<T>typePromiseDbAll=<T>(arg:string,arg2?:any)=>Promise<T>constsqlite3:Sqlite3=process.env.NODE_ENV==='production'?require('sqlite3'):require('sqlite3').verbose()constdb=newsqlite3.Database(join(__dirname,'sqlite'))constdbGet:PromiseDbGet=promisify(db.get.bind(db))constdbRun=function(...args:SQLiteArgs){returnnewPromise<RunResult>((resolve,reject)=>db.run.apply(db,[...args,function(this:RunResult,err:any){err?reject(err):resolve(this)},]),)}constdbAll:PromiseDbAll=promisify(db.all.bind(db))dbRun(`CREATE TABLE IF NOT EXISTS todo (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
completed BOOLEAN NOT NULL
)`).catch((err)=>{console.log(err)process.exit(1)})functionrowToTodo(row:TodoSQLite):Todo{return{...row,completed:!!row.completed}}constexportsObj:DataStorage<Todo>={fetchAll:()=>dbAll<TodoSQLite[]>('SELECT * FROM todo').then((rows)=>rows.map(rowToTodo),),fetchByCompleted:(completed)=>dbAll<TodoSQLite[]>('SELECT * FROM todo WHERE completed = ?',completed,).then((rows:TodoSQLite[])=>rows.map(rowToTodo)),create:async(todo)=>{awaitdbRun('INSERT INTO todo VALUES (?,?,?)',todo.id,todo.title,todo.completed,)},update:(id,update)=>{constsetColumns=[]constvalues=[]for(constcolumnof['title','completed']asconst){if(columninupdate){setColumns.push(`${column} = ? `)values.push(update[column])}}values.push(id)returndbRun(`UPDATE todo SET ${setColumns.join()} WHERE id = ?`,values,).then(({changes})=>changes===1?dbGet<TodoSQLite>('SELECT * FROM todo WHERE id = ?',id).then(rowToTodo,):null,)},remove:(id)=>dbRun('DELETE FROM todo WHERE id = ?',id).then(({changes})=>changes===1?id:null,),}exportdefaultexportsObj