From a9559dca6dfd2be96045a7edaf28d50913b115f7 Mon Sep 17 00:00:00 2001 From: Hengle Jiang Date: Sun, 19 Aug 2018 23:51:10 -0500 Subject: [PATCH] test auto resource mysql --- examples/auto.cr | 17 +++ src/CrectoAdmin/auto_resource.cr | 176 +++++++++++++++++++++++++++++++ src/CrectoAdmin/resource.cr | 4 +- 3 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 examples/auto.cr create mode 100644 src/CrectoAdmin/auto_resource.cr diff --git a/examples/auto.cr b/examples/auto.cr new file mode 100644 index 0000000..01bebee --- /dev/null +++ b/examples/auto.cr @@ -0,0 +1,17 @@ +# This will generate the crecto admin code for all tables in the database +# Only works for Mysql database currently +# Redirect the output code to the src folder and run/debug it manually +require "mysql" +require "../src/crecto-admin" # require "crecto-admin" instead if installed crecto-admin + +# Setup your repo +module Repo + extend Crecto::Repo + config do |conf| + conf.adapter = Crecto::Adapters::Mysql + conf.uri = "mysql://root:root@localhost:3306/unlcms2" # use your database uri + end +end + +# Generate Crystal code +auto_script(Repo) diff --git a/src/CrectoAdmin/auto_resource.cr b/src/CrectoAdmin/auto_resource.cr new file mode 100644 index 0000000..18c4617 --- /dev/null +++ b/src/CrectoAdmin/auto_resource.cr @@ -0,0 +1,176 @@ +module CrectoAdmin + class Column + property column_name : String + property column_key : String + property extra : String + property data_type : String + + def initialize(@column_name, @column_key, @extra, @data_type) + end + + def is_created_at? + column_name = @column_name.downcase + data_type = @data_type.downcase + (column_name == "created_at") && (data_type == "datetime") + end + + def is_updated_at? + column_name = @column_name.downcase + data_type = @data_type.downcase + (column_name == "updated_at") && (data_type == "datetime") + end + + def column_type + t = @data_type.upcase + return "Bool" if t.includes? "BOOL" + return "Int64" if t.includes?("INT") || t.includes?("SERIAL") + return "Float64" if t.includes?("DEC") || t.includes?("FLOAT") || t.includes?("DOUBLE") + return "Time" if t.includes? "DATETIME" + return "String" if t.includes?("CHAR") || t.includes?("TEXT") + nil + end + end + + class Table + property db_name : String + property table_name : String + property columns : Array(CrectoAdmin::Column) + property class_name : String + + def initialize(@db_name, @table_name) + @columns = [] of CrectoAdmin::Column + @class_name = "#{table_name[0].upcase}#{table_name[1..-1]}" + end + + def has_created_at? + @columns.each do |column| + return true if column.is_created_at? + end + false + end + + def has_updated_at? + @columns.each do |column| + return true if column.is_updated_at? + end + false + end + + def primary_key_column + pri_columns = [] of CrectoAdmin::Column + @columns.each do |column| + column_key = column.column_key.downcase + pri_columns << column if column_key.includes?("pri") + end + return nil if pri_columns.empty? + pri_columns.each do |column| + return column if column.column_name.includes? "id" + end + pri_columns[0] + end + + def has_primary_key_auto? + pri_column = primary_key_column + return false if pri_column.nil? + pri_column = pri_column.as(CrectoAdmin::Column) + pri_column.extra.includes?("auto_increment") + end + end + + def self.build_header(uri) + String.build do |s| + s << "require \"mysql\"\n" + s << "require \"crecto-admin\"\n\n" + s << "module Repo\n" + s << " extend Crecto::Repo\n" + s << " config do |conf|\n" + s << " conf.adapter = Crecto::Adapters::Mysql\n" + s << " conf.uri = \"" << uri << "\"\n" + s << " end\n" + s << "end\n\n" + s << "init_admin()\n\n" + end + end + + def self.build_class(table) + return "# skip table: #{table.table_name}, no primary_key\n\n" if table.primary_key_column.nil? + return "# skip table: #{table.table_name}, only primary_key\n\n" if table.columns.size < 2 + String.build do |s| + s << "class #{table.class_name} < Crecto::Model\n" + s << " set_created_at_field nil\n" unless table.has_created_at? + s << " set_updated_at_field nil\n" unless table.has_updated_at? + s << " schema \"#{table.table_name}\" do\n" + columns_symbols = [] of String + table.columns.each do |column| + if column == table.primary_key_column + s << " field :#{column.column_name}, PkeyValue, primary_key: true\n" + columns_symbols << ":#{column.column_name}" + elsif column.is_created_at? || column.is_updated_at? + next + elsif column.column_type.nil? + s << " # skip column: #{column.column_name} (#{column.data_type})\n" + else + s << " field :#{column.column_name}, #{column.column_type}\n" + columns_symbols << ":#{column.column_name}" + end + end + s << " end\n" + unless table.has_primary_key_auto? + s << " def self.form_attributes\n" + s << " [#{columns_symbols.join(", ")}]\n" + s << " end\n" + end + s << "end\n" + s << "admin_resource(#{table.class_name}, Repo)\n\n" + end + end + + def self.build_tail + String.build do |s| + s << "Kemal::Session.config do |config|\n" + s << " config.secret = \"my super secret\"\n" + s << "end\n" + s << "Kemal.run\n\n" + end + end +end + +def self.auto_script(repo) + db_uri = repo.config.database_url + index1 = db_uri.rindex('/') + index1 = -1 if index1.nil? + info_uri = db_uri[0..index1] + "information_schema" + index2 = db_uri.index('?') + index2 = -1 if index2.nil? + db_name = db_uri[index1 + 1..index2] + db_uri = db_uri[0..(index2 - 1)] unless index2 == -1 + + tables = {} of String => CrectoAdmin::Table + DB.open info_uri do |db| + db.query "select table_name, column_name, column_key, extra, data_type from columns where table_schema = '#{db_name}'" do |rs| + rs.each do + table_name = rs.read(String) + column_name = rs.read(String) + column_key = rs.read(String) + extra = rs.read(String) + data_type = rs.read(String) + tables[table_name] = CrectoAdmin::Table.new(db_name, table_name) unless tables.has_key? table_name + tables[table_name].columns << CrectoAdmin::Column.new(column_name, column_key, extra, data_type) + end + end + end + + header = CrectoAdmin.build_header(db_uri) + classes = tables.values.map do |table| + CrectoAdmin.build_class(table) + end + tail = CrectoAdmin.build_tail + all = String.build do |s| + s << header + classes.each do |c| + s << c + end + s << tail + end + puts all +end diff --git a/src/CrectoAdmin/resource.cr b/src/CrectoAdmin/resource.cr index 3558c43..9607aee 100644 --- a/src/CrectoAdmin/resource.cr +++ b/src/CrectoAdmin/resource.cr @@ -29,8 +29,8 @@ def self.admin_resource(model : Crecto::Model.class, repo, **opts) form_attributes = CrectoAdmin.merge_form_attributes(model.form_attributes, form_attributes) else form_attributes = form_attributes.select do |a| - next a == model.primary_key_field_symbol if a.is_a? Symbol - a[0] == model.primary_key_field_symbol + next a != model.primary_key_field_symbol if a.is_a? Symbol + a[0] != model.primary_key_field_symbol end end