0Pricing
Scala for Backend Engineering & Functional Programming · درس

تشغيل الاستعلامات

اقرأ الصفوف في case classes

تشغيل الاستعلامات درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.

The sql Interpolator

Doobie's sql string interpolator is the core of querying. It parses your SQL and turns embedded Scala values into safe, bound parameters.

Interpolated values become JDBC ? placeholders, so there is no SQL injection and no manual PreparedStatement wiring.

import doobie.implicits._

val minAge = 18
val frag = sql"select name from users where age >= $minAge"

From Fragment to Query

An sql"..." expression is a Fragment. To run it as a read you call .query[A], choosing the row type A.

Doobie uses a Read[A] typeclass to map result columns onto A, supporting primitives, tuples, and case classes.

case class User(name: String, age: Int)

val q: Query0[User] =
  sql"select name, age from users".query[User]

unique, option, and to

A Query0[A] offers different accumulators. .unique expects exactly one row, .option expects zero or one, and .to[List] collects all rows.

Each returns a ConnectionIO that you later .transact.

val one: ConnectionIO[User] = q.unique
val maybe: ConnectionIO[Option[User]] = q.option
val all: ConnectionIO[List[User]] = q.to[List]

Mapping Rows to Case Classes

Doobie derives Read instances for case classes automatically when each field has a column mapping. Column order must match the select list.

This lets you select straight into rich domain types without boilerplate row parsing.

case class Account(id: Long, email: String, active: Boolean)

val accounts =
  sql"select id, email, active from accounts"
    .query[Account].to[Vector]

Parameterized Queries

Every interpolated Scala value is bound as a parameter using its Put instance. You can interpolate as many as you like, including in different positions.

Because they are bound, not concatenated, types are checked and injection is impossible.

def findByEmail(email: String): ConnectionIO[Option[Account]] =
  sql"select id, email, active from accounts where email = $email"
    .query[Account].option

Streaming Large Results

For big result sets, use .stream to get an fs2 Stream[ConnectionIO, A]. Rows are pulled lazily with a server-side cursor, keeping memory bounded.

Combine it with fs2 combinators to process millions of rows incrementally.

import fs2.Stream

val s: Stream[ConnectionIO, Account] =
  sql"select id, email, active from accounts"
    .query[Account].stream

Controlling Fetch Size

The default cursor fetch size may load everything at once on some drivers. .streamWithChunkSize(n) sets the JDBC fetch size so the cursor fetches n rows per round trip.

Tuning this balances round trips against memory.

val s =
  sql"select id, email, active from accounts"
    .query[Account]
    .streamWithChunkSize(512)

Optional Columns and Nullability

Nullable columns map to Option[A] in your row type. If a column can be NULL you must read it as an Option, or Doobie throws on a null value.

This makes nullability explicit and type-safe at the boundary.

case class Person(id: Long, nickname: Option[String])

val ps =
  sql"select id, nickname from people".query[Person].to[List]

Building SQL with Fragments

Fragment values compose with ++, letting you assemble queries from pieces while keeping parameters bound.

The fr interpolator builds a fragment with a trailing space, which is handy for stitching clauses together.

val base = fr"select id, email, active from accounts"
val where = fr"where active = $${true}"
val q = (base ++ where).query[Account]

Dynamic WHERE Clauses

Doobie's Fragments helpers build conditional clauses. Fragments.whereAndOpt combines optional filters, emitting only the ones that are present.

This is the idiomatic way to build safe dynamic search queries.

import doobie.util.fragments._

val emailOpt: Option[String] = Some("a@b.com")
val filter = whereAndOpt(emailOpt.map(e => fr"email = $e"))
val q = (fr"select id, email, active from accounts" ++ filter)

Checking Queries at Build Time

Doobie's check analysis runs a query against the database schema to verify column types and counts match your Scala types.

Used in tests, it catches schema drift before it reaches production.

import doobie.scalatest._

// inside a spec mixing in IOChecker
check(sql"select id, email, active from accounts".query[Account])

Quick Check

Choose the right accumulator.

Recap

The sql interpolator builds parameterized Fragments; .query[A] turns them into a Query0[A] mapped via Read[A].

Pick .unique, .option, .to[List], or .stream to accumulate rows. Use Fragments for dynamic clauses and check to validate against the schema.

الأسئلة الشائعة

هل درس «تشغيل الاستعلامات» مجاني؟

نعم — نص درس «تشغيل الاستعلامات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «تشغيل الاستعلامات»؟

اقرأ الصفوف في case classes تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «تشغيل الاستعلامات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الاتصال باستخدام Transactor
  2. تشغيل الاستعلامات
  3. عمليات الإدراج والتحديث
  4. تركيب المعاملات
← العودة إلى Scala for Backend Engineering & Functional Programming