LoginSignup
8
5

More than 5 years have passed since last update.

絶望的な状況をTypeScriptとTypeORMが助けてくれた話

Last updated at Posted at 2018-05-19

経緯

2年ぶりにWindows機を引っ張り出してきたのだが、不覚にもログインパスワードを忘れてしまっている。ありうるパターンを30ぐらい試してみたが一向にログインできる気配がない。途方にくれていたところ、大昔に自分のPCのパスワードをLINEを使って友人に送っていたことを思い出した。しめた、と思いLINEを開いてみたところ、件の送信記録は見つからない。これは、iPhoneを5から7に変更するときにとっておいたLine.sqliteのバックアップに残っているハズだ!

ということでLine.sqliteからLINEのメッセージログをサルベージする運びとなった。

生でSQLを書くよりかは、コードにした方が柔軟性があるだろうと思い、最近ご無沙汰になっているTypeScriptでサルベージスクリプトを書くことにした。

利用ライブラリ

TypeORMというORマッパーを利用してsqliteを掘る。型があって便利。

(意訳) 他のしょぼいライブラリと違ってActive RecordパターンとData Mapperパターンを両方利用可能。だから、しゅごいクオリティの高い、疎結合で、スケールしまくる、メンテも余裕でできちゃう、アプリケーションが書けてやばたにえん。

データ構造

今回、全てのデータにアクセスする必要はないので、必要なところのみをエンティティに記述する。こんな感じ。ZMESSAGEとかが実際のテーブル名 / カラム名。よくあるリレーションを張る。

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from "typeorm"
import { User } from "./user"

@Entity("ZMESSAGE")
export class Message {
  @PrimaryGeneratedColumn({ name: "Z_PK" })
    id!: number

  @ManyToOne(type => User)
  @JoinColumn({ name: "ZSENDER", referencedColumnName: "id" })
    sender?: User

  @Column({ name: "ZTEXT" })
    text?: string
}
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"
import { Message } from "./message"

@Entity("ZUSER")
export class User {
  @PrimaryGeneratedColumn({ name: "Z_PK" })
    id!: number

  @Column({ name: "ZNAME" })
    name?: string

  @OneToMany(type => Message, message => message.sender)
    messages?: Message[]
}

処理

データ構造をうつしたエンティティを書いたらこんな感じで利用する。

import { ConnectionOptions, createConnection } from "typeorm"
import { root } from "./paths"
import { User } from "./entity/user"
import { Message } from "./entity/message"

const options: ConnectionOptions = {
  type: "sqlite",
  database: `${root}/data/line.sqlite`,
  entities: [ User, Message ],
  logging: true
}

async function main () {
  const connection = await createConnection(options)
  const messageRepository = connection.getRepository(Message)
  const allMessages = await messageRepository.find()
  // メッセージを検索する
  allMessages.forEach((message: Message) => {
    const text = message.text
    if (!text) {
      return
    }
    if (text.match(/ape/)) {
      console.log(text)
    }
  })
  // メッセージと送信者を紐付ける
  const messages = await messageRepository
    .createQueryBuilder("ZMESSAGE")
    .leftJoinAndSelect("ZMESSAGE.sender", "ZUSER")
    .where("ZMESSAGE.Z_PK=:id")
    .setParameter("id", 3)
    .getMany()
  console.log(messages[0].sender)
}

main().catch(console.error)

おわり(^ω^ )

無事パスワードをサルベージして、ログインすることができました。ついでに、この記事を書いてある間に、RAIDのリビルドも終わって最高マジ卍

今回のコード全体

苦情はコチラ

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5