坂本  篤司

坂本 篤司

1659686400

究極の TypeScript クエリ ビルダーの設計

戻り値の型を自動的に推測しながら、任意の複雑さのクエリを表現できる TypeScript のクエリ ビルダーの設計に着手しました。

簡単ではありませんでしたが、JavaScript の最もクールな最新機能のいくつかと、いくつかの暗い TypeScript の魔法の助けを借りて、私たちはそれをやってのけたと思います. その結果、ORM の型安全性と本格的なクエリ言語の表現力が組み合わされた、最高のものが提供されます。

今すぐクエリ ビルダーを試すことができます。MCU サンドボックスリポジトリのクローンを作成し、指示に従ってプロジェクトを初期化することをお勧めします。これには 1 分もかかりません。

SQLの続編

 

重要な注意: これは、EdgeDB のオブジェクト指向クエリ言語である EdgeQL のクエリ ビルダーです。SQL の精神的な後継者として設計されており、最大のユーザビリティの問題を解決します。この投稿全体を通して、[EdgeQL] タブをクリックして、各クエリ ビルダー式に相当する EdgeQL を確認してください。

TypeScript

const query = e.select(e.Movie, movie => ({
  id: true,
  title: true,
  actors: {
    name: true,
  },
  filter: e.op(movie.title, '=', 'Iron Man 3')
}));

// inferred type:
// { id: string; title: string; actors: { name: string }[]}

EdgeQL

select Movie {
  id,
  title,
  actors: {
    name
  }
}
filter .title = "Iron Man 3"

取得するフィールドを指定する GraphQL スタイルの「選択形状」に注意してください。ご想像のとおり、このクエリは行のフラットなリストではなく、構造化された JSON のような結果を返します。

{
  "id": "9278d96e-1932-44e4-a9b3-34e49b592c26",
  "title": "Iron Man 3",
  "release_year": 2013,
  "actors": [
    { "name": "Robert Downey Jr." },
    { "name": "Gwyneth Paltrow" },
    { "name": "Ben Kingsley" }
  ]
}

上記のクエリは、EdgeDB のスキーマ定義言語で定義されている次のスキーマを想定しています。

type Movie {
  required property title -> str;
  property release_year -> int64;
  multi link actors -> Person;
}

type Person {
  required property name -> str;
}

クエリ ビルダーの生成

クエリ ビルダーの使用を開始するには、EdgeDB インスタンスを起動する必要があります。これを行う最も簡単な方法は、EdgeDB CLI をインストールedgedb project initしてプロジェクト ディレクトリで実行することです。より完全な概要については、クイックスタートに従ってください。

edgedb次に、NPM からパッケージをインストールし、次のnpxコマンドを実行します。

$ npm install edgedb
$ npx edgeql-js

このコマンドは、データベースをイントロスペクトし、いくつかのファイルをdbschema/edgeql-jsディレクトリに生成します。(慣例により、dbschemaは、スキーマ ファイルや移行ファイルなど、EdgeDB 関連のものを保存するために使用されるディレクトリです。) クエリ ビルダーは、 という単一の変数としてインポートすることをお勧めしますe

import e from "./dbschema/edgeql-js";

この変数には、任意に複雑な EdgeQL クエリを定義するために必要なすべてが含まれていますが、「Hello World」クエリという小さなものから始めましょう。

import e from "./dbschema/edgeql-js";

const query = e.select("hello world!");

このe.select関数は、EdgeQL クエリを表すオブジェクトを返します。これを「クエリ ビルダー式」または単に「式」と呼びます。

式を実行するには、クライアントを式の.run()メソッドに渡します。

このcreateClient関数は次のインスタンスを返しますClient: EdgeDB インスタンスへの接続のプールを管理し、クエリを実行するための単純な API を提供するクラス。

import {createClient} from "edgedb";
import e from "./dbschema/edgeql-js";

const client = createClient();

const query = e.select("Hello world!");
const result = await query.run(client);
// => "Hello world!"

この.runメソッドは、厳密に型指定された Promise を返します。クエリ ビルダーは、すべての式の戻り値の型を自動的に推測します。上記の例でresultは、stringタイプがあります。このタイプは$inferヘルパーで抽出できます。

import {createClient} from "edgedb";
import e, {$infer} from "./dbschema/edgeql-js";

const client = createClient();

const query = e.select("Hello world!");
type query = $infer<typeof query>;
// string

いくつかの重要なクエリを見てみましょう。

オブジェクトの挿入

e.insert関数を使用してinsertクエリを記述します。

TypeScript

e.insert(e.Movie, {
  title: "Doctor Strange in the Multiverse of Madness",
  release_year: 2022
});

EdgeQL

insert Movie {
  title := "Doctor Strange in the Multiverse of Madness",
  release_year := 2022
}

最初の引数はオブジェクト タイプです。これらは、クエリ ビルダーによって自動生成されます。2 番目の引数には、挿入するデータが含まれます。idプロパティが含まれていないことに注意してください。EdgeDB によって自動生成されます。

titleプロパティには type があるためstre.insert当然文字列値が期待されます。同様release_yearに typeint64を持っているので、数値が必要です。次の表は、各 EdgeDB スカラー型を最も近い TypeScript の対応する型にマップします。

EdgeDB タイプJavaScript タイプ
strstring
boolboolean
float32 float64 int16 int32 int64number
jsonstring
uuidstring
bigintBigInt
decimal該当なし (サポートされていません)
bytesBuffer
datetimeDate
durationDuration()
cal::local_dateLocalDate()
cal::local_timeLocalTime()
cal::local_datetimeLocalDateTime()

このような JavaScript に相当するものがない特定の型についてdurationは、そのデータ型を表すカスタム クラスを実装しました。

ネストされたインサート

 

EdgeQL と同様に、サブクエリは完全に無痛です。e.insertネストされた挿入を行うには、1 つを別のものにドロップするだけです。

TypeScript

