server-postgres.cr 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. require "kemal"
  2. require "pg"
  3. require "commander"
  4. # Compose Objects (like Hash) to have a to_json method
  5. require "json/to_json"
  6. APPDB = DB.open(ENV["DATABASE_URL"])
  7. class CONTENT
  8. UTF8 = "; charset=UTF-8"
  9. JSON = "application/json"
  10. PLAIN = "text/plain"
  11. HTML = "text/html" + UTF8
  12. end
  13. ID_MAXIMUM = 10_000
  14. private def random_world
  15. id = rand(1..ID_MAXIMUM)
  16. id, random_number = APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: {Int32, Int32})
  17. {id: id, randomNumber: random_number}
  18. end
  19. private def set_world(world)
  20. APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id])
  21. world
  22. end
  23. private def fortunes
  24. data = Array(NamedTuple(id: Int32, message: String)).new
  25. APPDB.query_each("SELECT id, message FROM Fortune") do |rs|
  26. data.push({id: rs.read(Int32), message: rs.read(String)})
  27. end
  28. data
  29. end
  30. private def sanitized_query_count(request)
  31. queries = request.params.query["queries"]? || "1"
  32. queries = queries.to_i? || 1
  33. queries.clamp(1..500)
  34. end
  35. private def sanitized_concurrency(request)
  36. concurrency = request.params.query["concurrency"]? || "1"
  37. concurrency.to_i? || 1
  38. end
  39. before_all do |env|
  40. env.response.headers["Server"] = "Kemal"
  41. env.response.headers["Date"] = HTTP.format_time(Time.utc)
  42. end
  43. #
  44. # Basic Tests
  45. #
  46. # Test 1: JSON Serialization
  47. get "/json" do |env|
  48. env.response.content_type = CONTENT::JSON
  49. {message: "Hello, World!"}.to_json
  50. end
  51. # Test 6: Plaintext
  52. get "/plaintext" do |env|
  53. env.response.content_type = CONTENT::PLAIN
  54. "Hello, World!"
  55. end
  56. #
  57. # Postgres DatabaseTests
  58. #
  59. # Postgres Test 2: Single database query
  60. get "/db" do |env|
  61. env.response.content_type = CONTENT::JSON
  62. random_world.to_json
  63. end
  64. # Postgres Test 3: Multiple database query
  65. get "/queries" do |env|
  66. queries = sanitized_query_count(env)
  67. concurrency = sanitized_concurrency(env)
  68. results =
  69. if concurrency < 2
  70. (1..queries).map do
  71. random_world
  72. end
  73. else
  74. cmd = Commander(NamedTuple(id: Int32, randomNumber: Int32)).new(queries, concurrency)
  75. queries.times do
  76. cmd.dispatch do
  77. random_world
  78. end
  79. end
  80. cmd.collect
  81. end
  82. env.response.content_type = CONTENT::JSON
  83. results.to_json
  84. end
  85. # Postgres Test 4: Fortunes
  86. get "/fortunes" do |env|
  87. env.response.content_type = CONTENT::HTML
  88. data = fortunes
  89. additional_fortune = {
  90. id: 0,
  91. message: "Additional fortune added at request time.",
  92. }
  93. data.push(additional_fortune)
  94. data.sort_by! { |fortune| fortune[:message] }
  95. render "views/fortunes.ecr"
  96. end
  97. # Postgres Test 5: Database Updates
  98. get "/updates" do |env|
  99. updated = (1..sanitized_query_count(env)).map do
  100. set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)})
  101. end
  102. env.response.content_type = CONTENT::JSON
  103. updated.to_json
  104. end
  105. Kemal.config do |cfg|
  106. cfg.serve_static = false
  107. cfg.logging = false
  108. cfg.powered_by_header = false
  109. end
  110. Kemal.run { |cfg| cfg.server.not_nil!.bind_tcp(cfg.host_binding, cfg.port, reuse_port: true) }