使っていないが存在はするTagsやCategoryをリストから除く

👤horomi

過去の記事を整理した。

消すまでではないけれど、公開することもないかな。。。という記事を非公開にした。

カテゴリーやタグにあった項目も今となっては使わなくなっていたり、あることで余計に記事の属性が分かりにくくなりそうな部分を直した。

NotionDB上の記事はすっかりキレイになったんだけど、ブログ画面を確認してみると調整が必要な箇所に遭遇した。

  • 非公開記事上では指定しているタグやカテゴリーがブログ画面のTagsリストやCategorysリスト(以下、リスト)に表示されてしまっている【本番環境】
  • そもそも記事に指定することもしなくなったタグやカテゴリーまでリストに表示されている【本番環境】【開発環境】

そこで2点直すことにした。

  1. 非公開にしている記事で指定しているタグやカテゴリーをリストから除く【本番環境】
  2. 公開記事や非公開記事に指定していないタグやカテゴリーはリストに反映されないようにする【本番環境】【開発環境】

直している最中にキャッシュのif文が重複している箇所を発見したのでそこも修正した。

※ 今回のタグやカテゴリー関連以外のキャッシュ処理も重複していたので後日直すことにする

getAllPostsはキャッシュ処理をしている

getAllTags()はキャッシュがあればgetAllPosts()を使って処理するようになっていた。

export async function getAllTags(): Promise<string[]> {

  if (blogIndexCache.exists()) {
    const allPosts = await getAllPosts()
    return [...new Set(allPosts.flatMap((post) => post.Tags))].sort()
  }
  const res = (await client.databases.retrieve({
    database_id: DATABASE_ID,
  })) as unknown as responses.RetrieveDatabaseResponse
  return res.properties.Tags.multi_select.options
    .map((option) => option.name)
    .sort()
}
lib/notion/client.ts

キャッシュがあればgetAllPostsを使い、キャッシュがなければNotionAPIにリクエストを飛ばす。

でも、getAllPostsもキャッシュのあるなしで同じ分岐をさせていた。

export async function getAllPosts(): Promise<Post[]> {
  let results = []

  if (blogIndexCache.exists()) {
    results = blogIndexCache.get()
    console.log('Found cached posts.')
  } else {
    const params: QueryDatabaseParameters = {
      database_id: DATABASE_ID,
      filter: _buildFilter(),
      sorts: [
        {
          property: 'Date',
          direction: 'descending',
        },
      ],
      page_size: 100,
    }

    while (true) {
      const res = await client.databases.query(params)

      results = results.concat(res.results)

      if (!res.has_more) {
        break
      }

      params['start_cursor'] = res.next_cursor
    }
  }

  return results
    .filter((pageObject) => _validPageObject(pageObject))
    .map((pageObject) => _buildPost(pageObject))
}
lib/notion/client.ts

getAllPostsを使えばキャッシュの有無の分岐がなされる。
ならば、getAllTagsはキャッシュの有無の分岐からはじめる必要はないのでは!?

という意図で以下のように直すことにした。

export async function getAllTags(): Promise<string[]> {
  const allPosts = await getAllPosts()
  return [...new Set(allPosts.flatMap((post) => post.Tags))].sort()
}

getCategorysも同じ処理なので同様に直した。

DBにあるだけのretrieveと記事に所属するquery

修正前のgetAllTagsで使われていたclient.databases.retrieveというNotionAPIの関数が行っていた処理は、NotionDBに登録されているTagsプロパティの内容だった。

これに対し、
修正後の方は、getAllTags上ではキャッシュ判定はせず、getAllPosts内でキャッシュ判定をした後に動くclient.databases.queryは記事で使用されているTags情報を取って来ている。

だから、修正前では記事で使用していないがNotionDBには存在しているTagsがリストに表示されるという現象があった。

ブログの整理でブログラムの処理を向上させられた

今回、たまたま不具合を発見した。

実際に必要になって使用したらプログラムが対応していなかったことが分かった。

あらゆるシーンを想定してプログラムすることが理想だけど、作っている時には考えが及ばないことはある。

これは仕方ない。

使えば使うだけブログのプログラムが成長する。
だから使っていきたいと改めて感じた。

直していた時に、関連の関数の記述が気になって勉強した。以下参照

_buildFilterのconditions

開発環境かどうかで分岐している関数。

このconditionsって具体的にどんな内容なのかがイメージできていなかったことに気づいた。

function _buildFilter(conditions = []) {
  if (process.env.NODE_ENV === 'development') {
    return { and: conditions }
  }

  return {
    and: _uniqueConditions(
      conditions.concat([
        {
          property: 'Published',
          checkbox: {
            equals: true,
          },
        },
        {
          property: 'Date',
          date: {
            on_or_before: new Date().toISOString(),
          },
        },
      ])
    ),
  }
}
lib/notion/client.ts

実際に_buildFilters([ ])に渡しているところを観察してみる。

const params: QueryDatabaseParameters = {
    database_id: DATABASE_ID,
    filter: _buildFilter([
      {
        property: 'Rank',
        number: {
          is_not_empty: true,
        },
      },
    ]),
    sorts: [
      {
        property: 'Rank',
        direction: 'descending',
      },
    ],
    page_size: pageSize,
  }
lib/notion/client.tsのgetRankedPosts関数内

propertyの情報が入れられていることが分かる。

_buildFilterではpropertyとして渡ってくる情報をAND条件にして返すということだ。

また、開発環境ではない場合には渡ってきたproperty情報にpropertyのpublishedとdateを加えて返している。

_uniqueConditionsのproperties

propertyをconcatする時に動かす_uniqueConditionsでは何をしているのか?

function _uniqueConditions(conditions = []) {
  const properties = []

  return conditions.filter((cond) => {
    if (properties.includes(cond.property)) {
      return false
    }
    properties.push(cond.property)
    return true
  })
}
lib/notion/client.ts

渡ってきたpropertyのあとにconcatで指定しているpropertyのpublishedとdateがある。

このとき、渡ってきたpropertyと指定していたpropertyとが重複する場合がある。

例えばこんな感じ↓

  1. 渡ってきたproperty:published:がfalseの情報
    • const properties=[ ]に入れる
  2. 指定していたproperty:publishedがtrueの情報とdateがon_or_beforeの情報
    • propertiesに入っているpropertyの情報が今処理しようとしているpropertyの情報を含んでいるかを判定
    • 含んでいたらスキップ。既に存在しているpropertyの情報が優先的に残る
    • 含んでいなかったらconst properties=[ ]に入れる

propertyの重複がないように処理している関数だった。

私はこの、先に登場する const properties = [] という変数がどうも苦手だ。


propertyの処理について少しばかり理解が深まった気がする。☻