e.insert(e.Movie, {
  title: "Iron Man",
  release_year: 2008,
  actors: e.set(
    e.insert(e.Person, { name: "Robert Downey Jr." }),
    e.insert(e.Person, { name: "Gwyneth Paltrow" })
  ),
});

EdgeQL

insert Movie {
  title := "Iron Man",
  release_year : 2008,
  actors := {
    (insert Person { name := "Robert Downey Jr." }),
    (insert Person { name := "Gwyneth Paltrow" })
  }
}

上記では、関数を使用して setliterale.set定義しています。EdgeQL では、これは中かっこで示されます。select {'a', 'b', 'c'}

オブジェクトの選択

 

次に肉とじゃがいも:オブジェクトの選択. データベース内のすべての映画を選択することから始めましょう。

TypeScript

const query = e.select(e.Movie, () => ({
  id: true,
  title: true
}));

const result = await query.run(client);
// {id: string; title: string;}[]

EdgeQL

select Movie {
  id,
  title,
  release_year
}

オブジェクトのすべてのプロパティを選択するための省略形として、spread operator を特殊な*プロパティと組み合わせて使用​​します。これはクエリ ビルダー機能であり、EdgeQL に相当するものは (まだ) ありません。プレーンな EdgeQL は機能をサポートしていませんselect *

const query = e.select(e.Movie, () => ({
  ...e.Movie['*']
}));

const result = await query.run(client);
/* {
  id: string;
  title: string;
  release_year: number | null;
}[] */

ご想像のとおり、プロパティの型はrelease_yearオプションnumber | nullのプロパティです。

ネスティング形状

のようなリンクされたオブジェクトを取得するために、シェイプをネストできますactors

TypeScript

const query = e.select(e.Movie, () => ({
  title: true,
  actors: {
    name: true,
  }
}));

const result = await query.run(client);
// { title: string, actors: {name: string}[] }[]

EdgeQL

select Movie {
  title,
  actors: {
    name
  }
}

計算されたプロパティの追加

この時点で、なぜ の 2 番目の引数がe.select単純なオブジェクトではなく関数なのか不思議に思うかもしれません。そうですね: クエリ ビルダーは、単純な GraphQL スタイルの選択セットよりも多くのことができます。まず、計算されたプロパティを定義できます。

TypeScript

const query = e.select(e.Movie, (movie) => ({
  title: true,
  title_upper: e.str_upper(movie.title),
  cast_size: e.count(movie.actors)
}));

const result = await query.run(client);
// { title: string; title_upper: string; cast_size: number }[]

EdgeQL

select Movie {
  title,
  title_upper := str_upper(.title),
  cast_size := count(.actors)
}

「形状関数」には次の引数がありますmovie。この変数は「スコープ」を表します。これを使用して、選択しているユーザーのプロパティとリンクを参照できます。この場合、2 つの組み込み関数を使用していくつかの単純な計算式を定義しています:e.counte.str_upper; クエリ ビルダーは、EdgeDB 標準ライブラリ全体を反映しています。

title_upperああ、クエリビルダーがandの型を正しく推測したことに注意してくださいcast_size! このクエリの結果は次のようになります。

[
  {
    title: "Iron Man",
    title_upper: "IRON MAN",
    cast_size: 2
  },
  // etc.
]

フィルターの追加

 

filter選択クエリに句を追加するにはfilter、シェイプに特殊キーを含めます。このキーにはブール式が必要です。最も一般的には、この式には、、、、、およびなどの演算子が含まれます。演算子は関数で表現されます。=>=++notore.op

以下では、タイトルに「matrix」(大文字と小文字を区別しない)を含むすべての映画を選択しています。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  release_year: true,
  filter: e.op(movie.title, "ilike", "%matrix%"),
}));

EdgeQL

select Movie {
  title,
  release_year
} filter .title ilike "%matrix%"

関連するEdgeDB タイプに応じて、式はさまざまなプロパティとメソッドを持つことができます。たとえば、str(上記のような) 値に対応する式はmovie.title、簡単にインデックスを作成してスライスすることができます。array(これは、、、tupleおよび式にも当てはまりますjson。)

movie.titleこれは文字列ではないことに注意してください。文字列を返すクエリを表すオブジェクトですさらに、さらに別の式を返します。クエリ ビルダーは、プロキシ APIを利用して、この「マジック インデックス」を実装します。movie.title[0]

これを使用して、文字「A」で始まるすべての映画を選択できます。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  release_year: true,
  filter: e.op(movie.title[0], "=", "A"),
}));

EdgeQL

select Movie {
  title,
  release_year
} filter .title[0] = "A"

フラットな API

この時点で、形状が少し混み合っていると思われるかもしれません。フィールドの選択、計算されたプロパティ、およびフィルターを定義するために単一のオブジェクトを使用するのはなぜですか? 重要な競合はありませんか?

実は違う!これは非常に意図的な決定です。EdgeQL は「filter」などの特定のキーワードを予約しているため、プロパティやリンク名として簡単に使用できません。計算フィールドに関しては、選択シェイプ内のプロパティ/リンクを「上書き」することはできません。TypeScript (および EdgeQL) はエラーをスローします。

この API では、クエリの深さの各レイヤーが、オブジェクトのネストの 1 つのレイヤーに対応します。

e.select(e.Movie, (movie) => ({ id: true, title: true, actors: (actor) => ({ name: true, filter: e.op(actor.name, "ilike", "chris") }), filter: e.op(movie.release_year, "=", 2022) }));

Prisma vs EdgeDB

これを、最新の JavaScript ORM のより冗長な構文と比較してください。Prisma では、クエリの深さの追加レイヤーごとに 2 つのレイヤーのオブジェクト ネストが必要です。Prisma クライアントで表現された同じクエリを次に示します。

prisma.movie.findMany({
  where: {
    release_year: {
      eq: 2022
    }
  },
  select: {
    id: true,
    title: true,
    actors: {
      select: {
        name: true
      },
      where: {
        name: {
          contains: "chris",
          mode: "insensitive"
        }
      }
    }
  }
});

カーディナリティの推測

 

クエリ ビルダは、単一のオブジェクトを選択しようとしているときにそれを認識できるほどスマートです。例えば:

