Closed10

scalikejdbc genでtableからcase classを作成する

ara_ta3ara_ta3

設定ファイル

build.sbt

organization := "com.example"

name := "scalikejdbcgen-getting-startd"

version := "0.1.0-SNAPSHOT"

scalaVersion := "2.13.16"

enablePlugins(ScalikejdbcPlugin)

project/build.properties

sbt.version=1.10.5

project/scalikejdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ecsite-samples
jdbc.username=user
jdbc.password=password

project/plugins.sbt

libraryDependencies ++= Seq(
  "mysql" % "mysql-connector-java" % "8.0.33",
)

addSbtPlugin("org.scalikejdbc" %% "scalikejdbc-mapper-generator" % "4.3.2")
ara_ta3ara_ta3

Makefile

CONTAINER_NAME = scalikejdbcgen-gettingstarted
MYSQL_ROOT_PASSWORD = rootpassword
MYSQL_DATABASE = ecsite-samples
MYSQL_USER = user
MYSQL_PASSWORD = password
MYSQL_IMAGE = mysql:8.0

start:
	docker rm -f $(CONTAINER_NAME)
	docker run --name $(CONTAINER_NAME) \
		-e MYSQL_ROOT_PASSWORD=$(MYSQL_ROOT_PASSWORD) \
		-e MYSQL_DATABASE=$(MYSQL_DATABASE) \
		-e MYSQL_USER=$(MYSQL_USER) \
		-e MYSQL_PASSWORD=$(MYSQL_PASSWORD) \
		-v $(PWD)/migrations:/docker-entrypoint-initdb.d \
		-p 3306:3306 $(MYSQL_IMAGE)

wait-for-mysql:
	until docker exec $(CONTAINER_NAME) mysqladmin ping -u$(MYSQL_USER) -p$(MYSQL_PASSWORD) --silent; do \
		echo "Waiting for MySQL to be ready..."; \
		sleep 10; \
	done

stop:
	docker stop $(CONTAINER_NAME)

clean: stop
	docker rm $(CONTAINER_NAME)

mysqlcli:
	docker exec -it $(CONTAINER_NAME) mysql -u$(MYSQL_USER) -p$(MYSQL_PASSWORD) $(MYSQL_DATABASE)

ara_ta3ara_ta3

テーブル定義

CREATE TABLE items (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    stock INT DEFAULT 0
);

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL
);

CREATE TABLE current_cart (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL UNIQUE,
    item_id INT NOT NULL,
    quantity INT NOT NULL DEFAULT 1,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (item_id) REFERENCES items(id)
);

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    total_amount DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE ordered_items (
    id INT AUTO_INCREMENT PRIMARY KEY,
    order_id INT NOT NULL,
    item_id INT NOT NULL,
    quantity INT NOT NULL,
    price_at_purchase DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(id),
    FOREIGN KEY (item_id) REFERENCES items(id)
);
ara_ta3ara_ta3

scalikejdbcGenAllは成功する

[info] started sbt server
sbt:scalikejdbcgen-getting-startd> scalikejdbcGenAll
"models.CurrentCart" already exists.
"models.CurrentCartSpec" already exists.
"models.Items" already exists.
"models.ItemsSpec" already exists.
"models.OrderedItems" already exists.
"models.OrderedItemsSpec" already exists.
"models.Orders" already exists.
"models.OrdersSpec" already exists.
"models.Users" already exists.
"models.UsersSpec" already exists.
ara_ta3ara_ta3

前うまく行かなかったと思ったけど成功するわ

sbt:scalikejdbcgen-getting-startd> scalikejdbcGenEcho items
package models

import scalikejdbc._

case class Items(
  id: Int,
  name: String,
  description: Option[String] = None,
  price: BigDecimal,
  stock: Option[Int] = None) {

  def save()(implicit session: DBSession = Items.autoSession): Items = Items.save(this)(session)

  def destroy()(implicit session: DBSession = Items.autoSession): Int = Items.destroy(this)(session)

}


object Items extends SQLSyntaxSupport[Items] {

  override val tableName = "items"

  override val columns = Seq("id", "name", "description", "price", "stock")

  def apply(i: SyntaxProvider[Items])(rs: WrappedResultSet): Items = apply(i.resultName)(rs)
  def apply(i: ResultName[Items])(rs: WrappedResultSet): Items = new Items(
    id = rs.get(i.id),
    name = rs.get(i.name),
    description = rs.get(i.description),
    price = rs.get(i.price),
    stock = rs.get(i.stock)
  )

  val i = Items.syntax("i")

  override val autoSession = AutoSession

  def find(id: Int)(implicit session: DBSession = autoSession): Option[Items] = {
    withSQL {
      select.from(Items as i).where.eq(i.id, id)
    }.map(Items(i.resultName)).single.apply()
  }

  def findAll()(implicit session: DBSession = autoSession): List[Items] = {
    withSQL(select.from(Items as i)).map(Items(i.resultName)).list.apply()
  }

  def countAll()(implicit session: DBSession = autoSession): Long = {
    withSQL(select(sqls.count).from(Items as i)).map(rs => rs.long(1)).single.apply().get
  }

