aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/guff/api-methods.cr66
-rw-r--r--src/guff/database.cr8
-rw-r--r--src/guff/model.cr10
-rw-r--r--src/guff/post-model.cr133
-rw-r--r--src/guff/site-model.cr8
-rw-r--r--src/guff/tag-model.cr42
-rw-r--r--src/guff/template-database.cr14
-rw-r--r--src/guff/template.cr27
8 files changed, 271 insertions, 37 deletions
diff --git a/src/guff/api-methods.cr b/src/guff/api-methods.cr
index d0bf415..c29b324 100644
--- a/src/guff/api-methods.cr
+++ b/src/guff/api-methods.cr
@@ -248,7 +248,6 @@ module Guff
},
},
-
"test": {
"version": {
text: "Get version",
@@ -335,37 +334,54 @@ module Guff
args : Hash(String, String)
)
@models.post.get_posts(
- site_id: @models.site.to_site(context.request.headers["host"]?),
+ site_id: get_site(context),
q: args["q"]? || "",
- tags: (args.has_key?("tags") && args["tags"].size > 0) ? [args["tags"].split(',')] : NO_TAGS,
+ tags: get_posts_tags(args["tags"]),
page: args.has_key?("page") ? args["page"].to_i : 1,
).to_json
end
- private def get_site_id(host : String?)
- # TODO
- 0
- end
-
private def do_post_add_post(
context : HTTP::Server::Context,
args : Hash(String, String)
)
- @models.post.add_post(args).to_json
+ post_id = @models.post.add_post(
+ site_id: get_site(context),
+ slug: args["slug"],
+ name: args["name"],
+ body: args["name"],
+ tags: get_tags(args["tags"]?),
+ )
+
+ # return json
+ { post_id: post_id }.to_json
end
private def do_post_remove_posts(
context : HTTP::Server::Context,
args : Hash(String, String)
)
- @models.post.remove_posts(args).to_json
+ @models.post.remove_posts(
+ site_id: get_site(context),
+ post_ids: args["post_ids"].split(',').map { |post_id|
+ post_id.to_s.to_i
+ },
+ )
+
+ { ok: true }.to_json
end
private def do_post_set_tags(
context : HTTP::Server::Context,
args : Hash(String, String)
)
- @models.post.set_tags(args).to_json
+ @models.post.set_tags(
+ site_id: get_site(context),
+ post_id: (args["post_id"] as String).to_i,
+ tags: get_tags(args["tags"]?),
+ )
+
+ { ok: true}.to_json
end
###############
@@ -486,5 +502,33 @@ module Guff
)
raise "some random error"
end
+
+ ###################
+ # utility methods #
+ ###################
+
+ private def get_site(context : HTTP::Server::Context) : Int?
+ @models.site.to_site(context.request.headers["host"]?)
+ end
+
+ private def get_tags(
+ s : String?
+ ) : Array(String)
+ if s && s.size > 0
+ Array(String).from_json(s)
+ else
+ [] of String
+ end
+ end
+
+ private def get_posts_tags(
+ s : String?
+ ) : Array(Array(String))
+ if s && s.size > 0
+ Array(Array(String)).from_json(s)
+ else
+ [] of Array(String)
+ end
+ end
end
end
diff --git a/src/guff/database.cr b/src/guff/database.cr
index bab300f..0e41b75 100644
--- a/src/guff/database.cr
+++ b/src/guff/database.cr
@@ -71,7 +71,7 @@ module Guff
def all(
sql : String,
args = nil : Array(String) | Hash(String, String) | Nil,
- &block : Proc(Hash(String, ::SQLite3::Value), Nil) \
+ &block : Hash(String, ::SQLite3::Value) -> \
)
# build statement
run(sql, args) do |rs|
@@ -117,7 +117,7 @@ module Guff
def query(
sql : String,
args = nil : Array(String) | Hash(String, String) | Nil,
- &block : Proc(::SQLite3::ResultSet, Nil) \
+ &block : ::SQLite3::ResultSet -> \
)
run(sql, args, &block)
end
@@ -131,7 +131,7 @@ module Guff
private def run(
sql : String,
args : Hash(String, String),
- &block : Proc(::SQLite3::ResultSet, Nil) \
+ &block : ::SQLite3::ResultSet -> \
)
run(sql, [args], &block)
end
@@ -139,7 +139,7 @@ module Guff
private def run(
sql : String,
args = nil : Array(String | Hash(String, String))?,
- &block : Proc(::SQLite3::ResultSet, Nil) \
+ &block : ::SQLite3::ResultSet -> \
)
# build statement
puts "sql = %s" % [sql]
diff --git a/src/guff/model.cr b/src/guff/model.cr
index 515af4e..bd35629 100644
--- a/src/guff/model.cr
+++ b/src/guff/model.cr
@@ -26,7 +26,7 @@ module Guff
key : Symbol,
args : Array(String) | Hash(String, String) | Nil,
tmpl_args : Hash(String, String) | Nil,
- &block : Proc(Hash(String, ::SQLite3::Value), Nil) \
+ &block : Hash(String, ::SQLite3::Value) -> \
)
@db.all(key, args, tmpl_args, &block)
end
@@ -39,11 +39,19 @@ module Guff
@db.query(key, args, tmpl_args)
end
+ def transaction(&block)
+ @db.transaction(&block)
+ end
+
def template(
key : Symbol,
args : Hash(String, String) | Nil
)
@db.template(key, args)
end
+
+ def last_insert_row_id
+ @db.last_insert_row_id
+ end
end
end
diff --git a/src/guff/post-model.cr b/src/guff/post-model.cr
index 4788ba3..0a78458 100644
--- a/src/guff/post-model.cr
+++ b/src/guff/post-model.cr
@@ -42,6 +42,34 @@ module Guff
ORDER BY %{sort} %{dir}
OFFSET :offset LIMIT :limit
",
+
+ remove_posts: "
+ UPDATE posts
+ SET is_active = 0
+ WHERE site_id = :site_id
+ AND post_id IN (%{post_ids})
+ ",
+
+ set_tags_delete: "
+ DELETE FROM post_tags WHERE post_id = (
+ SELECT post_id
+ FROM posts
+ WHERE site_id = :site_id
+ AND post_id = :post_id
+ )
+ ",
+
+ set_tags_insert: "
+ INSERT INTO post_tags(post_id, tag_id)
+ SELECT a.post_id,
+ b.tag_id
+
+ FROM posts a
+ CROSS JOIN tags b
+
+ WHERE a.site_id = :site_id
+ AND b.name IN (%{tags})
+ ",
})
def initialize(models : Models)
@@ -196,19 +224,106 @@ module Guff
}) : NO_POSTS
end
- def add_post(req)
- # TODO: return post id
- {ok: true}
+ ####################
+ # add_post methods #
+ ####################
+
+ def add_post(
+ site_id = nil : Int?,
+ slug = "" : String,
+ name = "" : String,
+ body = "" : String,
+ tags = [] of String : Array(String),
+ ) : Int64
+ post_id = -1_i64
+
+ # check slug, name, and body
+ { "slug": slug, "name": name, "body": body }.each do |name, text|
+ raise "invalid %s" % [name] unless text.size > 0
+ end
+
+ transaction do
+ query(:add_post, {
+ "site_id": (site_id || @models.site.get_default).to_s,
+ "slug": slug,
+ "name": name,
+ "raw_body": body,
+ "body": body,
+ }, nil)
+
+ # get post id
+ post_id = last_insert_row_id
+
+ # set post tags
+ set_tags(
+ site_id: site_id,
+ post_id: post_id,
+ tags: tags,
+ use_transaction: false,
+ )
+ end
+
+ # return post id
+ post_id
end
- def remove_posts(req)
- # TODO
- {ok: true}
+ def remove_posts(
+ site_id = nil : Int?,
+ post_ids = [] of Int : Array(Int)
+ )
+ query(:remove_posts, {
+ "site_id": (site_id || @models.site.get_default).to_s,
+ }, {
+ "post_ids": post_ids.map { |post_id|
+ "'" + @db.quote(post_id.to_s) + "'"
+ }.join(',')
+ })
+
+ # no return value
+ nil
end
- def set_tags(req)
- # TODO
- {ok: true}
+ def set_tags(
+ site_id = nil : Int?,
+ post_id = nil : Int?,
+ tags = [] of String : Array(String),
+ use_transaction = true : Bool
+ )
+ if use_transaction
+ transaction do
+ raw_set_tags(site_id, post_id, tags)
+ end
+ else
+ raw_set_tags(site_id, post_id, tags)
+ end
+
+ nil
+ end
+
+ private def raw_set_tags(
+ site_id = nil : Int?,
+ post_id = nil : Int?,
+ tags = [] of String : Array(String),
+ )
+ # build sql args
+ args = {
+ "site_id": (site_id || @models.site.get_default).to_s,
+ "post_id": post_id.to_s,
+ }
+
+ # delete existing post tags
+ query(:set_tags_delete, args, nil)
+
+ if tags.size > 0
+ @models.tag.add_tags(tags)
+
+ # add new post tags
+ query(:set_tags_insert, args, {
+ "tags": tags.map { |tag|
+ "'" + @db.quote(tag) + "'"
+ }.join(','),
+ })
+ end
end
end
end
diff --git a/src/guff/site-model.cr b/src/guff/site-model.cr
index ecde831..9c8899a 100644
--- a/src/guff/site-model.cr
+++ b/src/guff/site-model.cr
@@ -13,11 +13,13 @@ module Guff
super(models, SQL)
end
- def get_default
- one(:get_default, nil, {} of String => String)
+ def get_default : Int
+ r = one(:get_default, nil, {} of String => String)
+ raise "no default site" unless r
+ r.to_i
end
- def to_site(host : String?)
+ def to_site(host : String?) : Int
# TODO
get_default
end
diff --git a/src/guff/tag-model.cr b/src/guff/tag-model.cr
index 5d758d1..2aa9d89 100644
--- a/src/guff/tag-model.cr
+++ b/src/guff/tag-model.cr
@@ -1,10 +1,52 @@
module Guff
class TagModel < Model
SQL = TemplateCache.new({
+ add_tags: "
+ INSERT INTO tags(name) VALUES(%{tags})
+ ",
+
+ get_tags: "
+ SELECT tag_id,
+ name
+
+ FROM tags
+
+ WHERE name IN (%{tags})
+ ",
} of Symbol => String)
def initialize(models : Models)
super(models, SQL)
end
+
+ def add_tags(tags : Array(String))
+ # get ids of existing tags
+ ids = get_ids(tags)
+
+ query(:add_tags, nil, {
+ "tags": tags.reject { |tag|
+ ids[tag]?
+ }.map { |tag|
+ "'" + @db.quote(tag) + "'"
+ }.join(','),
+ })
+ end
+
+ private def get_ids(
+ tags = [] of String : Array(String)
+ ) : Hash(String, Int32)
+ r = {} of String => Int32
+
+ all(:get_tags, nil, {
+ "tags": tags.map { |tag|
+ "'" + @db.quote(tag) + "'"
+ }.join(','),
+ }) do |row|
+ r[row["name"] as String] = (row["tag_id"] as String).to_i
+ end
+
+ # return result
+ r
+ end
end
end
diff --git a/src/guff/template-database.cr b/src/guff/template-database.cr
index 7ff9690..bfe8321 100644
--- a/src/guff/template-database.cr
+++ b/src/guff/template-database.cr
@@ -23,7 +23,7 @@ module Guff
key : Symbol,
args : Array(String) | Hash(String, String) | Nil,
tmpl_args : Hash(String, String)?,
- &block : Proc(Hash(String, ::SQLite3::Value), Nil) \
+ &block : Hash(String, ::SQLite3::Value) -> \
)
@db.all(template(key, tmpl_args), args, &block)
end
@@ -42,5 +42,17 @@ module Guff
)
@templates[key].run(args)
end
+
+ def last_insert_row_id
+ @db.last_insert_row_id
+ end
+
+ def quote(s) : String
+ @db.quote(s)
+ end
+
+ def transaction(&block)
+ @db.transaction(&block)
+ end
end
end
diff --git a/src/guff/template.cr b/src/guff/template.cr
index 4b54fb6..f5a1693 100644
--- a/src/guff/template.cr
+++ b/src/guff/template.cr
@@ -7,16 +7,19 @@ module Guff
@has_keys = @tokens.select { |t| t.type == :key }.size > 0
end
- def run(args = nil : Hash(String, String)?) : String
+ def run(args : Nil) : String
+ raise_missing if @has_keys
+
+ # return literal string
+ @string
+ end
+
+ def run(
+ args = {} of String => String : Hash(String, String)
+ ) : String
if @has_keys
# check template args
- if !args || args.size == 0
- raise "missing template args: %s" % [@tokens.select { |t|
- t.type == :key
- }.map { |t|
- t.value
- }.sort.join(", ")]
- end
+ raise_missing if args.size == 0
# build result
String.build do |r|
@@ -30,6 +33,14 @@ module Guff
end
end
+ private def raise_missing
+ raise "missing template args: %s" % [@tokens.select { |t|
+ t.type == :key
+ }.map { |t|
+ t.value
+ }.sort.join(", ")]
+ end
+
SCAN_RE = %r{
# match key
(?:%\{(?<key>[^\}]+)\})