const query = e.select(e.Movie, (movie) => ({
  title: true,
  filter: e.op(movie.id, '=', e.uuid('2053a8b4-49b1-437a-84c8-e1b0291ccd9f'))
}));

const result = await query.run(client);
// { title: string } | null

推測される結果の型は{ title: string } | nullです。代わりに のような排他的でないプロパティでフィルター処理するrelease_yearと、結果は配列になります。

  const query = e.select(e.Movie, (movie) => ({
    title: true,
    filter: e.op(movie.id, '=', e.uuid('2053a8b4-49b1-437a-84c8-e1b0291ccd9f'))
    filter: e.op(movie.release_year, '=', 2022)
  }));

  const result = await query.run(client);
  // { title: string }[]

.idクエリ ビルダは、等値演算子 ( ) を使用した排他的 (一意性) 制約 ( など) を使用してプロパティをフィルター処理したことを検出します=。このような状況では、クエリは 0 個または 1 個のオブジェクトしか返すことができません。これは、推論された型に反映されます。.findOneそのため、 とに別々の API を用意する必要はありません.findMany。クエリ ビルダーがそれを判断できます。

注文とページ付け

特殊order_byキーは、 の結果に対する順序付け操作を指定するために使用できselectlimit/offsetはページネーションに使用できます。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  order_by: e.count(movie.actors),
  limit: 10,
  offset: 40
}));

EdgeQL

select Movie {
  title
}
order by count(.actors)
limit 10
offset 40

このorder_byキーは、カスタマイズ可能な方向と空の処理ポリシーを備えた複合注文をサポートしています。

e.select(e.Movie, (movie) => ({
  title: true,
  order_by: [
    {
      expression: e.count(movie.actors),
      direction: e.ASC,
      empty: e.EMPTY_LAST,
    },
    {
      expression: movie.title,
      direction: e.DESC,
    }
  ]
}));

オブジェクトの更新

 

TypeScript

e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', 'Avengers: Infinity War - Part II'),
  set: {
    title: 'Avengers: Endgame',
  },
}));

EdgeQL

 e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', 'Avengers: Infinity War - Part II'),
  set: {
    title: 'Avengers: Endgame',
  },
}));

自己参照の更新

 

クエリ ビルダは、プロパティを現在の値の変更されたバージョンに設定するときに特に便利です (または、ORM は特に悪い)。たとえば、このクエリは、すべての映画のタイトルから余分な空白を削除します。

TypeScript

e.update(e.Movie, (movie) => ({
  set: {
    title: e.str_trim(movie.title),
  },
}));

EdgeQL

 update Movie
set {
  title := str_trim(.title)
}

ORM では、これは表現できません。データベース内のすべての映画を反復処理するスクリプトを作成する必要があります。

リンクの更新

 

リンクを更新する場合、クエリ ビルダーは、リンクされたオブジェクトのセットに追加または削除するための特別な構文をサポートしています。

TypeScript

const actors = e.select(e.Person, person => ({
  filter: e.op(person.name, 'in', e.set('Benedict Cumberbatch', 'Rachel McAdams'))
}));

const query = e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', "Doctor Strange"),
  set: {
    actors: {'+=': actors},
  }
})).run(client);

EdgeQL

with actors := (
  select Person
  filter .name in {'Benedict Cumberbatch', 'Rachel McAdams'}
)
update Movie
filter .title = "Doctor Strange"
set {
  actors += actors
}

クエリの作成

 

前のupdate例は、クエリ ビルダーの最大の強みの 1 つである構成性も示しています。クエリの宣言実行は 2つの異なるステップであるため、クエリの一部を個別に宣言し、後でそれらをすべてまとめることができます。複雑なクエリを作成することは、スクリプトを作成するように感じます。

たとえば、複数の式を構成して、ネストされた挿入 + 選択を 1 つのクエリで実行できます。

TypeScript

const rdj = e.insert(e.Person, {
  name: "Robert Downey Jr."
});

const ironMan = e.insert(e.Movie, {
  title: "Iron Man",
  release_year: 2008,
  actors: rdj
});

const query = e.select(ironMan, () => ({
  title: true,
  release_year: true,
  num_actors: e.count(ironMan.actors)
}));

const result = await query.run(client);
// {title: string; release_year: number; num_actors: number}

EdgeQL

with
  rdj := (
    insert Person {
      name := "Robert Downey Jr."
    }
  ),
  ironMan := (
    insert Movie {
      title := "Iron Man",
      release_year := 2008
    }
  )
select ironMan {
  title,
  release_year,
  num_actors := count(.actors)
};

クエリビルダーは、newMovie内部で複数回発生することを検出しquery、それをブロックに抽出しwithます (別名、SQL 用語では「共通テーブル式」)。1 つしかないことに注意してくださいawait実行 していませんrdjand ironMan; これらは、データベースへの 1 回の往復で実行できる最終的な「スーパークエリ」に構成されるサブクエリです。

クエリ パラメータの使用

 

最後のチェリーとして、クエリ ビルダーを使用すると、クエリを簡単にパラメーター化できます。POSTこれにより、タイプセーフな方法で外部データ (受信リクエストの本文など) を使用できます。

TypeScript

const query = e.params(
  { title: e.str, release_year: e.int64 },
  ($) => {
    return e.insert(e.Movie, {
      title: $.title,
      release_year: $.release_year,
    });
  }
);

const result = await query.run(client, {
  title: 'Thor: Love and Thunder',
  release_year: 2022,
});

EdgeQL

with
 title := <str>$title,
 release_year := <int64>$release_year
insert Movie {
 title := title,
 release_year := release_year
}

パラメータ化されたクエリの場合、パラメータを 2 番目の引数として に渡します.run()。厳密に型指定され、実行時に検証されます。

ORMとの比較

