Prechádzať zdrojové kódy

Adds Onyx Framework for Crystal (#4460)

* added onyx

* fixes for onyx

* fixes readme

* removes lib folder

* fixes bad docker file

* adds Vlad as an Author

* Update frameworks/Crystal/onyx/README.md

Co-Authored-By: CaDs <[email protected]>

* Apply suggestions from code review

Co-Authored-By: CaDs <[email protected]>

* refactoring and performance optimization

* cleanup

* sets CRYSTAL_ENV to production, refactorin

* adds Vlad changes, and some fixes
Carlos Donderis 6 rokov pred
rodič
commit
1599b9061b

+ 11 - 0
frameworks/Crystal/onyx/README.md

@@ -0,0 +1,11 @@
+# Crystal-Onyx
+
+This is the [Onyx](https://github.com/onyxframework/) test of the Framework Benchmarks. Crystal is a new language that closely resembles Ruby with a goal of removing typed variables and parameters (instead inferencing), whilst maintaining top speed through bindings into C.
+
+The framework consists of multiple components:
+
+[Onyx::HTTP](https://github.com/onyxframework/http) is a collection of HTTP handlers, which essentially are building blocks for your web application
+[Onyx::REST](https://github.com/onyxframework/rest) is a REST layer on top of Onyx::HTTP which implements splitting business and rendering logic into Actions and Views, inspired by Hanami
+[Onyx::SQL](https://github.com/onyxframework/rest) is a database-agnostic SQL ORM
+
+Onyx Framework is designed to be both powerful and adoptable by Crystal newcomers. It utilizes complex concepts like annotations and generics, but hides it under beautiful DSL. Such an approach makes it possible to write less code, thus reducing the possibility of bugs, but still make it easy to extend the framework’s functionality.

+ 29 - 0
frameworks/Crystal/onyx/benchmark_config.json

@@ -0,0 +1,29 @@
+{
+  "framework": "onyx",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Onyx",
+        "language": "Crystal",
+        "flavor": "None",
+        "orm": "Micro",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Onyx (PostgreSQL)",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 16 - 0
frameworks/Crystal/onyx/onyx.dockerfile

@@ -0,0 +1,16 @@
+FROM crystallang/crystal:0.27.1
+
+WORKDIR /onyx
+COPY run.sh run.sh
+COPY src src
+COPY shard.yml shard.yml
+
+ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_pool_size=56&max_idle_pool_size=56
+ENV TEST_HOST tfb-server
+ENV CRYSTAL_ENV production
+
+RUN shards install
+RUN crystal build --release --no-debug src/server_postgres.cr
+
+EXPOSE 8080
+CMD bash run.sh

+ 5 - 0
frameworks/Crystal/onyx/run.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+./server_postgres -p 8080 &
+
+wait

+ 46 - 0
frameworks/Crystal/onyx/shard.lock

@@ -0,0 +1,46 @@
+version: 1.0
+shards:
+  callbacks:
+    github: vladfaust/callbacks.cr
+    version: 0.2.0
+
+  db:
+    github: crystal-lang/crystal-db
+    version: 0.5.1
+
+  dotenv:
+    github: gdotdesign/cr-dotenv
+    version: 0.1.0
+
+  http-params-serializable:
+    github: vladfaust/http-params-serializable
+    version: 0.3.0
+
+  onyx:
+    github: onyxframework/onyx
+    version: 0.1.2
+
+  onyx-http:
+    github: onyxframework/http
+    version: 0.1.1
+
+  onyx-rest:
+    github: onyxframework/rest
+    version: 0.6.3
+
+  onyx-sql:
+    github: onyxframework/sql
+    version: 0.6.2
+
+  pg:
+    github: will/crystal-pg
+    version: 0.15.0
+
+  radix:
+    github: luislavena/radix
+    version: 0.3.9
+
+  time_format:
+    github: vladfaust/time_format.cr
+    version: 0.1.1
+

+ 24 - 0
frameworks/Crystal/onyx/shard.yml

@@ -0,0 +1,24 @@
+name: onyx
+version: 0.1.0
+
+authors:
+  - Vlad Faust
+  - Carlos Donderis
+
+crystal: 0.27.2
+
+license: MIT
+
+dependencies:
+  onyx:
+    github: onyxframework/onyx
+    version: ~> 0.1.2
+  onyx-rest:
+    github: onyxframework/rest
+    version: ~> 0.6.2
+  onyx-sql:
+    github: onyxframework/sql
+    version: ~> 0.6.2
+  pg:
+    github: will/crystal-pg
+    version: ~> 0.15.0

+ 141 - 0
frameworks/Crystal/onyx/src/server_postgres.cr

@@ -0,0 +1,141 @@
+require "pg"
+require "onyx/sql"
+require "onyx/rest"
+
+class World
+  include Onyx::SQL::Model
+
+  schema world do
+    pkey id : Int32
+    type random_number : Int32, key: "randomnumber"
+  end
+end
+
+def random_id
+  Random.rand(10_000).succ
+end
+
+struct Views::World
+  include Onyx::REST::View
+
+  def initialize(@world : ::World)
+  end
+
+  json do
+    object do
+      field "id", @world.id
+      field "randomnumber", @world.random_number
+    end
+  end
+end
+
+struct Views::Worlds
+  include Onyx::REST::View
+
+  def initialize(@worlds : Enumerable(::World))
+  end
+
+  json do
+    array do
+      @worlds.each do |world|
+        Views::World.new(world).to_json(itself)
+      end
+    end
+  end
+end
+
+struct Actions::RandomWorld
+  include Onyx::REST::Action
+
+  QUERY = World.where(id: 0).build(true)[0]
+
+  def call
+    world = Onyx.query(World, QUERY, random_id).first
+    return Views::World.new(world)
+  end
+end
+
+struct Actions::ManyWorlds
+  include Onyx::REST::Action
+
+  QUERY = World.where("id = ANY(?)", 0).build(true)[0]
+
+  params do
+    query do
+      type queries : String | Int32 = 1
+    end
+  end
+
+  def call
+    queries = params.query.queries.is_a?(String) ? 1 : params.query.queries.as(Int32)
+    ids = queries.clamp(1..500).times.map do
+      random_id
+    end.join(',').try do |s|
+      "{#{s}}"
+    end
+
+    worlds = Onyx.query(World, QUERY, ids)
+    return Views::Worlds.new(worlds)
+  end
+end
+
+struct Actions::UpdateWorlds
+  include Onyx::REST::Action
+
+  QUERY = World.update.set(random_number: 0).where(id: 0).build[0]
+
+  params do
+    query do
+      type queries : String | Int32 = 1
+    end
+  end
+
+  def call
+    queries = params.query.queries.is_a?(String) ? 1 : params.query.queries.as(Int32)
+
+    worlds = Array(World).new
+
+    queries.clamp(1..500).times.each do
+      id, number = {random_id, random_id}
+
+      world = World.new(id: id, random_number: number)
+      worlds << world
+
+      Onyx.exec(QUERY, world.random_number, world.id)
+    end
+
+    return Views::Worlds.new(worlds)
+  end
+end
+
+class CustomHandler
+  include HTTP::Handler
+
+  def call(context)
+    context.response.headers["Server"] = "Onyx"
+    context.response.headers["Date"] = HTTP.format_time(Time.now)
+    call_next(context)
+  end
+end
+
+Onyx.draw do
+  get "/json" do |env|
+    env.response.content_type = "application/json"
+    {message: "Hello, World!"}.to_json(env.response)
+  end
+
+  get "/db", Actions::RandomWorld
+  get "/queries", Actions::ManyWorlds
+  get "/updates", Actions::UpdateWorlds
+
+  get "/plaintext" do |env|
+    env.response.content_type = "text/plain"
+    env.response << "Hello, World!"
+  end
+end
+
+Onyx.render(:json)
+
+Onyx.listen(ENV["TEST_HOST"], 8080) do
+  handlers.insert(2, CustomHandler.new)
+end