From 65e6278b679c165c8ccc0bc690e3b86a447a4620 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 14:04:36 +0200 Subject: [PATCH 1/8] set baby steps in the transactions query --- app/grids/transactions_query.rb | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 app/grids/transactions_query.rb diff --git a/app/grids/transactions_query.rb b/app/grids/transactions_query.rb new file mode 100644 index 0000000..e7f0ed5 --- /dev/null +++ b/app/grids/transactions_query.rb @@ -0,0 +1,47 @@ +class TransactionsQuery + def initialize user + @user = user + @transactions = Arel::Table.new(:transactions) + end + + def arel + Arel::SelectManager.new(ActiveRecord::Base) + .from(transactions) + .project( + @transactions[:amount], + @transactions[:date], + @transactions[:peer_id], + @transactions[:issuer_id], + @transactions[:message] + ) + end + + def transactions + Arel::Nodes::UnionAll.new(outgoing, incoming) + end + + def outgoing + @transactions + .where(@transactions[:debtor_id].eq(@user.id)) + .project( + (@transactions[:amount]*Arel::Nodes::SqlLiteral.new("-1")).as('amount'), + @transactions[:creditor_id].as('peer_id'), + @transactions[:created_at].as('date'), + @transactions[:issuer_id], + @transactions[:issuer_type] + ) + end + + def incoming + @user.incoming_transactions.arel + @transactions + .where(@transactions[:debtor_id].eq(@user.id)) + .project( + @transactions[:amount], + @transactions[:debtor_id].as('peer_id'), + @transactions[:created_at].as('date'), + @transactions[:issuer_id], + @transactions[:issuer_type] + ) + end +end From 2d753146f00f88cbf969e00207657612c56951ae Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 15:05:46 +0200 Subject: [PATCH 2/8] update transactions query to include peer --- app/grids/transactions_query.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/app/grids/transactions_query.rb b/app/grids/transactions_query.rb index e7f0ed5..032ab97 100644 --- a/app/grids/transactions_query.rb +++ b/app/grids/transactions_query.rb @@ -2,22 +2,25 @@ class TransactionsQuery def initialize user @user = user @transactions = Arel::Table.new(:transactions) + @perspectived = Arel::Table.new(:perspectived_transactions) + @peers = Arel::Table.new(:users).alias('peers') end def arel Arel::SelectManager.new(ActiveRecord::Base) .from(transactions) + .join(@peers).on(@peers[:id].eq(@perspectived[:peer_id])) .project( - @transactions[:amount], - @transactions[:date], - @transactions[:peer_id], - @transactions[:issuer_id], - @transactions[:message] + @perspectived[:amount], + @perspectived[:date], + @peers[:name].as('peer'), + @perspectived[:issuer_id], + @perspectived[:message] ) end def transactions - Arel::Nodes::UnionAll.new(outgoing, incoming) + Arel::Nodes::TableAlias.new(incoming.union(outgoing), @perspectived.name) end def outgoing @@ -28,7 +31,8 @@ class TransactionsQuery @transactions[:creditor_id].as('peer_id'), @transactions[:created_at].as('date'), @transactions[:issuer_id], - @transactions[:issuer_type] + @transactions[:issuer_type], + @transactions[:message] ) end @@ -41,7 +45,8 @@ class TransactionsQuery @transactions[:debtor_id].as('peer_id'), @transactions[:created_at].as('date'), @transactions[:issuer_id], - @transactions[:issuer_type] + @transactions[:issuer_type], + @transactions[:message] ) end end From 81b30902f77ec7056a22c4c66115b1ba1d3915b0 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 15:47:54 +0200 Subject: [PATCH 3/8] add issuer name to transactions query --- app/grids/transactions_query.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/grids/transactions_query.rb b/app/grids/transactions_query.rb index 032ab97..99ea471 100644 --- a/app/grids/transactions_query.rb +++ b/app/grids/transactions_query.rb @@ -7,20 +7,32 @@ class TransactionsQuery end def arel + Arel::SelectManager.new(ActiveRecord::Base) + .from(issued_by(User).union(issued_by(Client))) + .project(Arel.star) + end + + def issued_by klass + issuers = klass.arel_table.alias('issuer') Arel::SelectManager.new(ActiveRecord::Base) .from(transactions) .join(@peers).on(@peers[:id].eq(@perspectived[:peer_id])) + .join(issuers).on(issuers[:id].eq(@perspectived[:issuer_id])) + .where(@perspectived[:issuer_type].eq(klass.name)) .project( @perspectived[:amount], @perspectived[:date], + @perspectived[:message], @peers[:name].as('peer'), - @perspectived[:issuer_id], - @perspectived[:message] + issuers[:name].as('issuer') ) end def transactions - Arel::Nodes::TableAlias.new(incoming.union(outgoing), @perspectived.name) + Arel::Nodes::TableAlias.new( + incoming.union(outgoing), + @perspectived.name + ) end def outgoing From bd99e150a47f97d2c3bda76c98411ca86a8d83b5 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 15:59:22 +0200 Subject: [PATCH 4/8] union all --- app/grids/transactions_query.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/grids/transactions_query.rb b/app/grids/transactions_query.rb index 99ea471..36d2990 100644 --- a/app/grids/transactions_query.rb +++ b/app/grids/transactions_query.rb @@ -8,7 +8,7 @@ class TransactionsQuery def arel Arel::SelectManager.new(ActiveRecord::Base) - .from(issued_by(User).union(issued_by(Client))) + .from(issued_by(User).union(:all, issued_by(Client))) .project(Arel.star) end @@ -30,7 +30,7 @@ class TransactionsQuery def transactions Arel::Nodes::TableAlias.new( - incoming.union(outgoing), + incoming.union(:all, outgoing), @perspectived.name ) end From 8ef41c9503780095e2887462cab5293fd561fe6d Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 16:40:15 +0200 Subject: [PATCH 5/8] add helpers to transactions_query --- app/grids/transactions_query.rb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/grids/transactions_query.rb b/app/grids/transactions_query.rb index 36d2990..2bf0ba8 100644 --- a/app/grids/transactions_query.rb +++ b/app/grids/transactions_query.rb @@ -1,15 +1,25 @@ class TransactionsQuery + attr_reader :arel_table + def initialize user @user = user @transactions = Arel::Table.new(:transactions) @perspectived = Arel::Table.new(:perspectived_transactions) @peers = Arel::Table.new(:users).alias('peers') + @arel_table = Arel::Table.new(@user.name.concat('_transactions')) + end + + def query + Arel::SelectManager.new(ActiveRecord::Base) + .from(arel) + .project(Arel.star) end def arel - Arel::SelectManager.new(ActiveRecord::Base) - .from(issued_by(User).union(:all, issued_by(Client))) - .project(Arel.star) + Arel::Nodes::TableAlias.new( + issued_by(User).union(:all, issued_by(Client)), + arel_table.name + ) end def issued_by klass From fdf4e27a276cefcbc94115757da3d817aadc8c38 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 19:41:47 +0200 Subject: [PATCH 6/8] integrate arel query with datatable --- app/controllers/concerns/data_table.rb | 24 ++++++++++++------- .../concerns}/transactions_query.rb | 6 ++--- 2 files changed, 18 insertions(+), 12 deletions(-) rename app/{grids => controllers/concerns}/transactions_query.rb (93%) diff --git a/app/controllers/concerns/data_table.rb b/app/controllers/concerns/data_table.rb index d8bac14..a192337 100644 --- a/app/controllers/concerns/data_table.rb +++ b/app/controllers/concerns/data_table.rb @@ -1,4 +1,3 @@ - module DataTable extend ActiveSupport::Concern @@ -47,6 +46,12 @@ module DataTable end selection_to_json(user, params[:draw], selection) + + transactions = TransactionsQuery.new(@user) + query = transactions.query + + selection = ActiveRecord::Base.connection.execute(query.to_sql).to_a + response_json(params[:draw], selection) end private @@ -78,18 +83,19 @@ module DataTable return clean end - def selection_to_json(user, draw, selection) + def response_json(draw, selection) { draw: draw, recordsTotal: user.transactions.count, recordsFiltered: selection.count, - data: selection.offset(params[:start]).take(params[:length]).map { |transaction| { - time: transaction.created_at, - amount: transaction.signed_amount_for(user), - peer: transaction.peer_of(user).try(:name), - issuer: transaction.issuer.name, - message: transaction.message, - }} + #data: selection.offset(params[:start]).take(params[:length]).map { |transaction| { + #time: transaction.created_at, + #amount: transaction.signed_amount_for(user), + #peer: transaction.peer_of(user).try(:name), + #issuer: transaction.issuer.name, + #message: transaction.message, + #}} + data: selection } end end diff --git a/app/grids/transactions_query.rb b/app/controllers/concerns/transactions_query.rb similarity index 93% rename from app/grids/transactions_query.rb rename to app/controllers/concerns/transactions_query.rb index 2bf0ba8..8bfd543 100644 --- a/app/grids/transactions_query.rb +++ b/app/controllers/concerns/transactions_query.rb @@ -31,7 +31,7 @@ class TransactionsQuery .where(@perspectived[:issuer_type].eq(klass.name)) .project( @perspectived[:amount], - @perspectived[:date], + @perspectived[:time], @perspectived[:message], @peers[:name].as('peer'), issuers[:name].as('issuer') @@ -51,7 +51,7 @@ class TransactionsQuery .project( (@transactions[:amount]*Arel::Nodes::SqlLiteral.new("-1")).as('amount'), @transactions[:creditor_id].as('peer_id'), - @transactions[:created_at].as('date'), + @transactions[:created_at].as('time'), @transactions[:issuer_id], @transactions[:issuer_type], @transactions[:message] @@ -65,7 +65,7 @@ class TransactionsQuery .project( @transactions[:amount], @transactions[:debtor_id].as('peer_id'), - @transactions[:created_at].as('date'), + @transactions[:created_at].as('time'), @transactions[:issuer_id], @transactions[:issuer_type], @transactions[:message] From dd3c27c3744d168feeface61dd2973de4f23cd68 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 20:12:12 +0200 Subject: [PATCH 7/8] make datatable an object --- app/controllers/concerns/data_table.rb | 113 +++++++++++++++---------- app/controllers/users_controller.rb | 7 +- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/app/controllers/concerns/data_table.rb b/app/controllers/concerns/data_table.rb index a192337..0d29cd3 100644 --- a/app/controllers/concerns/data_table.rb +++ b/app/controllers/concerns/data_table.rb @@ -1,57 +1,82 @@ -module DataTable - extend ActiveSupport::Concern +class DataTable + def initialize user, params + @user = user + @params = sanitize_params(params) + @transactions = TransactionsQuery.new(@user) + @table = @transactions.arel_table + end + + def query + @transactions.query + end + + def predicates + end + + def range_predicates name + col = @params[:columns][name] + [ + (@table[:name].gteq(col[:lower]) if col[:lower]), + (@table[:name].lteq(col[:upper]) if col[:upper]) + ] + end + + def json + #if columns[:time][:lower] + #query = query.where(table[:time].gteq(columns[:time][:lower])) + #end + + #if columns[:time][:upper] + #query = query.where(table + - def apply_filter(user, params) - params = sanitize_params(params) - selection = user.transactions # filter time - lower = params[:columns][:time][:lower] - upper = params[:columns][:time][:upper] - if lower and upper - selection = selection.where(created_at: lower..upper) - elsif lower - selection = selection.where('created_at > :lower', lower: lower) - elsif upper - selection = selection.where('created_at < :upper', upper: upper) - end + #lower = params[:columns][:time][:lower] + #upper = params[:columns][:time][:upper] + #if lower and upper + #selection = selection.where(created_at: lower..upper) + #elsif lower + #selection = selection.where('created_at > :lower', lower: lower) + #elsif upper + #selection = selection.where('created_at < :upper', upper: upper) + #end - # filter amount TODO this filters on absolute value - lower = params[:columns][:amount][:lower] - upper = params[:columns][:amount][:upper] - if lower and upper - selection = selection.where(amount: lower..upper) - elsif lower - selection = selection.where('amount > :lower', lower: lower) - elsif upper - selection = selection.where('amount < :upper', upper: upper) - end + ## filter amount TODO this filters on absolute value + #lower = params[:columns][:amount][:lower] + #upper = params[:columns][:amount][:upper] + #if lower and upper + #selection = selection.where(amount: lower..upper) + #elsif lower + #selection = selection.where('amount > :lower', lower: lower) + #elsif upper + #selection = selection.where('amount < :upper', upper: upper) + #end - # filter peer # TODO peer.name - peer = params[:columns][:peer][:value] - if peer - selection = selection.where("(debtor_id = :id AND creditor_id LIKE :peer) OR (creditor_id = :id AND debtor_id LIKE :peer)", id: user.id, peer: "%#{peer}%") - end + ## filter peer # TODO peer.name + #peer = params[:columns][:peer][:value] + #if peer + #selection = selection.where("(debtor_id = :id AND creditor_id LIKE :peer) OR (creditor_id = :id AND debtor_id LIKE :peer)", id: user.id, peer: "%#{peer}%") + #end - # filter issuer # TODO issuer.name - issuer = params[:columns][:issuer][:value] - if issuer - selection = selection.where("issuer_id LIKE :re", re: "%#{issuer}%") - end + ## filter issuer # TODO issuer.name + #issuer = params[:columns][:issuer][:value] + #if issuer + #selection = selection.where("issuer_id LIKE :re", re: "%#{issuer}%") + #end - # filter message - message = params[:columns][:message][:value] - if message - selection = selection.where("message LIKE :re", re: "%#{message}%") - end + ## filter message + #message = params[:columns][:message][:value] + #if message + #selection = selection.where("message LIKE :re", re: "%#{message}%") + #end - selection_to_json(user, params[:draw], selection) + ##selection_to_json(user, params[:draw], selection) - transactions = TransactionsQuery.new(@user) - query = transactions.query + #query = transactions.query selection = ActiveRecord::Base.connection.execute(query.to_sql).to_a - response_json(params[:draw], selection) + response_json(@params[:draw], selection) end private @@ -86,7 +111,7 @@ module DataTable def response_json(draw, selection) { draw: draw, - recordsTotal: user.transactions.count, + recordsTotal: @user.transactions.count, recordsFiltered: selection.count, #data: selection.offset(params[:start]).take(params[:length]).map { |transaction| { #time: transaction.created_at, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6dcaeb3..d1e5a0a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,13 +1,14 @@ class UsersController < ApplicationController load_and_authorize_resource - include DataTable - def show @user = User.find(params[:id]) respond_to do |format| format.html - format.json { render json: apply_filter(@user, params) } + format.json do + datatable = DataTable.new(@user, params) + render json: datatable.json + end end end From 25c3bdd0ca82cac5891cfda7471ea6f5e4497806 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Thu, 10 Sep 2015 21:09:57 +0200 Subject: [PATCH 8/8] implement filters for datatable --- app/controllers/concerns/data_table.rb | 82 ++++++++------------------ 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/app/controllers/concerns/data_table.rb b/app/controllers/concerns/data_table.rb index 0d29cd3..abdfb4d 100644 --- a/app/controllers/concerns/data_table.rb +++ b/app/controllers/concerns/data_table.rb @@ -1,4 +1,5 @@ class DataTable + def initialize user, params @user = user @params = sanitize_params(params) @@ -6,11 +7,28 @@ class DataTable @table = @transactions.arel_table end + def json + response_json(@params[:draw], data) + end + + def data + ActiveRecord::Base.connection.execute(self.query.to_sql) + end + def query - @transactions.query + pred = predicates + q = @transactions.query + q = q.where(pred) if pred + q end def predicates + [ *range_predicates(:amount), + *range_predicates(:time), + eq_predicate(:peer), + eq_predicate(:issuer), + like_predicate(:message) + ].compact.inject { |l, r| l.and(r) } end def range_predicates name @@ -21,62 +39,14 @@ class DataTable ] end - def json - #if columns[:time][:lower] - #query = query.where(table[:time].gteq(columns[:time][:lower])) - #end + def eq_predicate name + value = @params[:columns][:name][:value] + @table[:name].eq(value) if value + end - #if columns[:time][:upper] - #query = query.where(table - - - - # filter time - #lower = params[:columns][:time][:lower] - #upper = params[:columns][:time][:upper] - #if lower and upper - #selection = selection.where(created_at: lower..upper) - #elsif lower - #selection = selection.where('created_at > :lower', lower: lower) - #elsif upper - #selection = selection.where('created_at < :upper', upper: upper) - #end - - ## filter amount TODO this filters on absolute value - #lower = params[:columns][:amount][:lower] - #upper = params[:columns][:amount][:upper] - #if lower and upper - #selection = selection.where(amount: lower..upper) - #elsif lower - #selection = selection.where('amount > :lower', lower: lower) - #elsif upper - #selection = selection.where('amount < :upper', upper: upper) - #end - - ## filter peer # TODO peer.name - #peer = params[:columns][:peer][:value] - #if peer - #selection = selection.where("(debtor_id = :id AND creditor_id LIKE :peer) OR (creditor_id = :id AND debtor_id LIKE :peer)", id: user.id, peer: "%#{peer}%") - #end - - ## filter issuer # TODO issuer.name - #issuer = params[:columns][:issuer][:value] - #if issuer - #selection = selection.where("issuer_id LIKE :re", re: "%#{issuer}%") - #end - - ## filter message - #message = params[:columns][:message][:value] - #if message - #selection = selection.where("message LIKE :re", re: "%#{message}%") - #end - - ##selection_to_json(user, params[:draw], selection) - - #query = transactions.query - - selection = ActiveRecord::Base.connection.execute(query.to_sql).to_a - response_json(@params[:draw], selection) + def like_predicate name + value = @params[:columns][:name][:value] + @table[:name].matches("%#{value}%") if value end private