上記の例から明らかであることを願っていますが、表現力という点では、クエリ ビルダーは、私たちが認識しているすべての ORM を超えています。概して、ORM は比較的基本的な読み取り/書き込み操作しか表現できませんが、適切なクエリ言語はさらに多くのことを表現できます。

  • 文字列の変更
  • イテラブルのインデックス作成とスライス
  • 集計
  • 算数
  • 時相論理
  • 合体とデフォルト ( ??JavaScript)
  • 条件 ( a ? b : cJavaScript)
  • パラメータ化
  • unionまたはのようなロジックを設定しますin
  • 型ロジックとキャスト
  • クエリ構成 (AKA 共通テーブル式)
  • 計算されたプロパティ
  • ポリモーフィック クエリ
  • 自己参照の更新

これは、スキーマ モデリングについては言うまでもありません。EdgeDB は、ほとんどの ORM に欠けているさらに多くの機能をサポートしています。

  • 計算されたプロパティ — これらは、プロパティがフェッチされるたびに動的に実行される EdgeQL に対応する「仮想」プロパティです。
  • 計算されたデフォルト
  • 複雑な制約ロジック
  • スキーマ ミックスイン (継承)
  • リンク プロパティ
  • 全範囲の数値型 ( int{16,|32|64}float{32|64}bigint、およびdecimal)
  • durationおよび非タイムゾーン対応の日付と時刻のような一時的な型
  • プランナーと追跡システムを含む、データベース ネイティブの移行システム

今後の方向性

 

クエリ ビルダーは、2022 年 2 月の EdgeDB 1.0 リリース以降に利用可能であり、安定しており、運用に対応しています。e.groupクエリ ビルダーは最近アップグレードされ、ステートメントやグローバル スキーマ変数など、すべての EdgeDB 2.0 機能をサポートするようになりました。この投稿では、クエリ ビルダーの全機能のサブセットのみを取り上げます。より包括的な外観については、ドキュメントを参照してください。

2022 年 7 月 28 日のライブストリーム配信開始イベントで EdgeDB 2.0 をリリースします。最大の新機能と EdgeDB の新しい管理 UI の最初の公開デモについてのライトニング トークに参加してください。

ソース: https://www.edgedb.com/blog/designing-the-ultimate-typescript-query-builder

#typescript #EdgeDB

What is GEEK

Buddha Community

究極の TypeScript クエリ ビルダーの設計

The Definitive Guide to TypeScript & Possibly The Best TypeScript Book

TypeScript Deep Dive

I've been looking at the issues that turn up commonly when people start using TypeScript. This is based on the lessons from Stack Overflow / DefinitelyTyped and general engagement with the TypeScript community. You can follow for updates and don't forget to ★ on GitHub 🌹

Reviews

  • Thanks for the wonderful book. Learned a lot from it. (link)
  • Its probably the Best TypeScript book out there. Good Job (link)
  • Love how precise and clear the examples and explanations are! (link)
  • For the low, low price of free, you get pages of pure awesomeness. Chock full of source code examples and clear, concise explanations, TypeScript Deep Dive will help you learn TypeScript development. (link)
  • Just a big thank you! Best TypeScript 2 detailed explanation! (link)
  • This gitbook got my project going pronto. Fluent easy read 5 stars. (link)
  • I recommend the online #typescript book by @basarat you'll love it.(link)
  • I've always found this by @basarat really helpful. (link)
  • We must highlight TypeScript Deep Dive, an open source book.(link)
  • Great online resource for learning. (link)
  • Thank you for putting this book together, and for all your hard work within the TypeScript community. (link)
  • TypeScript Deep Dive is one of the best technical texts I've read in a while. (link)
  • Thanks @basarat for the TypeScript Deep Dive Book. Help me a lot with my first TypeScript project. (link)
  • Thanks to @basarat for this great #typescript learning resource. (link)
  • Guyz excellent book on Typescript(@typescriptlang) by @basarat (link)
  • Leaning on the legendary @basarat's "TypeScript Deep Dive" book heavily at the moment (link)
  • numTimesPointedPeopleToBasaratsTypeScriptBook++; (link)
  • A book not only for typescript, a good one for deeper JavaScript knowledge as well. link
  • In my new job, we're using @typescriptlang, which I am new to. This is insanely helpful huge thanks, @basarat! link
  • Thank you for writing TypeScript Deep Dive. I have learned so much. link
  • Loving @basarat's @typescriptlang online book basarat.gitbooks.io/typescript/# loaded with great recipes! link
  • Microsoft doc is great already, but if want to "dig deeper" into TypeScript I find this book of great value link
  • Thanks, this is a great book 🤓🤓 link
  • Deep dive to typescript is awesome in so many levels. i find it very insightful. Thanks link
  • @basarat's intro to @typescriptlang is still one of the best going (if not THE best) link
  •  
  • This is sweet! So many #typescript goodies! link

Get Started

If you are here to read the book online get started.

Translations

Book is completely free so you can copy paste whatever you want without requiring permission. If you have a translation you want me to link here. Send a PR.

Other Options

You can also download one of the Epub, Mobi, or PDF formats from the actions tab by clicking on the latest build run. You will find the files in the artifacts section.

Special Thanks

All the amazing contributors 🌹

Share

Share URL: https://basarat.gitbook.io/typescript/

Author: Basarat
Source Code: https://github.com/basarat/typescript-book/ 
License: View license

#typescript #opensource 

坂本  篤司

坂本 篤司

1659686400

究極の TypeScript クエリ ビルダーの設計

戻り値の型を自動的に推測しながら、任意の複雑さのクエリを表現できる TypeScript のクエリ ビルダーの設計に着手しました。

簡単ではありませんでしたが、JavaScript の最もクールな最新機能のいくつかと、いくつかの暗い TypeScript の魔法の助けを借りて、私たちはそれをやってのけたと思います. その結果、ORM の型安全性と本格的なクエリ言語の表現力が組み合わされた、最高のものが提供されます。

今すぐクエリ ビルダーを試すことができます。MCU サンドボックスリポジトリのクローンを作成し、指示に従ってプロジェクトを初期化することをお勧めします。これには 1 分もかかりません。

SQLの続編

 