  def findBy(where: SQLSyntax)(implicit session: DBSession = autoSession): Option[Items] = {
    withSQL {
      select.from(Items as i).where.append(where)
    }.map(Items(i.resultName)).single.apply()
  }

  def findAllBy(where: SQLSyntax)(implicit session: DBSession = autoSession): List[Items] = {
    withSQL {
      select.from(Items as i).where.append(where)
    }.map(Items(i.resultName)).list.apply()
  }

  def countBy(where: SQLSyntax)(implicit session: DBSession = autoSession): Long = {
    withSQL {
      select(sqls.count).from(Items as i).where.append(where)
    }.map(_.long(1)).single.apply().get
  }

  def create(
    name: String,
    description: Option[String] = None,
    price: BigDecimal,
    stock: Option[Int] = None)(implicit session: DBSession = autoSession): Items = {
    val generatedKey = withSQL {
      insert.into(Items).namedValues(
        column.name -> name,
        column.description -> description,
        column.price -> price,
        column.stock -> stock
      )
    }.updateAndReturnGeneratedKey.apply()

    Items(
      id = generatedKey.toInt,
      name = name,
      description = description,
      price = price,
      stock = stock)
  }

  def batchInsert(entities: collection.Seq[Items])(implicit session: DBSession = autoSession): List[Int] = {
    val params: collection.Seq[Seq[(String, Any)]] = entities.map(entity =>
      Seq(
        "name" -> entity.name,
        "description" -> entity.description,
        "price" -> entity.price,
        "stock" -> entity.stock))
    SQL("""insert into items(
      name,
      description,
      price,
      stock
    ) values (
      {name},
      {description},
      {price},
      {stock}
    )""").batchByName(params.toSeq: _*).apply[List]()
  }

  def save(entity: Items)(implicit session: DBSession = autoSession): Items = {
    withSQL {
      update(Items).set(
        column.id -> entity.id,
        column.name -> entity.name,
        column.description -> entity.description,
        column.price -> entity.price,
        column.stock -> entity.stock
      ).where.eq(column.id, entity.id)
    }.update.apply()
    entity
  }

  def destroy(entity: Items)(implicit session: DBSession = autoSession): Int = {
    withSQL { delete.from(Items).where.eq(column.id, entity.id) }.update.apply()
  }

}

package models

import scalikejdbc.specs2.mutable.AutoRollback
import org.specs2.mutable._
import scalikejdbc._


class ItemsSpec extends Specification {

  "Items" should {

    val i = Items.syntax("i")

    "find by primary keys" in new AutoRollback {
      val maybeFound = Items.find(123)
      maybeFound.isDefined should beTrue
    }
    "find by where clauses" in new AutoRollback {
      val maybeFound = Items.findBy(sqls.eq(i.id, 123))
      maybeFound.isDefined should beTrue
    }
    "find all records" in new AutoRollback {
      val allResults = Items.findAll()
      allResults.size should be_>(0)
    }
    "count all records" in new AutoRollback {
      val count = Items.countAll()
      count should be_>(0L)
    }
    "find all by where clauses" in new AutoRollback {
      val results = Items.findAllBy(sqls.eq(i.id, 123))
      results.size should be_>(0)
    }
    "count by where clauses" in new AutoRollback {
      val count = Items.countBy(sqls.eq(i.id, 123))
      count should be_>(0L)
    }
    "create new record" in new AutoRollback {
      val created = Items.create(name = "MyString", price = new java.math.BigDecimal("1"))
      created should not(beNull)
    }
    "save a record" in new AutoRollback {
      val entity = Items.findAll().head
      // TODO modify something
      val modified = entity
      val updated = Items.save(modified)
      updated should not equalTo(entity)
    }
    "destroy a record" in new AutoRollback {
      val entity = Items.findAll().head
      val deleted = Items.destroy(entity) == 1
      deleted should beTrue
      val shouldBeNone = Items.find(123)
      shouldBeNone.isDefined should beFalse
    }
    "perform batch insert" in new AutoRollback {
      val entities = Items.findAll()
      entities.foreach(e => Items.destroy(e))
      val batchInserted = Items.batchInsert(entities)
      batchInserted.size should be_>(0)
    }
  }

}

[success] Total time: 0 s, completed 2025/02/01 13:55:59
sbt:scalikejdbcgen-getting-startd> scalikejdbcGen items
"models.Items" already exists.
"models.ItemsSpec" already exists.
[success] Total time: 0 s, completed 2025/02/01 13:56:03
sbt:scalikejdbcgen-getting-startd> scalikejdbcGenForce items
"models.Items" created.
"models.ItemsSpec" created.
[success] Total time: 0 s, completed 2025/02/01 13:56:06

参考

ara_ta3ara_ta3

やりたいこと

  • testを出力しない
  • テンプレートの切り替え
    • srcのコードを時前のテンプレートにしたい
  • database名の切り替え
ara_ta3ara_ta3

テンプレートはqueryDslかinterpolationのみかー

ara_ta3ara_ta3

んーーーscalikejdbcGenEchoで一部だけ表示してコピペするのが無難かもしれないなぁ

ara_ta3ara_ta3

prismaのほうが良いのではということを思い始めた

このスクラップは2025/02/01にクローズされました