重要な注意: これは、EdgeDB のオブジェクト指向クエリ言語である EdgeQL のクエリ ビルダーです。SQL の精神的な後継者として設計されており、最大のユーザビリティの問題を解決します。この投稿全体を通して、[EdgeQL] タブをクリックして、各クエリ ビルダー式に相当する EdgeQL を確認してください。

TypeScript

const query = e.select(e.Movie, movie => ({
  id: true,
  title: true,
  actors: {
    name: true,
  },
  filter: e.op(movie.title, '=', 'Iron Man 3')
}));

// inferred type:
// { id: string; title: string; actors: { name: string }[]}

EdgeQL

select Movie {
  id,
  title,
  actors: {
    name
  }
}
filter .title = "Iron Man 3"

取得するフィールドを指定する GraphQL スタイルの「選択形状」に注意してください。ご想像のとおり、このクエリは行のフラットなリストではなく、構造化された JSON のような結果を返します。

{
  "id": "9278d96e-1932-44e4-a9b3-34e49b592c26",
  "title": "Iron Man 3",
  "release_year": 2013,
  "actors": [
    { "name": "Robert Downey Jr." },
    { "name": "Gwyneth Paltrow" },
    { "name": "Ben Kingsley" }
  ]
}

上記のクエリは、EdgeDB のスキーマ定義言語で定義されている次のスキーマを想定しています。

type Movie {
  required property title -> str;
  property release_year -> int64;
  multi link actors -> Person;
}

type Person {
  required property name -> str;
}

クエリ ビルダーの生成

クエリ ビルダーの使用を開始するには、EdgeDB インスタンスを起動する必要があります。これを行う最も簡単な方法は、EdgeDB CLI をインストールedgedb project initしてプロジェクト ディレクトリで実行することです。より完全な概要については、クイックスタートに従ってください。

edgedb次に、NPM からパッケージをインストールし、次のnpxコマンドを実行します。

$ npm install edgedb
$ npx edgeql-js

このコマンドは、データベースをイントロスペクトし、いくつかのファイルをdbschema/edgeql-jsディレクトリに生成します。(慣例により、dbschemaは、スキーマ ファイルや移行ファイルなど、EdgeDB 関連のものを保存するために使用されるディレクトリです。) クエリ ビルダーは、 という単一の変数としてインポートすることをお勧めしますe

import e from "./dbschema/edgeql-js";

この変数には、任意に複雑な EdgeQL クエリを定義するために必要なすべてが含まれていますが、「Hello World」クエリという小さなものから始めましょう。

import e from "./dbschema/edgeql-js";

const query = e.select("hello world!");

このe.select関数は、EdgeQL クエリを表すオブジェクトを返します。これを「クエリ ビルダー式」または単に「式」と呼びます。

式を実行するには、クライアントを式の.run()メソッドに渡します。

このcreateClient関数は次のインスタンスを返しますClient: EdgeDB インスタンスへの接続のプールを管理し、クエリを実行するための単純な API を提供するクラス。

import {createClient} from "edgedb";
import e from "./dbschema/edgeql-js";

const client = createClient();

const query = e.select("Hello world!");
const result = await query.run(client);
// => "Hello world!"

この.runメソッドは、厳密に型指定された Promise を返します。クエリ ビルダーは、すべての式の戻り値の型を自動的に推測します。上記の例でresultは、stringタイプがあります。このタイプは$inferヘルパーで抽出できます。

import {createClient} from "edgedb";
import e, {$infer} from "./dbschema/edgeql-js";

const client = createClient();

const query = e.select("Hello world!");
type query = $infer<typeof query>;
// string

いくつかの重要なクエリを見てみましょう。

オブジェクトの挿入

e.insert関数を使用してinsertクエリを記述します。

TypeScript

e.insert(e.Movie, {
  title: "Doctor Strange in the Multiverse of Madness",
  release_year: 2022
});

EdgeQL

insert Movie {
  title := "Doctor Strange in the Multiverse of Madness",
  release_year := 2022
}

最初の引数はオブジェクト タイプです。これらは、クエリ ビルダーによって自動生成されます。2 番目の引数には、挿入するデータが含まれます。idプロパティが含まれていないことに注意してください。EdgeDB によって自動生成されます。

titleプロパティには type があるためstre.insert当然文字列値が期待されます。同様release_yearに typeint64を持っているので、数値が必要です。次の表は、各 EdgeDB スカラー型を最も近い TypeScript の対応する型にマップします。

EdgeDB タイプJavaScript タイプ
strstring
boolboolean
float32 float64 int16 int32 int64number
jsonstring
uuidstring
bigintBigInt
decimal該当なし (サポートされていません)
bytesBuffer
datetimeDate
durationDuration()
cal::local_dateLocalDate()
cal::local_timeLocalTime()
cal::local_datetimeLocalDateTime()

このような JavaScript に相当するものがない特定の型についてdurationは、そのデータ型を表すカスタム クラスを実装しました。

ネストされたインサート

 

EdgeQL と同様に、サブクエリは完全に無痛です。e.insertネストされた挿入を行うには、1 つを別のものにドロップするだけです。

TypeScript

e.insert(e.Movie, {
  title: "Iron Man",
  release_year: 2008,
  actors: e.set(
    e.insert(e.Person, { name: "Robert Downey Jr." }),
    e.insert(e.Person, { name: "Gwyneth Paltrow" })
  ),
});

EdgeQL

insert Movie {
  title := "Iron Man",
  release_year : 2008,
  actors := {
    (insert Person { name := "Robert Downey Jr." }),
    (insert Person { name := "Gwyneth Paltrow" })
  }
}

上記では、関数を使用して setliterale.set定義しています。EdgeQL では、これは中かっこで示されます。select {'a', 'b', 'c'}

オブジェクトの選択

 

次に肉とじゃがいも:オブジェクトの選択. データベース内のすべての映画を選択することから始めましょう。

TypeScript

const query = e.select(e.Movie, () => ({
  id: true,
  title: true
}));

const result = await query.run(client);
// {id: string; title: string;}[]

EdgeQL

select Movie {
  id,
  title,
  release_year
}

オブジェクトのすべてのプロパティを選択するための省略形として、spread operator を特殊な*プロパティと組み合わせて使用​​します。これはクエリ ビルダー機能であり、EdgeQL に相当するものは (まだ) ありません。プレーンな EdgeQL は機能をサポートしていませんselect *

const query = e.select(e.Movie, () => ({
  ...e.Movie['*']
}));

const result = await query.run(client);
/* {
  id: string;
  title: string;
  release_year: number | null;
}[] */

ご想像のとおり、プロパティの型はrelease_yearオプションnumber | nullのプロパティです。

ネスティング形状

のようなリンクされたオブジェクトを取得するために、シェイプをネストできますactors

TypeScript

const query = e.select(e.Movie, () => ({
  title: true,
  actors: {
    name: true,
  }
}));

const result = await query.run(client);
// { title: string, actors: {name: string}[] }[]

EdgeQL

select Movie {
  title,
  actors: {
    name
  }
}

計算されたプロパティの追加

この時点で、なぜ の 2 番目の引数がe.select単純なオブジェクトではなく関数なのか不思議に思うかもしれません。そうですね: クエリ ビルダーは、単純な GraphQL スタイルの選択セットよりも多くのことができます。まず、計算されたプロパティを定義できます。

TypeScript

const query = e.select(e.Movie, (movie) => ({
  title: true,
  title_upper: e.str_upper(movie.title),
  cast_size: e.count(movie.actors)
}));

const result = await query.run(client);
// { title: string; title_upper: string; cast_size: number }[]

EdgeQL

select Movie {
  title,
  title_upper := str_upper(.title),
  cast_size := count(.actors)
}

「形状関数」には次の引数がありますmovie。この変数は「スコープ」を表します。これを使用して、選択しているユーザーのプロパティとリンクを参照できます。この場合、2 つの組み込み関数を使用していくつかの単純な計算式を定義しています:e.counte.str_upper; クエリ ビルダーは、EdgeDB 標準ライブラリ全体を反映しています。

title_upperああ、クエリビルダーがandの型を正しく推測したことに注意してくださいcast_size! このクエリの結果は次のようになります。

[
  {
    title: "Iron Man",
    title_upper: "IRON MAN",
    cast_size: 2
  },
  // etc.
]

フィルターの追加

 

filter選択クエリに句を追加するにはfilter、シェイプに特殊キーを含めます。このキーにはブール式が必要です。最も一般的には、この式には、、、、、およびなどの演算子が含まれます。演算子は関数で表現されます。=>=++notore.op

以下では、タイトルに「matrix」(大文字と小文字を区別しない)を含むすべての映画を選択しています。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  release_year: true,
  filter: e.op(movie.title, "ilike", "%matrix%"),
}));

EdgeQL

select Movie {
  title,
  release_year
} filter .title ilike "%matrix%"

関連するEdgeDB タイプに応じて、式はさまざまなプロパティとメソッドを持つことができます。たとえば、str(上記のような) 値に対応する式はmovie.title、簡単にインデックスを作成してスライスすることができます。array(これは、、、tupleおよび式にも当てはまりますjson。)

movie.titleこれは文字列ではないことに注意してください。文字列を返すクエリを表すオブジェクトですさらに、さらに別の式を返します。クエリ ビルダーは、プロキシ APIを利用して、この「マジック インデックス」を実装します。movie.title[0]

これを使用して、文字「A」で始まるすべての映画を選択できます。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  release_year: true,
  filter: e.op(movie.title[0], "=", "A"),
}));

EdgeQL

select Movie {
  title,
  release_year
} filter .title[0] = "A"

フラットな API

この時点で、形状が少し混み合っていると思われるかもしれません。フィールドの選択、計算されたプロパティ、およびフィルターを定義するために単一のオブジェクトを使用するのはなぜですか? 重要な競合はありませんか?

実は違う!これは非常に意図的な決定です。EdgeQL は「filter」などの特定のキーワードを予約しているため、プロパティやリンク名として簡単に使用できません。計算フィールドに関しては、選択シェイプ内のプロパティ/リンクを「上書き」することはできません。TypeScript (および EdgeQL) はエラーをスローします。

この API では、クエリの深さの各レイヤーが、オブジェクトのネストの 1 つのレイヤーに対応します。

e.select(e.Movie, (movie) => ({ id: true, title: true, actors: (actor) => ({ name: true, filter: e.op(actor.name, "ilike", "chris") }), filter: e.op(movie.release_year, "=", 2022) }));

Prisma vs EdgeDB

これを、最新の JavaScript ORM のより冗長な構文と比較してください。Prisma では、クエリの深さの追加レイヤーごとに 2 つのレイヤーのオブジェクト ネストが必要です。Prisma クライアントで表現された同じクエリを次に示します。

prisma.movie.findMany({
  where: {
    release_year: {
      eq: 2022
    }
  },
  select: {
    id: true,
    title: true,
    actors: {
      select: {
        name: true
      },
      where: {
        name: {
          contains: "chris",
          mode: "insensitive"
        }
      }
    }
  }
});

カーディナリティの推測

 

クエリ ビルダは、単一のオブジェクトを選択しようとしているときにそれを認識できるほどスマートです。例えば:

const query = e.select(e.Movie, (movie) => ({
  title: true,
  filter: e.op(movie.id, '=', e.uuid('2053a8b4-49b1-437a-84c8-e1b0291ccd9f'))
}));

const result = await query.run(client);
// { title: string } | null

推測される結果の型は{ title: string } | nullです。代わりに のような排他的でないプロパティでフィルター処理するrelease_yearと、結果は配列になります。

  const query = e.select(e.Movie, (movie) => ({
    title: true,
    filter: e.op(movie.id, '=', e.uuid('2053a8b4-49b1-437a-84c8-e1b0291ccd9f'))
    filter: e.op(movie.release_year, '=', 2022)
  }));

  const result = await query.run(client);
  // { title: string }[]

.idクエリ ビルダは、等値演算子 ( ) を使用した排他的 (一意性) 制約 ( など) を使用してプロパティをフィルター処理したことを検出します=。このような状況では、クエリは 0 個または 1 個のオブジェクトしか返すことができません。これは、推論された型に反映されます。.findOneそのため、 とに別々の API を用意する必要はありません.findMany。クエリ ビルダーがそれを判断できます。

注文とページ付け

特殊order_byキーは、 の結果に対する順序付け操作を指定するために使用できselectlimit/offsetはページネーションに使用できます。

TypeScript

e.select(e.Movie, (movie) => ({
  title: true,
  order_by: e.count(movie.actors),
  limit: 10,
  offset: 40
}));

EdgeQL

select Movie {
  title
}
order by count(.actors)
limit 10
offset 40

このorder_byキーは、カスタマイズ可能な方向と空の処理ポリシーを備えた複合注文をサポートしています。

e.select(e.Movie, (movie) => ({
  title: true,
  order_by: [
    {
      expression: e.count(movie.actors),
      direction: e.ASC,
      empty: e.EMPTY_LAST,
    },
    {
      expression: movie.title,
      direction: e.DESC,
    }
  ]
}));

オブジェクトの更新

 

TypeScript

e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', 'Avengers: Infinity War - Part II'),
  set: {
    title: 'Avengers: Endgame',
  },
}));

EdgeQL

 e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', 'Avengers: Infinity War - Part II'),
  set: {
    title: 'Avengers: Endgame',
  },
}));

自己参照の更新

 

クエリ ビルダは、プロパティを現在の値の変更されたバージョンに設定するときに特に便利です (または、ORM は特に悪い)。たとえば、このクエリは、すべての映画のタイトルから余分な空白を削除します。

TypeScript

e.update(e.Movie, (movie) => ({
  set: {
    title: e.str_trim(movie.title),
  },
}));

EdgeQL

 update Movie
set {
  title := str_trim(.title)
}

ORM では、これは表現できません。データベース内のすべての映画を反復処理するスクリプトを作成する必要があります。

リンクの更新

 

リンクを更新する場合、クエリ ビルダーは、リンクされたオブジェクトのセットに追加または削除するための特別な構文をサポートしています。

TypeScript

const actors = e.select(e.Person, person => ({
  filter: e.op(person.name, 'in', e.set('Benedict Cumberbatch', 'Rachel McAdams'))
}));

const query = e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', "Doctor Strange"),
  set: {
    actors: {'+=': actors},
  }
})).run(client);

EdgeQL

with actors := (
  select Person
  filter .name in {'Benedict Cumberbatch', 'Rachel McAdams'}
)
update Movie
filter .title = "Doctor Strange"
set {
  actors += actors
}

クエリの作成

 

前のupdate例は、クエリ ビルダーの最大の強みの 1 つである構成性も示しています。クエリの宣言実行は 2つの異なるステップであるため、クエリの一部を個別に宣言し、後でそれらをすべてまとめることができます。複雑なクエリを作成することは、スクリプトを作成するように感じます。

たとえば、複数の式を構成して、ネストされた挿入 + 選択を 1 つのクエリで実行できます。

TypeScript

const rdj = e.insert(e.Person, {
  name: "Robert Downey Jr."
});

const ironMan = e.insert(e.Movie, {
  title: "Iron Man",
  release_year: 2008,
  actors: rdj
});

const query = e.select(ironMan, () => ({
  title: true,
  release_year: true,
  num_actors: e.count(ironMan.actors)
}));

const result = await query.run(client);
// {title: string; release_year: number; num_actors: number}

EdgeQL

with
  rdj := (
    insert Person {
      name := "Robert Downey Jr."
    }
  ),
  ironMan := (
    insert Movie {
      title := "Iron Man",
      release_year := 2008
    }
  )
select ironMan {
  title,
  release_year,
  num_actors := count(.actors)
};

クエリビルダーは、newMovie内部で複数回発生することを検出しquery、それをブロックに抽出しwithます (別名、SQL 用語では「共通テーブル式」)。1 つしかないことに注意してくださいawait実行 していませんrdjand ironMan; これらは、データベースへの 1 回の往復で実行できる最終的な「スーパークエリ」に構成されるサブクエリです。

クエリ パラメータの使用

 

最後のチェリーとして、クエリ ビルダーを使用すると、クエリを簡単にパラメーター化できます。POSTこれにより、タイプセーフな方法で外部データ (受信リクエストの本文など) を使用できます。

TypeScript

const query = e.params(
  { title: e.str, release_year: e.int64 },
  ($) => {
    return e.insert(e.Movie, {
      title: $.title,
      release_year: $.release_year,
    });
  }
);

const result = await query.run(client, {
  title: 'Thor: Love and Thunder',
  release_year: 2022,
});

EdgeQL

with
 title := <str>$title,
 release_year := <int64>$release_year
insert Movie {
 title := title,
 release_year := release_year
}

パラメータ化されたクエリの場合、パラメータを 2 番目の引数として に渡します.run()。厳密に型指定され、実行時に検証されます。

ORMとの比較

上記の例から明らかであることを願っていますが、表現力という点では、クエリ ビルダーは、私たちが認識しているすべての ORM を超えています。概して、ORM は比較的基本的な読み取り/書き込み操作しか表現できませんが、適切なクエリ言語はさらに多くのことを表現できます。

  • 文字列の変更
  • イテラブルのインデックス作成とスライス
  • 集計
  • 算数
  • 時相論理
  • 合体とデフォルト ( ??JavaScript)
  • 条件 ( a ? b : cJavaScript)
  • パラメータ化
  • unionまたはのようなロジックを設定しますin
  • 型ロジックとキャスト
  • クエリ構成 (AKA 共通テーブル式)
  • 計算されたプロパティ
  • ポリモーフィック クエリ
  • 自己参照の更新

これは、スキーマ モデリングについては言うまでもありません。EdgeDB は、ほとんどの ORM に欠けているさらに多くの機能をサポートしています。

  • 計算されたプロパティ — これらは、プロパティがフェッチされるたびに動的に実行される EdgeQL に対応する「仮想」プロパティです。
  • 計算されたデフォルト
  • 複雑な制約ロジック
  • スキーマ ミックスイン (継承)
  • リンク プロパティ
  • 全範囲の数値型 ( int{16,|32|64}float{32|64}bigint、およびdecimal)
  • durationおよび非タイムゾーン対応の日付と時刻のような一時的な型
  • プランナーと追跡システムを含む、データベース ネイティブの移行システム

今後の方向性

 

クエリ ビルダーは、2022 年 2 月の EdgeDB 1.0 リリース以降に利用可能であり、安定しており、運用に対応しています。e.groupクエリ ビルダーは最近アップグレードされ、ステートメントやグローバル スキーマ変数など、すべての EdgeDB 2.0 機能をサポートするようになりました。この投稿では、クエリ ビルダーの全機能のサブセットのみを取り上げます。より包括的な外観については、ドキュメントを参照してください。

2022 年 7 月 28 日のライブストリーム配信開始イベントで EdgeDB 2.0 をリリースします。最大の新機能と EdgeDB の新しい管理 UI の最初の公開デモについてのライトニング トークに参加してください。

ソース: https://www.edgedb.com/blog/designing-the-ultimate-typescript-query-builder

#typescript #EdgeDB

Cayla  Erdman

Cayla Erdman

1601549700

What’s New In Typescript 4.0?

Today I am going to talk about new features in Typescript 4.0.

TypeScript 4.0 comes with lots of new features to make JavaScript development easier.

Labeled Tuple Elements

You can label tuple elements.

You can write:

type Range = [start: number, end: number];

to restrict args to have a string and a number.

you can also write:

type Foo = [first: number, second?: string, ...rest: any[]];

to have rest entries in your tuple.

If your tuple has type Foo, then the tuple starts with a number and a string.

Then the rest of the entries can be anything.

Labels don’t require you to name your variables differently when destructuring.

For example, if you have:

function foo(x: [first: string, second: number]) {
  const [a, b] = x;
}

then you can name the destructured variables anything you want.

#software-development #typescript-with-react #typescript #typescript-4 #react native

Christa  Stehr

Christa Stehr

1599308024

Microsoft Releases TypeScript 4.0 With Speed Boosting Features

icrosoft recently announced the availability of TypeScript version 4.0. The developers at the tech giant claimed that this version of the language represents the next generation of TypeScript with more expressivity, productivity as well as scalability.

Developed by the tech giant, TypeScript is an open-source programming language that is built on top of JavaScript by adding syntax for static type definitions. The types in this language provide a way to describe the shape of an object, providing better documentation as well as allowing TypeScript to validate that the code is working correctly.

According to the latest Stack Overflow Developers survey 2020, it secured the second position as the most loved language and  9th position among 25 programming languages as the most commonly used programming language by the developers. In one of our articles, we discussed how TypeScript weighs over other programming languages.

It is one of the fastest-growing programming languages among the developers. The motive behind this language is that while writing down the types of values and where they are used, developers can use TypeScript to type-check the code and let them know about mistakes before they run the code. TypeScript compiler can be used to strip away types from the code, leaving them with clean, readable JavaScript that runs anywhere.

In the present scenario, TypeScript is a core part of many developer’s JavaScript stack. The language adds optional types to JavaScript that support tools for large-scale JavaScript applications for any browser, for any host and on any operating systems.

The program manager of TypeScript, Daniel Rosenwasser, said in a blog post, “In our past two major versions, we looked back at some highlights that shined over the years. For TypeScript 4.0, we’re going to keep up that tradition.”

What’s New?

Based on the feedback by the developer’s community, TypeScript 4.0 includes many intuitive features that are focussed on boosting the performance of this language. Some of them are mentioned below-

Speed Improvements in build mode with –noEmitOnError

According to Rosenwasser, previously, compiling a program after a previous compile with errors under incremental would result in extremely slow performance when using the –noEmitOnError flag. The reason is, none of the information from the last compilation would be cached in a .tsbuildinfo file based on the –noEmitOnError flag.

But now TypeScript 4.0 changes this. The new update provides a great speed boost in these scenarios, and in turn, improves the build mode scenarios, which imply both –incremental and –noEmitOnError.

#developers corner #microsoft #microsoft releases typescript 4.0 #programming language #programming language with high salary #typescript #typescript 4.0

Yoshiko  Jones

Yoshiko Jones

1603953021

What is TypeScript? Why TypeScript? and Why Not TypeScript?

Maybe you’ve been using JavaScript for a while and you’ve been hearing the buzz around… TypeScript. In this 2 part series, we’ll take a look at Why TypeScript? and Why Not TypeScript?

What is TypeScript?

According to the TypeScript website “TypeScript extends JavaScript by adding Types… TypeScript code is transformed into JavaScript code via the TypeScript compiler or Babel. This JavaScript is clean, simple code which runs anywhere JavaScript runs…”. In short, many refer to TypeScript as a superset of JavaScript.

In my opinion, this is kind of true and kind of not. Technically, not all valid JavaScript code can also be TypeScript code. We’ll talk about that later on. But, at its core, TypeScript was designed to allow developers to turn JavaScript, a dynamic programming language (one that is interpreted at runtime) into a statically typed programming language (one that is compiled before running). Let’s dive in.

Reasons For TypeScript

Improved Code Quality (potentially)

TypeScript makes use of features similar to languages like C## or Java: it truly is object oriented. This allows for more robust code. It enables the developer to implement type checking and make use of interfaces, classes, inheritance, etc. This can up the game as far as clean code when looking at a JavaScript program and a TypeScript program.

_Why did you throw in the word _potentially? Well, most valid JavaScript code can become TypeScript code. This means you don’t have to use the object oriented or typed features of TypeScript. Remember, TypeScript is optionally typed. It is not required. If TypeScript is utilized merely like JavaScript then improved code quality may not actually be a thing.

#typescript #programming #javascript #web-development #developer