Ruby on Rails random LOC |
1 | module Arel |
2 | module AliasPredication |
3 | def as other |
4 | Nodes::As.new self, Nodes::SqlLiteral.new(other) |
5 | end |
6 | end |
7 | endmodule Arel |
8 | module Attributes |
9 | class Attribute Struct.new :relation, :name |
10 | include Arel::Expressions |
11 | include Arel::Predications |
12 | include Arel::AliasPredication |
13 | include Arel::OrderPredications |
14 | include Arel::Math |
15 | def lower |
16 | relation.lower self |
17 | end |
18 | def type_cast_for_database(value) |
19 | relation.type_cast_for_database(name, value) |
20 | end |
21 | def able_to_type_cast? |
22 | relation.able_to_type_cast? |
23 | end |
24 | end |
25 | class String Attribute; end |
26 | class Time Attribute; end |
27 | class Boolean Attribute; end |
28 | class Decimal Attribute; end |
29 | class Float Attribute; end |
30 | class Integer Attribute; end |
31 | class Undefined Attribute; end |
32 | end |
33 | Attribute = Attributes::Attribute |
34 | end |
35 | require 'arel/attributes/attribute' |
36 | module Arel |
37 | module Attributes |
38 | def self.for column |
39 | case column.type |
40 | when :string, :text, :binary then String |
41 | when :integer then Integer |
42 | when :float then Float |
43 | when :decimal then Decimal |
44 | when :boolean then Boolean |
45 | else |
46 | Undefined |
47 | end |
48 | end |
49 | end |
50 | end |
51 | module Arel |
52 | module Collectors |
53 | class Bind |
54 | def initialize |
55 | @parts = [] |
56 | end |
57 | def str |
58 | @parts str |
59 | self |
60 | end |
61 | def add_bind bind |
62 | @parts bind |
63 | self |
64 | end |
65 | def value; @parts; end |
66 | def substitute_binds bvs |
67 | bvs = bvs.dup |
68 | @parts.map do |val| |
69 | if Arel::Nodes::BindParam === val |
70 | bvs.shift |
71 | else |
72 | val |
73 | end |
74 | end |
75 | end |
76 | def compile bvs |
77 | substitute_binds(bvs).join |
78 | end |
79 | end |
80 | end |
81 | end |
82 | module Arel |
83 | module Collectors |
84 | class PlainString |
85 | def initialize |
86 | @str = '' |
87 | end |
88 | def value |
89 | @str |
90 | end |
91 | def str |
92 | @str str |
93 | self |
94 | end |
95 | end |
96 | end |
97 | end |
98 | require 'arel/collectors/plain_string' |
99 | module Arel |
100 | module Collectors |
101 | class SQLString PlainString |
102 | def initialize(*) |
103 | super |
104 | @bind_index = 1 |
105 | end |
106 | def add_bind bind |
107 | self yield(@bind_index) |
108 | @bind_index += 1 |
109 | self |
110 | end |
111 | def compile bvs |
112 | value |
113 | end |
114 | end |
115 | end |
116 | end |
117 | module Arel |
118 | module Compatibility # :nodoc: |
119 | class Wheres # :nodoc: |
120 | include Enumerable |
121 | module Value # :nodoc: |
122 | attr_accessor :visitor |
123 | def value |
124 | visitor.accept self |
125 | end |
126 | def name |
127 | super.to_sym |
128 | end |
129 | end |
130 | def initialize engine, collection |
131 | @engine = engine |
132 | @collection = collection |
133 | end |
134 | def each |
135 | to_sql = Visitors::ToSql.new @engine |
136 | @collection.each { |c| |
137 | c.extend(Value) |
138 | c.visitor = to_sql |
139 | yield c |
140 | } |
141 | end |
142 | end |
143 | end |
144 | end |
145 | module Arel |
146 | module Crud |
147 | def compile_update values, pk |
148 | um = UpdateManager.new |
149 | if Nodes::SqlLiteral === values |
150 | relation = @ctx.from |
151 | else |
152 | relation = values.first.first.relation |
153 | end |
154 | um.key = pk |
155 | um.table relation |
156 | um.set values |
157 | um.take @ast.limit.expr if @ast.limit |
158 | um.order(*@ast.orders) |
159 | um.wheres = @ctx.wheres |
160 | um |
161 | end |
162 | def compile_insert values |
163 | im = create_insert |
164 | im.insert values |
165 | im |
166 | end |
167 | def create_insert |
168 | InsertManager.new |
169 | end |
170 | def compile_delete |
171 | dm = DeleteManager.new |
172 | dm.wheres = @ctx.wheres |
173 | dm.from @ctx.froms |
174 | dm |
175 | end |
176 | end |
177 | end |
178 | module Arel |
179 | class DeleteManager Arel::TreeManager |
180 | def initialize |
181 | super |
182 | @ast = Nodes::DeleteStatement.new |
183 | @ctx = @ast |
184 | end |
185 | def from relation |
186 | @ast.relation = relation |
187 | self |
188 | end |
189 | def wheres= list |
190 | @ast.wheres = list |
191 | end |
192 | end |
193 | end |
194 | module Arel |
195 | module Expressions |
196 | def count distinct = false |
197 | Nodes::Count.new [self], distinct |
198 | end |
199 | def sum |
200 | Nodes::Sum.new [self] |
201 | end |
202 | def maximum |
203 | Nodes::Max.new [self] |
204 | end |
205 | def minimum |
206 | Nodes::Min.new [self] |
207 | end |
208 | def average |
209 | Nodes::Avg.new [self] |
210 | end |
211 | def extract field |
212 | Nodes::Extract.new [self], field |
213 | end |
214 | end |
215 | end |
216 | module Arel |
217 | module FactoryMethods |
218 | def create_true |
219 | Arel::Nodes::True.new |
220 | end |
221 | def create_false |
222 | Arel::Nodes::False.new |
223 | end |
224 | def create_table_alias relation, name |
225 | Nodes::TableAlias.new(relation, name) |
226 | end |
227 | klass.new(to, constraint) |
228 | end |
229 | def create_string_join to |
230 | create_join to, nil, Nodes::StringJoin |
231 | end |
232 | def create_and clauses |
233 | Nodes::And.new clauses |
234 | end |
235 | def create_on expr |
236 | Nodes::On.new expr |
237 | end |
238 | def grouping expr |
239 | Nodes::Grouping.new expr |
240 | end |
241 | def lower column |
242 | end |
243 | end |
244 | end |
245 | module Arel |
246 | class InsertManager Arel::TreeManager |
247 | def initialize |
248 | super |
249 | @ast = Nodes::InsertStatement.new |
250 | end |
251 | def into table |
252 | @ast.relation = table |
253 | self |
254 | end |
255 | def columns; @ast.columns end |
256 | def values= val; @ast.values = val; end |
257 | def select select |
258 | @ast.select = select |
259 | end |
260 | def insert fields |
261 | return if fields.empty? |
262 | if String === fields |
263 | @ast.values = Nodes::SqlLiteral.new(fields) |
264 | else |
265 | @ast.relation ||= fields.first.first.relation |
266 | values = [] |
267 | fields.each do |column, value| |
268 | @ast.columns column |
269 | values value |
270 | end |
271 | @ast.values = create_values values, @ast.columns |
272 | end |
273 | end |
274 | def create_values values, columns |
275 | Nodes::Values.new values, columns |
276 | end |
277 | end |
278 | end |
279 | module Arel |
280 | module Math |
281 | def *(other) |
282 | Arel::Nodes::Multiplication.new(self, other) |
283 | end |
284 | def +(other) |
285 | end |
286 | def -(other) |
287 | end |
288 | def /(other) |
289 | Arel::Nodes::Division.new(self, other) |
290 | end |
291 | end |
292 | end |
293 | module Arel |
294 | module Nodes |
295 | class And Arel::Nodes::Node |
296 | attr_reader :children |
297 | def initialize children |
298 | super() |
299 | @children = children |
300 | end |
301 | def left |
302 | children.first |
303 | end |
304 | def right |
305 | children[1] |
306 | end |
307 | def hash |
308 | children.hash |
309 | end |
310 | def eql? other |
311 | self.class == other.class && |
312 | self.children == other.children |
313 | end |
314 | alias :== :eql? |
315 | end |
316 | end |
317 | end |
318 | module Arel |
319 | module Nodes |
320 | class Ascending Ordering |
321 | def reverse |
322 | Descending.new(expr) |
323 | end |
324 | def direction |
325 | :asc |
326 | end |
327 | def ascending? |
328 | true |
329 | end |
330 | def descending? |
331 | false |
332 | end |
333 | end |
334 | end |
335 | end |
336 | module Arel |
337 | module Nodes |
338 | class Binary Arel::Nodes::Node |
339 | attr_accessor :left, :right |
340 | def initialize left, right |
341 | super() |
342 | @left = left |
343 | @right = right |
344 | end |
345 | def initialize_copy other |
346 | super |
347 | @left = @left.clone if @left |
348 | @right = @right.clone if @right |
349 | end |
350 | def hash |
351 | [self.class, @left, @right].hash |
352 | end |
353 | def eql? other |
354 | self.class == other.class && |
355 | self.left == other.left && |
356 | self.right == other.right |
357 | end |
358 | alias :== :eql? |
359 | end |
360 | %w{ |
361 | As |
362 | Assignment |
363 | Between |
364 | GreaterThan |
365 | GreaterThanOrEqual |
366 | Join |
367 | LessThan |
368 | LessThanOrEqual |
369 | NotEqual |
370 | NotIn |
371 | NotRegexp |
372 | Or |
373 | Regexp |
374 | Union |
375 | UnionAll |
376 | Intersect |
377 | Except |
378 | }.each do |name| |
379 | const_set name, Class.new(Binary) |
380 | end |
381 | end |
382 | end |
383 | module Arel |
384 | module Nodes |
385 | class BindParam Node |
386 | def ==(other) |
387 | other.is_a?(BindParam) |
388 | end |
389 | end |
390 | end |
391 | end |
392 | module Arel |
393 | module Nodes |
394 | class Count Arel::Nodes::Function |
395 | super(expr, aliaz) |
396 | @distinct = distinct |
397 | end |
398 | end |
399 | end |
400 | end |
401 | module Arel |
402 | module Nodes |
403 | class DeleteStatement Arel::Nodes::Binary |
404 | alias :relation :left |
405 | alias :relation= :left= |
406 | alias :wheres :right |
407 | alias :wheres= :right= |
408 | def initialize relation = nil, wheres = [] |
409 | super |
410 | end |
411 | def initialize_copy other |
412 | super |
413 | @right = @right.clone |
414 | end |
415 | end |
416 | end |
417 | end |
418 | module Arel |
419 | module Nodes |
420 | class Descending Ordering |
421 | def reverse |
422 | Ascending.new(expr) |
423 | end |
424 | def direction |
425 | :desc |
426 | end |
427 | def ascending? |
428 | false |
429 | end |
430 | def descending? |
431 | true |
432 | end |
433 | end |
434 | end |
435 | end |
436 | module Arel |
437 | module Nodes |
438 | class Equality Arel::Nodes::Binary |
439 | def operator; :== end |
440 | alias :operand1 :left |
441 | alias :operand2 :right |
442 | end |
443 | end |
444 | end |
445 | module Arel |
446 | module Nodes |
447 | class Extract Arel::Nodes::Unary |
448 | include Arel::AliasPredication |
449 | include Arel::Predications |
450 | attr_accessor :field |
451 | def initialize expr, field |
452 | super(expr) |
453 | @field = field |
454 | end |
455 | def hash |
456 | super ^ @field.hash |
457 | end |
458 | def eql? other |
459 | super && |
460 | self.field == other.field |
461 | end |
462 | alias :== :eql? |
463 | end |
464 | end |
465 | end |
466 | module Arel |
467 | module Nodes |
468 | class False Arel::Nodes::Node |
469 | def hash |
470 | self.class.hash |
471 | end |
472 | def eql? other |
473 | self.class == other.class |
474 | end |
475 | end |
476 | end |
477 | end |
478 | module Arel |
479 | module Nodes |
480 | class FullOuterJoin Arel::Nodes::Join |
481 | end |
482 | end |
483 | end |
484 | module Arel |
485 | module Nodes |
486 | class Function Arel::Nodes::Node |
487 | include Arel::Predications |
488 | include Arel::WindowPredications |
489 | attr_accessor :expressions, :alias, :distinct |
490 | def initialize expr, aliaz = nil |
491 | super() |
492 | @expressions = expr |
493 | @alias = aliaz && SqlLiteral.new(aliaz) |
494 | @distinct = false |
495 | end |
496 | def as aliaz |
497 | self.alias = SqlLiteral.new(aliaz) |
498 | self |
499 | end |
500 | def hash |
501 | [@expressions, @alias, @distinct].hash |
502 | end |
503 | def eql? other |
504 | self.class == other.class && |
505 | self.expressions == other.expressions && |
506 | self.alias == other.alias && |
507 | self.distinct == other.distinct |
508 | end |
509 | end |
510 | %w{ |
511 | Sum |
512 | Exists |
513 | Max |
514 | Min |
515 | Avg |
516 | }.each do |name| |
517 | const_set(name, Class.new(Function)) |
518 | end |
519 | end |
520 | end |
521 | module Arel |
522 | module Nodes |
523 | class Grouping Unary |
524 | include Arel::Predications |
525 | end |
526 | end |
527 | end |
528 | module Arel |
529 | module Nodes |
530 | class In Equality |
531 | end |
532 | end |
533 | end |
534 | module Arel |
535 | module Nodes |
536 | class InfixOperation Binary |
537 | include Arel::Expressions |
538 | include Arel::Predications |
539 | include Arel::OrderPredications |
540 | include Arel::AliasPredication |
541 | include Arel::Math |
542 | attr_reader :operator |
543 | def initialize operator, left, right |
544 | super(left, right) |
545 | @operator = operator |
546 | end |
547 | end |
548 | class Multiplication InfixOperation |
549 | def initialize left, right |
550 | super(:*, left, right) |
551 | end |
552 | end |
553 | class Division InfixOperation |
554 | def initialize left, right |
555 | super(:/, left, right) |
556 | end |
557 | end |
558 | class Addition InfixOperation |
559 | def initialize left, right |
560 | super(:+, left, right) |
561 | end |
562 | end |
563 | class Subtraction InfixOperation |
564 | def initialize left, right |
565 | super(:-, left, right) |
566 | end |
567 | end |
568 | end |
569 | endmodule Arel |
570 | module Nodes |
571 | class InnerJoin Arel::Nodes::Join |
572 | end |
573 | end |
574 | end |
575 | module Arel |
576 | module Nodes |
577 | class InsertStatement Arel::Nodes::Node |
578 | def initialize |
579 | super() |
580 | @relation = nil |
581 | @columns = [] |
582 | @values = nil |
583 | @select = nil |
584 | end |
585 | def initialize_copy other |
586 | super |
587 | @columns = @columns.clone |
588 | @values = @values.clone if @values |
589 | @select = @select.clone if @select |
590 | end |
591 | def hash |
592 | [@relation, @columns, @values, @select].hash |
593 | end |
594 | def eql? other |
595 | self.class == other.class && |
596 | self.relation == other.relation && |
597 | self.columns == other.columns && |
598 | self.select == other.select && |
599 | self.values == other.values |
600 | end |
601 | alias :== :eql? |
602 | end |
603 | end |
604 | end |
605 | module Arel |
606 | module Nodes |
607 | class JoinSource Arel::Nodes::Binary |
608 | def initialize single_source, joinop = [] |
609 | super |
610 | end |
611 | def empty? |
612 | !left && right.empty? |
613 | end |
614 | end |
615 | end |
616 | end |
617 | module Arel |
618 | module Nodes |
619 | class Matches Binary |
620 | attr_reader :escape |
621 | def initialize(left, right, escape = nil) |
622 | super(left, right) |
623 | @escape = escape && Nodes.build_quoted(escape) |
624 | end |
625 | end |
626 | class DoesNotMatch Matches; end |
627 | end |
628 | end |
629 | module Arel |
630 | module Nodes |
631 | class NamedFunction Arel::Nodes::Function |
632 | attr_accessor :name |
633 | def initialize name, expr, aliaz = nil |
634 | super(expr, aliaz) |
635 | @name = name |
636 | end |
637 | def hash |
638 | super ^ @name.hash |
639 | end |
640 | def eql? other |
641 | super && self.name == other.name |
642 | end |
643 | alias :== :eql? |
644 | end |
645 | end |
646 | end |
647 | require 'arel/collectors/sql_string' |
648 | module Arel |
649 | module Nodes |
650 | class Node |
651 | include Arel::FactoryMethods |
652 | include Enumerable |
653 | if $DEBUG |
654 | def _caller |
655 | @caller |
656 | end |
657 | def initialize |
658 | @caller = caller.dup |
659 | end |
660 | end |
661 | def not |
662 | Nodes::Not.new self |
663 | end |
664 | def or right |
665 | Nodes::Grouping.new Nodes::Or.new(self, right) |
666 | end |
667 | def and right |
668 | Nodes::And.new [self, right] |
669 | end |
670 | def to_sql engine = Table.engine |
671 | collector = Arel::Collectors::SQLString.new |
672 | collector.value |
673 | end |
674 | def each &block |
675 | return enum_for(:each) unless block_given? |
676 | end |
677 | end |
678 | end |
679 | end |
680 | module Arel |
681 | module Nodes |
682 | class OuterJoin Arel::Nodes::Join |
683 | end |
684 | end |
685 | end |
686 | module Arel |
687 | module Nodes |
688 | class Over Binary |
689 | include Arel::AliasPredication |
690 | def initialize(left, right = nil) |
691 | super(left, right) |
692 | end |
693 | def operator; 'OVER' end |
694 | end |
695 | end |
696 | endmodule Arel |
697 | module Nodes |
698 | class RightOuterJoin Arel::Nodes::Join |
699 | end |
700 | end |
701 | end |
702 | module Arel |
703 | module Nodes |
704 | class SelectCore Arel::Nodes::Node |
705 | attr_accessor :havings, :source, :set_quantifier |
706 | def initialize |
707 | super() |
708 | @source = JoinSource.new nil |
709 | @top = nil |
710 | @set_quantifier = nil |
711 | @projections = [] |
712 | @wheres = [] |
713 | @groups = [] |
714 | @havings = [] |
715 | @windows = [] |
716 | end |
717 | def from |
718 | @source.left |
719 | end |
720 | def from= value |
721 | @source.left = value |
722 | end |
723 | alias :froms= :from= |
724 | alias :froms :from |
725 | def initialize_copy other |
726 | super |
727 | @source = @source.clone if @source |
728 | @projections = @projections.clone |
729 | @wheres = @wheres.clone |
730 | @groups = @groups.clone |
731 | @havings = @havings.clone |
732 | @windows = @windows.clone |
733 | end |
734 | def hash |
735 | [ |
736 | @source, @top, @set_quantifier, @projections, |
737 | @wheres, @groups, @havings, @windows |
738 | ].hash |
739 | end |
740 | def eql? other |
741 | self.class == other.class && |
742 | self.source == other.source && |
743 | self.top == other.top && |
744 | self.set_quantifier == other.set_quantifier && |
745 | self.projections == other.projections && |
746 | self.wheres == other.wheres && |
747 | self.groups == other.groups && |
748 | self.havings == other.havings && |
749 | self.windows == other.windows |
750 | end |
751 | alias :== :eql? |
752 | end |
753 | end |
754 | end |
755 | module Arel |
756 | module Nodes |
757 | class SelectStatement Arel::Nodes::Node |
758 | attr_reader :cores |
759 | def initialize cores = [SelectCore.new] |
760 | super() |
761 | @cores = cores |
762 | @orders = [] |
763 | @limit = nil |
764 | @lock = nil |
765 | @offset = nil |
766 | @with = nil |
767 | end |
768 | def initialize_copy other |
769 | super |
770 | @cores = @cores.map { |x| x.clone } |
771 | @orders = @orders.map { |x| x.clone } |
772 | end |
773 | def hash |
774 | end |
775 | def eql? other |
776 | self.class == other.class && |
777 | self.cores == other.cores && |
778 | self.orders == other.orders && |
779 | self.limit == other.limit && |
780 | self.lock == other.lock && |
781 | self.offset == other.offset && |
782 | self.with == other.with |
783 | end |
784 | alias :== :eql? |
785 | end |
786 | end |
787 | end |
788 | module Arel |
789 | module Nodes |
790 | class SqlLiteral String |
791 | include Arel::Expressions |
792 | include Arel::Predications |
793 | include Arel::AliasPredication |
794 | include Arel::OrderPredications |
795 | def encode_with(coder) |
796 | coder.scalar = self.to_s |
797 | end |
798 | end |
799 | end |
800 | end |
801 | module Arel |
802 | module Nodes |
803 | class StringJoin Arel::Nodes::Join |
804 | def initialize left, right = nil |
805 | super |
806 | end |
807 | end |
808 | end |
809 | end |
810 | module Arel |
811 | module Nodes |
812 | class TableAlias Arel::Nodes::Binary |
813 | alias :name :right |
814 | alias :relation :left |
815 | alias :table_alias :name |
816 | def [] name |
817 | Attribute.new(self, name) |
818 | end |
819 | def table_name |
820 | end |
821 | def type_cast_for_database(*args) |
822 | relation.type_cast_for_database(*args) |
823 | end |
824 | def able_to_type_cast? |
825 | end |
826 | end |
827 | end |
828 | end |
829 | module Arel |
830 | module Nodes |
831 | class Distinct Arel::Nodes::Node |
832 | def hash |
833 | self.class.hash |
834 | end |
835 | def eql? other |
836 | self.class == other.class |
837 | end |
838 | end |
839 | end |
840 | end |
841 | module Arel |
842 | module Nodes |
843 | class True Arel::Nodes::Node |
844 | def hash |
845 | self.class.hash |
846 | end |
847 | def eql? other |
848 | self.class == other.class |
849 | end |
850 | end |
851 | end |
852 | end |
853 | module Arel |
854 | module Nodes |
855 | class Unary Arel::Nodes::Node |
856 | attr_accessor :expr |
857 | alias :value :expr |
858 | def initialize expr |
859 | super() |
860 | @expr = expr |
861 | end |
862 | def hash |
863 | @expr.hash |
864 | end |
865 | def eql? other |
866 | self.class == other.class && |
867 | self.expr == other.expr |
868 | end |
869 | alias :== :eql? |
870 | end |
871 | %w{ |
872 | Bin |
873 | Group |
874 | Limit |
875 | Not |
876 | Offset |
877 | On |
878 | Ordering |
879 | Top |
880 | Lock |
881 | DistinctOn |
882 | }.each do |name| |
883 | const_set(name, Class.new(Unary)) |
884 | end |
885 | end |
886 | end |
887 | module Arel |
888 | module Nodes |
889 | class UnqualifiedColumn Arel::Nodes::Unary |
890 | alias :attribute :expr |
891 | alias :attribute= :expr= |
892 | def relation |
893 | @expr.relation |
894 | end |
895 | def column |
896 | @expr.column |
897 | end |
898 | def name |
899 | @expr.name |
900 | end |
901 | end |
902 | end |
903 | end |
904 | module Arel |
905 | module Nodes |
906 | class UpdateStatement Arel::Nodes::Node |
907 | attr_accessor :key |
908 | def initialize |
909 | @relation = nil |
910 | @wheres = [] |
911 | @values = [] |
912 | @orders = [] |
913 | @limit = nil |
914 | @key = nil |
915 | end |
916 | def initialize_copy other |
917 | super |
918 | @wheres = @wheres.clone |
919 | @values = @values.clone |
920 | end |
921 | def hash |
922 | end |
923 | def eql? other |
924 | self.class == other.class && |
925 | self.relation == other.relation && |
926 | self.wheres == other.wheres && |
927 | self.values == other.values && |
928 | self.orders == other.orders && |
929 | self.limit == other.limit && |
930 | self.key == other.key |
931 | end |
932 | alias :== :eql? |
933 | end |
934 | end |
935 | end |
936 | module Arel |
937 | module Nodes |
938 | class Values Arel::Nodes::Binary |
939 | alias :expressions :left |
940 | alias :expressions= :left= |
941 | alias :columns :right |
942 | alias :columns= :right= |
943 | def initialize exprs, columns = [] |
944 | super |
945 | end |
946 | end |
947 | end |
948 | end |
949 | module Arel |
950 | module Nodes |
951 | class Window Arel::Nodes::Node |
952 | attr_accessor :orders, :framing, :partitions |
953 | def initialize |
954 | @orders = [] |
955 | @partitions = [] |
956 | @framing = nil |
957 | end |
958 | def order *expr |
959 | @orders.concat expr.map { |x| |
960 | } |
961 | self |
962 | end |
963 | def partition *expr |
964 | @partitions.concat expr.map { |x| |
965 | } |
966 | self |
967 | end |
968 | def frame(expr) |
969 | @framing = expr |
970 | end |
971 | def rows(expr = nil) |
972 | if @framing |
973 | Rows.new(expr) |
974 | else |
975 | frame(Rows.new(expr)) |
976 | end |
977 | end |
978 | def range(expr = nil) |
979 | if @framing |
980 | Range.new(expr) |
981 | else |
982 | frame(Range.new(expr)) |
983 | end |
984 | end |
985 | def initialize_copy other |
986 | super |
987 | @orders = @orders.map { |x| x.clone } |
988 | end |
989 | def hash |
990 | [@orders, @framing].hash |
991 | end |
992 | def eql? other |
993 | self.class == other.class && |
994 | self.orders == other.orders && |
995 | self.framing == other.framing && |
996 | self.partitions == other.partitions |
997 | end |
998 | alias :== :eql? |
999 | end |
1000 | class NamedWindow Window |
1001 | attr_accessor :name |
1002 | def initialize name |
1003 | super() |
1004 | @name = name |
1005 | end |
1006 | def initialize_copy other |
1007 | super |
1008 | @name = other.name.clone |
1009 | end |
1010 | def hash |
1011 | super ^ @name.hash |
1012 | end |
1013 | def eql? other |
1014 | super && self.name == other.name |
1015 | end |
1016 | alias :== :eql? |
1017 | end |
1018 | class Rows Unary |
1019 | def initialize(expr = nil) |
1020 | super(expr) |
1021 | end |
1022 | end |
1023 | class Range Unary |
1024 | def initialize(expr = nil) |
1025 | super(expr) |
1026 | end |
1027 | end |
1028 | class CurrentRow Node |
1029 | def hash |
1030 | self.class.hash |
1031 | end |
1032 | def eql? other |
1033 | self.class == other.class |
1034 | end |
1035 | end |
1036 | class Preceding Unary |
1037 | def initialize(expr = nil) |
1038 | super(expr) |
1039 | end |
1040 | end |
1041 | class Following Unary |
1042 | def initialize(expr = nil) |
1043 | super(expr) |
1044 | end |
1045 | end |
1046 | end |
1047 | end |
1048 | module Arel |
1049 | module Nodes |
1050 | class With Arel::Nodes::Unary |
1051 | alias children expr |
1052 | end |
1053 | class WithRecursive With; end |
1054 | end |
1055 | end |
1056 | require 'arel/nodes/node' |
1057 | require 'arel/nodes/select_statement' |
1058 | require 'arel/nodes/select_core' |
1059 | require 'arel/nodes/insert_statement' |
1060 | require 'arel/nodes/update_statement' |
1061 | require 'arel/nodes/bind_param' |
1062 | require 'arel/nodes/terminal' |
1063 | require 'arel/nodes/true' |
1064 | require 'arel/nodes/false' |
1065 | require 'arel/nodes/unary' |
1066 | require 'arel/nodes/grouping' |
1067 | require 'arel/nodes/ascending' |
1068 | require 'arel/nodes/descending' |
1069 | require 'arel/nodes/unqualified_column' |
1070 | require 'arel/nodes/with' |
1071 | require 'arel/nodes/binary' |
1072 | require 'arel/nodes/equality' |
1073 | require 'arel/nodes/join_source' |
1074 | require 'arel/nodes/delete_statement' |
1075 | require 'arel/nodes/table_alias' |
1076 | require 'arel/nodes/infix_operation' |
1077 | require 'arel/nodes/over' |
1078 | require 'arel/nodes/matches' |
1079 | require 'arel/nodes/and' |
1080 | require 'arel/nodes/function' |
1081 | require 'arel/nodes/count' |
1082 | require 'arel/nodes/extract' |
1083 | require 'arel/nodes/values' |
1084 | require 'arel/nodes/named_function' |
1085 | require 'arel/nodes/window' |
1086 | require 'arel/nodes/full_outer_join' |
1087 | require 'arel/nodes/inner_join' |
1088 | require 'arel/nodes/outer_join' |
1089 | require 'arel/nodes/right_outer_join' |
1090 | require 'arel/nodes/string_join' |
1091 | require 'arel/nodes/sql_literal' |
1092 | module Arel |
1093 | module Nodes |
1094 | class Casted Arel::Nodes::Node # :nodoc: |
1095 | attr_reader :val, :attribute |
1096 | def initialize val, attribute |
1097 | @val = val |
1098 | @attribute = attribute |
1099 | super() |
1100 | end |
1101 | def nil?; @val.nil?; end |
1102 | def eql? other |
1103 | self.class == other.class && |
1104 | self.val == other.val && |
1105 | self.attribute == other.attribute |
1106 | end |
1107 | alias :== :eql? |
1108 | end |
1109 | class Quoted Arel::Nodes::Unary # :nodoc: |
1110 | alias :val :value |
1111 | def nil?; val.nil?; end |
1112 | end |
1113 | def self.build_quoted other, attribute = nil |
1114 | case other |
1115 | other |
1116 | else |
1117 | case attribute |
1118 | when Arel::Attributes::Attribute |
1119 | Casted.new other, attribute |
1120 | else |
1121 | Quoted.new other |
1122 | end |
1123 | end |
1124 | end |
1125 | end |
1126 | end |
1127 | module Arel |
1128 | module OrderPredications |
1129 | def asc |
1130 | Nodes::Ascending.new self |
1131 | end |
1132 | def desc |
1133 | Nodes::Descending.new self |
1134 | end |
1135 | end |
1136 | end |
1137 | module Arel |
1138 | module Predications |
1139 | def not_eq other |
1140 | Nodes::NotEqual.new self, quoted_node(other) |
1141 | end |
1142 | def not_eq_any others |
1143 | grouping_any :not_eq, others |
1144 | end |
1145 | def not_eq_all others |
1146 | grouping_all :not_eq, others |
1147 | end |
1148 | def eq other |
1149 | Nodes::Equality.new self, quoted_node(other) |
1150 | end |
1151 | def eq_any others |
1152 | grouping_any :eq, others |
1153 | end |
1154 | def eq_all others |
1155 | grouping_all :eq, quoted_array(others) |
1156 | end |
1157 | def between other |
1158 | if equals_quoted?(other.begin, -Float::INFINITY) |
1159 | if equals_quoted?(other.end, Float::INFINITY) |
1160 | not_in([]) |
1161 | elsif other.exclude_end? |
1162 | lt(other.end) |
1163 | else |
1164 | lteq(other.end) |
1165 | end |
1166 | elsif equals_quoted?(other.end, Float::INFINITY) |
1167 | gteq(other.begin) |
1168 | elsif other.exclude_end? |
1169 | gteq(other.begin).and(lt(other.end)) |
1170 | else |
1171 | left = quoted_node(other.begin) |
1172 | right = quoted_node(other.end) |
1173 | Nodes::Between.new(self, left.and(right)) |
1174 | end |
1175 | end |
1176 | def in other |
1177 | case other |
1178 | when Arel::SelectManager |
1179 | Arel::Nodes::In.new(self, other.ast) |
1180 | when Range |
1181 | if $VERBOSE |
1182 | warn -eowarn |
1183 | eowarn |
1184 | end |
1185 | between(other) |
1186 | when Enumerable |
1187 | Nodes::In.new self, quoted_array(other) |
1188 | else |
1189 | Nodes::In.new self, quoted_node(other) |
1190 | end |
1191 | end |
1192 | def in_any others |
1193 | grouping_any :in, others |
1194 | end |
1195 | def in_all others |
1196 | grouping_all :in, others |
1197 | end |
1198 | def not_between other |
1199 | if equals_quoted?(other.begin, -Float::INFINITY) |
1200 | if equals_quoted?(other.end, Float::INFINITY) |
1201 | self.in([]) |
1202 | elsif other.exclude_end? |
1203 | gteq(other.end) |
1204 | else |
1205 | gt(other.end) |
1206 | end |
1207 | elsif equals_quoted?(other.end, Float::INFINITY) |
1208 | lt(other.begin) |
1209 | else |
1210 | left = lt(other.begin) |
1211 | right = if other.exclude_end? |
1212 | gteq(other.end) |
1213 | else |
1214 | gt(other.end) |
1215 | end |
1216 | left.or(right) |
1217 | end |
1218 | end |
1219 | def not_in other |
1220 | case other |
1221 | when Arel::SelectManager |
1222 | Arel::Nodes::NotIn.new(self, other.ast) |
1223 | when Range |
1224 | if $VERBOSE |
1225 | warn -eowarn |
1226 | eowarn |
1227 | end |
1228 | not_between(other) |
1229 | when Enumerable |
1230 | Nodes::NotIn.new self, quoted_array(other) |
1231 | else |
1232 | Nodes::NotIn.new self, quoted_node(other) |
1233 | end |
1234 | end |
1235 | def not_in_any others |
1236 | grouping_any :not_in, others |
1237 | end |
1238 | def not_in_all others |
1239 | grouping_all :not_in, others |
1240 | end |
1241 | def matches other, escape = nil |
1242 | end |
1243 | def matches_any others, escape = nil |
1244 | grouping_any :matches, others, escape |
1245 | end |
1246 | def matches_all others, escape = nil |
1247 | grouping_all :matches, others, escape |
1248 | end |
1249 | def does_not_match other, escape = nil |
1250 | end |
1251 | def does_not_match_any others, escape = nil |
1252 | grouping_any :does_not_match, others, escape |
1253 | end |
1254 | def does_not_match_all others, escape = nil |
1255 | grouping_all :does_not_match, others, escape |
1256 | end |
1257 | def gteq right |
1258 | end |
1259 | def gteq_any others |
1260 | grouping_any :gteq, others |
1261 | end |
1262 | def gteq_all others |
1263 | grouping_all :gteq, others |
1264 | end |
1265 | def gt right |
1266 | Nodes::GreaterThan.new self, quoted_node(right) |
1267 | end |
1268 | def gt_any others |
1269 | grouping_any :gt, others |
1270 | end |
1271 | def gt_all others |
1272 | grouping_all :gt, others |
1273 | end |
1274 | def lt right |
1275 | Nodes::LessThan.new self, quoted_node(right) |
1276 | end |
1277 | def lt_any others |
1278 | grouping_any :lt, others |
1279 | end |
1280 | def lt_all others |
1281 | grouping_all :lt, others |
1282 | end |
1283 | def lteq right |
1284 | end |
1285 | def lteq_any others |
1286 | grouping_any :lteq, others |
1287 | end |
1288 | def lteq_all others |
1289 | grouping_all :lteq, others |
1290 | end |
1291 | private |
1292 | def grouping_any method_id, others, *extras |
1293 | Nodes::Grouping.new nodes.inject { |memo,node| |
1294 | Nodes::Or.new(memo, node) |
1295 | } |
1296 | end |
1297 | def grouping_all method_id, others, *extras |
1298 | Nodes::Grouping.new Nodes::And.new(nodes) |
1299 | end |
1300 | def quoted_node(other) |
1301 | Nodes.build_quoted(other, self) |
1302 | end |
1303 | def quoted_array(others) |
1304 | others.map { |v| quoted_node(v) } |
1305 | end |
1306 | def equals_quoted?(maybe_quoted, value) |
1307 | if maybe_quoted.is_a?(Nodes::Quoted) |
1308 | maybe_quoted.val == value |
1309 | else |
1310 | maybe_quoted == value |
1311 | end |
1312 | end |
1313 | end |
1314 | end |
1315 | require 'arel/collectors/sql_string' |
1316 | module Arel |
1317 | class SelectManager Arel::TreeManager |
1318 | include Arel::Crud |
1319 | STRING_OR_SYMBOL_CLASS = [Symbol, String] |
1320 | def initialize table = nil |
1321 | super() |
1322 | @ast = Nodes::SelectStatement.new |
1323 | @ctx = @ast.cores.last |
1324 | from table |
1325 | end |
1326 | def initialize_copy other |
1327 | super |
1328 | @ctx = @ast.cores.last |
1329 | end |
1330 | def limit |
1331 | @ast.limit && @ast.limit.expr.expr |
1332 | end |
1333 | alias :taken :limit |
1334 | def constraints |
1335 | @ctx.wheres |
1336 | end |
1337 | def offset |
1338 | @ast.offset && @ast.offset.expr |
1339 | end |
1340 | def skip amount |
1341 | if amount |
1342 | @ast.offset = Nodes::Offset.new(amount) |
1343 | else |
1344 | @ast.offset = nil |
1345 | end |
1346 | self |
1347 | end |
1348 | alias :offset= :skip |
1349 | def exists |
1350 | Arel::Nodes::Exists.new @ast |
1351 | end |
1352 | def as other |
1353 | end |
1354 | def lock locking = Arel.sql('FOR UPDATE') |
1355 | case locking |
1356 | when true |
1357 | locking = Arel.sql('FOR UPDATE') |
1358 | when Arel::Nodes::SqlLiteral |
1359 | when String |
1360 | locking = Arel.sql locking |
1361 | end |
1362 | @ast.lock = Nodes::Lock.new(locking) |
1363 | self |
1364 | end |
1365 | def locked |
1366 | @ast.lock |
1367 | end |
1368 | def on *exprs |
1369 | self |
1370 | end |
1371 | def group *columns |
1372 | columns.each do |column| |
1373 | @ctx.groups.push Nodes::Group.new column |
1374 | end |
1375 | self |
1376 | end |
1377 | def from table |
1378 | case table |
1379 | when Nodes::Join |
1380 | @ctx.source.right table |
1381 | else |
1382 | @ctx.source.left = table |
1383 | end |
1384 | self |
1385 | end |
1386 | def froms |
1387 | @ast.cores.map { |x| x.from }.compact |
1388 | end |
1389 | def join relation, klass = Nodes::InnerJoin |
1390 | return self unless relation |
1391 | case relation |
1392 | when String, Nodes::SqlLiteral |
1393 | raise if relation.empty? |
1394 | klass = Nodes::StringJoin |
1395 | end |
1396 | self |
1397 | end |
1398 | def outer_join relation |
1399 | join(relation, Nodes::OuterJoin) |
1400 | end |
1401 | def having expr |
1402 | @ctx.havings expr |
1403 | self |
1404 | end |
1405 | def window name |
1406 | window = Nodes::NamedWindow.new(name) |
1407 | @ctx.windows.push window |
1408 | window |
1409 | end |
1410 | def project *projections |
1411 | @ctx.projections.concat projections.map { |x| |
1412 | } |
1413 | self |
1414 | end |
1415 | def projections |
1416 | @ctx.projections |
1417 | end |
1418 | def projections= projections |
1419 | @ctx.projections = projections |
1420 | end |
1421 | def distinct(value = true) |
1422 | if value |
1423 | @ctx.set_quantifier = Arel::Nodes::Distinct.new |
1424 | else |
1425 | @ctx.set_quantifier = nil |
1426 | end |
1427 | self |
1428 | end |
1429 | def distinct_on(value) |
1430 | if value |
1431 | else |
1432 | @ctx.set_quantifier = nil |
1433 | end |
1434 | self |
1435 | end |
1436 | def order *expr |
1437 | @ast.orders.concat expr.map { |x| |
1438 | } |
1439 | self |
1440 | end |
1441 | def orders |
1442 | @ast.orders |
1443 | end |
1444 | def where_sql engine = Table.engine |
1445 | return if @ctx.wheres.empty? |
1446 | viz = Visitors::WhereSql.new engine.connection |
1447 | end |
1448 | def union operation, other = nil |
1449 | if other |
1450 | else |
1451 | other = operation |
1452 | node_class = Nodes::Union |
1453 | end |
1454 | node_class.new self.ast, other.ast |
1455 | end |
1456 | def intersect other |
1457 | Nodes::Intersect.new ast, other.ast |
1458 | end |
1459 | def except other |
1460 | Nodes::Except.new ast, other.ast |
1461 | end |
1462 | alias :minus :except |
1463 | def with *subqueries |
1464 | if subqueries.first.is_a? Symbol |
1465 | else |
1466 | node_class = Nodes::With |
1467 | end |
1468 | @ast.with = node_class.new(subqueries.flatten) |
1469 | self |
1470 | end |
1471 | def take limit |
1472 | if limit |
1473 | else |
1474 | @ast.limit = nil |
1475 | @ctx.top = nil |
1476 | end |
1477 | self |
1478 | end |
1479 | alias limit= take |
1480 | def join_sources |
1481 | @ctx.source.right |
1482 | end |
1483 | def source |
1484 | @ctx.source |
1485 | end |
1486 | class Row Struct.new(:data) # :nodoc: |
1487 | def id |
1488 | data['id'] |
1489 | end |
1490 | def method_missing(name, *args) |
1491 | name = name.to_s |
1492 | return data[name] if data.key?(name) |
1493 | super |
1494 | end |
1495 | end |
1496 | private |
1497 | def collapse exprs, existing = nil |
1498 | exprs = exprs.unshift(existing.expr) if existing |
1499 | exprs = exprs.compact.map { |expr| |
1500 | if String === expr |
1501 | Arel.sql(expr) |
1502 | else |
1503 | expr |
1504 | end |
1505 | } |
1506 | if exprs.length == 1 |
1507 | exprs.first |
1508 | else |
1509 | create_and exprs |
1510 | end |
1511 | end |
1512 | end |
1513 | end |
1514 | module Arel |
1515 | class Table |
1516 | include Arel::Crud |
1517 | include Arel::FactoryMethods |
1518 | @engine = nil |
1519 | class self; attr_accessor :engine; end |
1520 | attr_accessor :name, :aliases, :table_alias |
1521 | alias :table_name :name |
1522 | def initialize(name, as: nil, type_caster: nil) |
1523 | @name = name.to_s |
1524 | @columns = nil |
1525 | @aliases = [] |
1526 | @type_caster = type_caster |
1527 | if as.to_s == @name |
1528 | as = nil |
1529 | end |
1530 | @table_alias = as |
1531 | end |
1532 | def alias name = "#{self.name}_2" |
1533 | Nodes::TableAlias.new(self, name).tap do |node| |
1534 | @aliases node |
1535 | end |
1536 | end |
1537 | def from |
1538 | SelectManager.new(self) |
1539 | end |
1540 | def join relation, klass = Nodes::InnerJoin |
1541 | return from unless relation |
1542 | case relation |
1543 | when String, Nodes::SqlLiteral |
1544 | raise if relation.empty? |
1545 | klass = Nodes::StringJoin |
1546 | end |
1547 | from.join(relation, klass) |
1548 | end |
1549 | def outer_join relation |
1550 | join(relation, Nodes::OuterJoin) |
1551 | end |
1552 | def group *columns |
1553 | from.group(*columns) |
1554 | end |
1555 | def order *expr |
1556 | from.order(*expr) |
1557 | end |
1558 | def where condition |
1559 | from.where condition |
1560 | end |
1561 | def project *things |
1562 | from.project(*things) |
1563 | end |
1564 | def take amount |
1565 | from.take amount |
1566 | end |
1567 | def skip amount |
1568 | from.skip amount |
1569 | end |
1570 | def having expr |
1571 | from.having expr |
1572 | end |
1573 | def [] name |
1574 | ::Arel::Attribute.new self, name |
1575 | end |
1576 | def hash |
1577 | @name.hash |
1578 | end |
1579 | def eql? other |
1580 | self.class == other.class && |
1581 | self.name == other.name && |
1582 | self.aliases == other.aliases && |
1583 | self.table_alias == other.table_alias |
1584 | end |
1585 | alias :== :eql? |
1586 | def type_cast_for_database(attribute_name, value) |
1587 | end |
1588 | def able_to_type_cast? |
1589 | !type_caster.nil? |
1590 | end |
1591 | protected |
1592 | attr_reader :type_caster |
1593 | private |
1594 | def attributes_for columns |
1595 | return nil unless columns |
1596 | columns.map do |column| |
1597 | end |
1598 | end |
1599 | end |
1600 | end |
1601 | require 'arel/collectors/sql_string' |
1602 | module Arel |
1603 | class TreeManager |
1604 | include Arel::FactoryMethods |
1605 | attr_reader :ast, :engine |
1606 | attr_accessor :bind_values |
1607 | def initialize |
1608 | @ctx = nil |
1609 | @bind_values = [] |
1610 | end |
1611 | def to_dot |
1612 | collector = Arel::Collectors::PlainString.new |
1613 | collector.value |
1614 | end |
1615 | def to_sql engine = Table.engine |
1616 | collector = Arel::Collectors::SQLString.new |
1617 | collector.value |
1618 | end |
1619 | def initialize_copy other |
1620 | super |
1621 | @ast = @ast.clone |
1622 | end |
1623 | def where expr |
1624 | if Arel::TreeManager === expr |
1625 | expr = expr.ast |
1626 | end |
1627 | @ctx.wheres expr |
1628 | self |
1629 | end |
1630 | end |
1631 | end |
1632 | module Arel |
1633 | class UpdateManager Arel::TreeManager |
1634 | def initialize |
1635 | super |
1636 | @ast = Nodes::UpdateStatement.new |
1637 | @ctx = @ast |
1638 | end |
1639 | def take limit |
1640 | self |
1641 | end |
1642 | def key= key |
1643 | @ast.key = Nodes.build_quoted(key) |
1644 | end |
1645 | def key |
1646 | @ast.key |
1647 | end |
1648 | def order *expr |
1649 | @ast.orders = expr |
1650 | self |
1651 | end |
1652 | def table table |
1653 | @ast.relation = table |
1654 | self |
1655 | end |
1656 | def wheres= exprs |
1657 | @ast.wheres = exprs |
1658 | end |
1659 | def where expr |
1660 | @ast.wheres expr |
1661 | self |
1662 | end |
1663 | def set values |
1664 | if String === values |
1665 | @ast.values = [values] |
1666 | else |
1667 | @ast.values = values.map { |column,value| |
1668 | Nodes::Assignment.new( |
1669 | Nodes::UnqualifiedColumn.new(column), |
1670 | value |
1671 | ) |
1672 | } |
1673 | end |
1674 | self |
1675 | end |
1676 | end |
1677 | end |
1678 | module Arel |
1679 | module Visitors |
1680 | class BindSubstitute |
1681 | def initialize delegate |
1682 | @delegate = delegate |
1683 | end |
1684 | end |
1685 | end |
1686 | end |
1687 | module Arel |
1688 | module Visitors |
1689 | module BindVisitor |
1690 | def initialize target |
1691 | @block = nil |
1692 | super |
1693 | end |
1694 | def accept node, collector, &block |
1695 | @block = block if block_given? |
1696 | super |
1697 | end |
1698 | private |
1699 | def visit_Arel_Nodes_Assignment o, collector |
1700 | if o.right.is_a? Arel::Nodes::BindParam |
1701 | collector = visit o.left, collector |
1702 | collector " = " |
1703 | visit o.right, collector |
1704 | else |
1705 | super |
1706 | end |
1707 | end |
1708 | def visit_Arel_Nodes_BindParam o, collector |
1709 | if @block |
1710 | val = @block.call |
1711 | if String === val |
1712 | collector val |
1713 | end |
1714 | else |
1715 | super |
1716 | end |
1717 | end |
1718 | end |
1719 | end |
1720 | end |
1721 | module Arel |
1722 | module Visitors |
1723 | class DepthFirst Arel::Visitors::Visitor |
1724 | def initialize block = nil |
1725 | @block = block || Proc.new |
1726 | super() |
1727 | end |
1728 | private |
1729 | def visit o |
1730 | super |
1731 | @block.call o |
1732 | end |
1733 | def unary o |
1734 | visit o.expr |
1735 | end |
1736 | alias :visit_Arel_Nodes_Group :unary |
1737 | alias :visit_Arel_Nodes_Grouping :unary |
1738 | alias :visit_Arel_Nodes_Having :unary |
1739 | alias :visit_Arel_Nodes_Limit :unary |
1740 | alias :visit_Arel_Nodes_Not :unary |
1741 | alias :visit_Arel_Nodes_Offset :unary |
1742 | alias :visit_Arel_Nodes_On :unary |
1743 | alias :visit_Arel_Nodes_Ordering :unary |
1744 | alias :visit_Arel_Nodes_Ascending :unary |
1745 | alias :visit_Arel_Nodes_Descending :unary |
1746 | alias :visit_Arel_Nodes_Top :unary |
1747 | alias :visit_Arel_Nodes_UnqualifiedColumn :unary |
1748 | def function o |
1749 | visit o.expressions |
1750 | visit o.alias |
1751 | visit o.distinct |
1752 | end |
1753 | alias :visit_Arel_Nodes_Avg :function |
1754 | alias :visit_Arel_Nodes_Exists :function |
1755 | alias :visit_Arel_Nodes_Max :function |
1756 | alias :visit_Arel_Nodes_Min :function |
1757 | alias :visit_Arel_Nodes_Sum :function |
1758 | def visit_Arel_Nodes_NamedFunction o |
1759 | visit o.name |
1760 | visit o.expressions |
1761 | visit o.distinct |
1762 | visit o.alias |
1763 | end |
1764 | def visit_Arel_Nodes_Count o |
1765 | visit o.expressions |
1766 | visit o.alias |
1767 | visit o.distinct |
1768 | end |
1769 | def nary o |
1770 | o.children.each { |child| visit child} |
1771 | end |
1772 | alias :visit_Arel_Nodes_And :nary |
1773 | def binary o |
1774 | visit o.left |
1775 | visit o.right |
1776 | end |
1777 | alias :visit_Arel_Nodes_As :binary |
1778 | alias :visit_Arel_Nodes_Assignment :binary |
1779 | alias :visit_Arel_Nodes_Between :binary |
1780 | alias :visit_Arel_Nodes_DeleteStatement :binary |
1781 | alias :visit_Arel_Nodes_DoesNotMatch :binary |
1782 | alias :visit_Arel_Nodes_Equality :binary |
1783 | alias :visit_Arel_Nodes_FullOuterJoin :binary |
1784 | alias :visit_Arel_Nodes_GreaterThan :binary |
1785 | alias :visit_Arel_Nodes_In :binary |
1786 | alias :visit_Arel_Nodes_InfixOperation :binary |
1787 | alias :visit_Arel_Nodes_JoinSource :binary |
1788 | alias :visit_Arel_Nodes_InnerJoin :binary |
1789 | alias :visit_Arel_Nodes_LessThan :binary |
1790 | alias :visit_Arel_Nodes_LessThanOrEqual :binary |
1791 | alias :visit_Arel_Nodes_Matches :binary |
1792 | alias :visit_Arel_Nodes_NotEqual :binary |
1793 | alias :visit_Arel_Nodes_NotIn :binary |
1794 | alias :visit_Arel_Nodes_NotRegexp :binary |
1795 | alias :visit_Arel_Nodes_Or :binary |
1796 | alias :visit_Arel_Nodes_OuterJoin :binary |
1797 | alias :visit_Arel_Nodes_Regexp :binary |
1798 | alias :visit_Arel_Nodes_RightOuterJoin :binary |
1799 | alias :visit_Arel_Nodes_TableAlias :binary |
1800 | alias :visit_Arel_Nodes_Values :binary |
1801 | alias :visit_Arel_Nodes_Union :binary |
1802 | def visit_Arel_Nodes_StringJoin o |
1803 | visit o.left |
1804 | end |
1805 | def visit_Arel_Attribute o |
1806 | visit o.relation |
1807 | visit o.name |
1808 | end |
1809 | def visit_Arel_Table o |
1810 | visit o.name |
1811 | end |
1812 | def terminal o |
1813 | end |
1814 | alias :visit_Arel_Nodes_Lock :terminal |
1815 | alias :visit_Arel_Nodes_Node :terminal |
1816 | alias :visit_Arel_Nodes_SqlLiteral :terminal |
1817 | alias :visit_Arel_Nodes_BindParam :terminal |
1818 | alias :visit_Arel_Nodes_Window :terminal |
1819 | alias :visit_Arel_Nodes_True :terminal |
1820 | alias :visit_Arel_Nodes_False :terminal |
1821 | alias :visit_BigDecimal :terminal |
1822 | alias :visit_Bignum :terminal |
1823 | alias :visit_Class :terminal |
1824 | alias :visit_Date :terminal |
1825 | alias :visit_DateTime :terminal |
1826 | alias :visit_FalseClass :terminal |
1827 | alias :visit_Fixnum :terminal |
1828 | alias :visit_Float :terminal |
1829 | alias :visit_NilClass :terminal |
1830 | alias :visit_String :terminal |
1831 | alias :visit_Symbol :terminal |
1832 | alias :visit_Time :terminal |
1833 | alias :visit_TrueClass :terminal |
1834 | def visit_Arel_Nodes_InsertStatement o |
1835 | visit o.relation |
1836 | visit o.columns |
1837 | visit o.values |
1838 | end |
1839 | def visit_Arel_Nodes_SelectCore o |
1840 | visit o.projections |
1841 | visit o.source |
1842 | visit o.wheres |
1843 | visit o.groups |
1844 | visit o.windows |
1845 | visit o.havings |
1846 | end |
1847 | def visit_Arel_Nodes_SelectStatement o |
1848 | visit o.cores |
1849 | visit o.orders |
1850 | visit o.limit |
1851 | visit o.lock |
1852 | visit o.offset |
1853 | end |
1854 | def visit_Arel_Nodes_UpdateStatement o |
1855 | visit o.relation |
1856 | visit o.values |
1857 | visit o.wheres |
1858 | visit o.orders |
1859 | visit o.limit |
1860 | end |
1861 | def visit_Array o |
1862 | o.each { |i| visit i } |
1863 | end |
1864 | alias :visit_Set :visit_Array |
1865 | def visit_Hash o |
1866 | o.each { |k,v| visit(k); visit(v) } |
1867 | end |
1868 | DISPATCH = dispatch_cache |
1869 | def get_dispatch_cache |
1870 | DISPATCH |
1871 | end |
1872 | end |
1873 | end |
1874 | end |
1875 | module Arel |
1876 | module Visitors |
1877 | class Dot Arel::Visitors::Visitor |
1878 | class Node # :nodoc: |
1879 | attr_accessor :name, :id, :fields |
1880 | def initialize name, id, fields = [] |
1881 | @name = name |
1882 | @id = id |
1883 | @fields = fields |
1884 | end |
1885 | end |
1886 | class Edge Struct.new :name, :from, :to # :nodoc: |
1887 | end |
1888 | def initialize |
1889 | super() |
1890 | @nodes = [] |
1891 | @edges = [] |
1892 | @node_stack = [] |
1893 | @edge_stack = [] |
1894 | @seen = {} |
1895 | end |
1896 | def accept object, collector |
1897 | visit object |
1898 | collector to_dot |
1899 | end |
1900 | private |
1901 | def visit_Arel_Nodes_Ordering o |
1902 | visit_edge o, "expr" |
1903 | end |
1904 | def visit_Arel_Nodes_TableAlias o |
1905 | visit_edge o, "name" |
1906 | visit_edge o, "relation" |
1907 | end |
1908 | def visit_Arel_Nodes_Count o |
1909 | visit_edge o, "expressions" |
1910 | visit_edge o, "distinct" |
1911 | end |
1912 | def visit_Arel_Nodes_Values o |
1913 | visit_edge o, "expressions" |
1914 | end |
1915 | def visit_Arel_Nodes_StringJoin o |
1916 | visit_edge o, "left" |
1917 | end |
1918 | def visit_Arel_Nodes_InnerJoin o |
1919 | visit_edge o, "left" |
1920 | visit_edge o, "right" |
1921 | end |
1922 | def visit_Arel_Nodes_DeleteStatement o |
1923 | visit_edge o, "relation" |
1924 | visit_edge o, "wheres" |
1925 | end |
1926 | def unary o |
1927 | visit_edge o, "expr" |
1928 | end |
1929 | alias :visit_Arel_Nodes_Group :unary |
1930 | alias :visit_Arel_Nodes_Grouping :unary |
1931 | alias :visit_Arel_Nodes_Having :unary |
1932 | alias :visit_Arel_Nodes_Limit :unary |
1933 | alias :visit_Arel_Nodes_Not :unary |
1934 | alias :visit_Arel_Nodes_Offset :unary |
1935 | alias :visit_Arel_Nodes_On :unary |
1936 | alias :visit_Arel_Nodes_Top :unary |
1937 | alias :visit_Arel_Nodes_UnqualifiedColumn :unary |
1938 | alias :visit_Arel_Nodes_Preceding :unary |
1939 | alias :visit_Arel_Nodes_Following :unary |
1940 | alias :visit_Arel_Nodes_Rows :unary |
1941 | alias :visit_Arel_Nodes_Range :unary |
1942 | def window o |
1943 | visit_edge o, "partitions" |
1944 | visit_edge o, "orders" |
1945 | visit_edge o, "framing" |
1946 | end |
1947 | alias :visit_Arel_Nodes_Window :window |
1948 | def named_window o |
1949 | visit_edge o, "partitions" |
1950 | visit_edge o, "orders" |
1951 | visit_edge o, "framing" |
1952 | visit_edge o, "name" |
1953 | end |
1954 | alias :visit_Arel_Nodes_NamedWindow :named_window |
1955 | def function o |
1956 | visit_edge o, "expressions" |
1957 | visit_edge o, "distinct" |
1958 | visit_edge o, "alias" |
1959 | end |
1960 | alias :visit_Arel_Nodes_Exists :function |
1961 | alias :visit_Arel_Nodes_Min :function |
1962 | alias :visit_Arel_Nodes_Max :function |
1963 | alias :visit_Arel_Nodes_Avg :function |
1964 | alias :visit_Arel_Nodes_Sum :function |
1965 | def extract o |
1966 | visit_edge o, "expressions" |
1967 | visit_edge o, "alias" |
1968 | end |
1969 | alias :visit_Arel_Nodes_Extract :extract |
1970 | def visit_Arel_Nodes_NamedFunction o |
1971 | visit_edge o, "name" |
1972 | visit_edge o, "expressions" |
1973 | visit_edge o, "distinct" |
1974 | visit_edge o, "alias" |
1975 | end |
1976 | def visit_Arel_Nodes_InsertStatement o |
1977 | visit_edge o, "relation" |
1978 | visit_edge o, "columns" |
1979 | visit_edge o, "values" |
1980 | end |
1981 | def visit_Arel_Nodes_SelectCore o |
1982 | visit_edge o, "source" |
1983 | visit_edge o, "projections" |
1984 | visit_edge o, "wheres" |
1985 | visit_edge o, "windows" |
1986 | end |
1987 | def visit_Arel_Nodes_SelectStatement o |
1988 | visit_edge o, "cores" |
1989 | visit_edge o, "limit" |
1990 | visit_edge o, "orders" |
1991 | visit_edge o, "offset" |
1992 | end |
1993 | def visit_Arel_Nodes_UpdateStatement o |
1994 | visit_edge o, "relation" |
1995 | visit_edge o, "wheres" |
1996 | visit_edge o, "values" |
1997 | end |
1998 | def visit_Arel_Table o |
1999 | visit_edge o, "name" |
2000 | end |
2001 | def visit_Arel_Attribute o |
2002 | visit_edge o, "relation" |
2003 | visit_edge o, "name" |
2004 | end |
2005 | def nary o |
2006 | o.children.each_with_index do |x,i| |
2007 | edge(i) { visit x } |
2008 | end |
2009 | end |
2010 | alias :visit_Arel_Nodes_And :nary |
2011 | def binary o |
2012 | visit_edge o, "left" |
2013 | visit_edge o, "right" |
2014 | end |
2015 | alias :visit_Arel_Nodes_As :binary |
2016 | alias :visit_Arel_Nodes_Assignment :binary |
2017 | alias :visit_Arel_Nodes_Between :binary |
2018 | alias :visit_Arel_Nodes_DoesNotMatch :binary |
2019 | alias :visit_Arel_Nodes_Equality :binary |
2020 | alias :visit_Arel_Nodes_GreaterThan :binary |
2021 | alias :visit_Arel_Nodes_In :binary |
2022 | alias :visit_Arel_Nodes_JoinSource :binary |
2023 | alias :visit_Arel_Nodes_LessThan :binary |
2024 | alias :visit_Arel_Nodes_LessThanOrEqual :binary |
2025 | alias :visit_Arel_Nodes_Matches :binary |
2026 | alias :visit_Arel_Nodes_NotEqual :binary |
2027 | alias :visit_Arel_Nodes_NotIn :binary |
2028 | alias :visit_Arel_Nodes_Or :binary |
2029 | alias :visit_Arel_Nodes_Over :binary |
2030 | def visit_String o |
2031 | @node_stack.last.fields o |
2032 | end |
2033 | alias :visit_Time :visit_String |
2034 | alias :visit_Date :visit_String |
2035 | alias :visit_DateTime :visit_String |
2036 | alias :visit_NilClass :visit_String |
2037 | alias :visit_TrueClass :visit_String |
2038 | alias :visit_FalseClass :visit_String |
2039 | alias :visit_Arel_Nodes_BindParam :visit_String |
2040 | alias :visit_Fixnum :visit_String |
2041 | alias :visit_BigDecimal :visit_String |
2042 | alias :visit_Float :visit_String |
2043 | alias :visit_Symbol :visit_String |
2044 | alias :visit_Arel_Nodes_SqlLiteral :visit_String |
2045 | def visit_Hash o |
2046 | o.each_with_index do |pair, i| |
2047 | edge("pair_#{i}") { visit pair } |
2048 | end |
2049 | end |
2050 | def visit_Array o |
2051 | o.each_with_index do |x,i| |
2052 | edge(i) { visit x } |
2053 | end |
2054 | end |
2055 | alias :visit_Set :visit_Array |
2056 | def visit_edge o, method |
2057 | edge(method) { visit o.send(method) } |
2058 | end |
2059 | def visit o |
2060 | if node = @seen[o.object_id] |
2061 | @edge_stack.last.to = node |
2062 | return |
2063 | end |
2064 | node = Node.new(o.class.name, o.object_id) |
2065 | @seen[node.id] = node |
2066 | @nodes node |
2067 | with_node node do |
2068 | super |
2069 | end |
2070 | end |
2071 | def edge name |
2072 | edge = Edge.new(name, @node_stack.last) |
2073 | @edge_stack.push edge |
2074 | @edges edge |
2075 | yield |
2076 | @edge_stack.pop |
2077 | end |
2078 | def with_node node |
2079 | if edge = @edge_stack.last |
2080 | edge.to = node |
2081 | end |
2082 | @node_stack.push node |
2083 | yield |
2084 | @node_stack.pop |
2085 | end |
2086 | def quote string |
2087 | string.to_s.gsub('"', '\"') |
2088 | end |
2089 | def to_dot |
2090 | @nodes.map { |node| |
2091 | label = "f0#{node.name}" |
2092 | node.fields.each_with_index do |field, i| |
2093 | label "|f#{i + 1}#{quote field}" |
2094 | end |
2095 | "#{node.id} [label=\"#{label}\"];" |
2096 | }.join(" ") + " " + @edges.map { |edge| |
2097 | }.join(" ") + " }" |
2098 | end |
2099 | end |
2100 | end |
2101 | end |
2102 | module Arel |
2103 | module Visitors |
2104 | class IBM_DB Arel::Visitors::ToSql |
2105 | private |
2106 | def visit_Arel_Nodes_Limit o, collector |
2107 | collector "FETCH FIRST " |
2108 | collector = visit o.expr, collector |
2109 | collector " ROWS ONLY" |
2110 | end |
2111 | end |
2112 | end |
2113 | end |
2114 | module Arel |
2115 | module Visitors |
2116 | class Informix Arel::Visitors::ToSql |
2117 | private |
2118 | def visit_Arel_Nodes_SelectStatement o, collector |
2119 | collector "SELECT " |
2120 | collector = maybe_visit o.offset, collector |
2121 | collector = maybe_visit o.limit, collector |
2122 | collector = o.cores.inject(collector) { |c,x| |
2123 | visit_Arel_Nodes_SelectCore x, c |
2124 | } |
2125 | if o.orders.any? |
2126 | collector "ORDER BY " |
2127 | collector = inject_join o.orders, collector, ", " |
2128 | end |
2129 | collector = maybe_visit o.lock, collector |
2130 | end |
2131 | def visit_Arel_Nodes_SelectCore o, collector |
2132 | froms = false |
2133 | if o.source && !o.source.empty? |
2134 | froms = true |
2135 | collector " FROM " |
2136 | collector = visit o.source, collector |
2137 | end |
2138 | if o.wheres.any? |
2139 | collector " WHERE " |
2140 | end |
2141 | if o.groups.any? |
2142 | collector "GROUP BY " |
2143 | collector = inject_join o.groups, collector, ", " |
2144 | end |
2145 | if o.havings.any? |
2146 | collector " HAVING " |
2147 | end |
2148 | collector |
2149 | end |
2150 | def visit_Arel_Nodes_Offset o, collector |
2151 | collector "SKIP " |
2152 | visit o.expr, collector |
2153 | end |
2154 | def visit_Arel_Nodes_Limit o, collector |
2155 | collector "FIRST " |
2156 | visit o.expr, collector |
2157 | collector " " |
2158 | end |
2159 | end |
2160 | end |
2161 | end |
2162 | module Arel |
2163 | module Visitors |
2164 | class MSSQL Arel::Visitors::ToSql |
2165 | RowNumber = Struct.new :children |
2166 | def initialize(*) |
2167 | @primary_keys = {} |
2168 | super |
2169 | end |
2170 | private |
2171 | def visit_Arel_Nodes_Top o |
2172 | "" |
2173 | end |
2174 | collector "ROW_NUMBER() OVER (ORDER BY " |
2175 | end |
2176 | def visit_Arel_Nodes_SelectStatement o, collector |
2177 | if !o.limit && !o.offset |
2178 | return super |
2179 | end |
2180 | is_select_count = false |
2181 | o.cores.each { |x| |
2182 | if select_count? x |
2183 | x.projections = [core_order_by] |
2184 | is_select_count = true |
2185 | else |
2186 | x.projections core_order_by |
2187 | end |
2188 | } |
2189 | if is_select_count |
2190 | collector "SELECT COUNT(1) as count_id FROM (" |
2191 | end |
2192 | collector "SELECT _t.* FROM (" |
2193 | collector = o.cores.inject(collector) { |c,x| |
2194 | visit_Arel_Nodes_SelectCore x, c |
2195 | } |
2196 | if is_select_count |
2197 | collector ") AS subquery" |
2198 | else |
2199 | collector |
2200 | end |
2201 | end |
2202 | def get_offset_limit_clause o |
2203 | first_row = o.offset ? o.offset.expr.to_i + 1 : 1 |
2204 | if last_row |
2205 | " _row_num BETWEEN #{first_row} AND #{last_row}" |
2206 | else |
2207 | " _row_num = #{first_row}" |
2208 | end |
2209 | end |
2210 | def determine_order_by orders, x |
2211 | if orders.any? |
2212 | orders |
2213 | elsif x.groups.any? |
2214 | x.groups |
2215 | else |
2216 | pk = find_left_table_pk(x.froms) |
2217 | pk ? [pk] : [] |
2218 | end |
2219 | end |
2220 | def row_num_literal order_by |
2221 | RowNumber.new order_by |
2222 | end |
2223 | def select_count? x |
2224 | end |
2225 | def find_left_table_pk o |
2226 | if o.kind_of?(Arel::Nodes::Join) |
2227 | find_left_table_pk(o.left) |
2228 | elsif o.instance_of?(Arel::Table) |
2229 | find_primary_key(o) |
2230 | end |
2231 | end |
2232 | def find_primary_key(o) |
2233 | @primary_keys[o.name] ||= begin |
2234 | primary_key_name && o[primary_key_name] |
2235 | end |
2236 | end |
2237 | end |
2238 | end |
2239 | end |
2240 | module Arel |
2241 | module Visitors |
2242 | class MySQL Arel::Visitors::ToSql |
2243 | private |
2244 | unless suppress_parens |
2245 | collector "( " |
2246 | end |
2247 | collector = case o.left |
2248 | when Arel::Nodes::Union |
2249 | visit_Arel_Nodes_Union o.left, collector, true |
2250 | else |
2251 | visit o.left, collector |
2252 | end |
2253 | collector " UNION " |
2254 | collector = case o.right |
2255 | when Arel::Nodes::Union |
2256 | visit_Arel_Nodes_Union o.right, collector, true |
2257 | else |
2258 | visit o.right, collector |
2259 | end |
2260 | if suppress_parens |
2261 | collector |
2262 | else |
2263 | collector " )" |
2264 | end |
2265 | end |
2266 | def visit_Arel_Nodes_Bin o, collector |
2267 | collector "BINARY " |
2268 | visit o.expr, collector |
2269 | end |
2270 | def visit_Arel_Nodes_SelectStatement o, collector |
2271 | if o.offset && !o.limit |
2272 | end |
2273 | super |
2274 | end |
2275 | def visit_Arel_Nodes_SelectCore o, collector |
2276 | o.froms ||= Arel.sql('DUAL') |
2277 | super |
2278 | end |
2279 | def visit_Arel_Nodes_UpdateStatement o, collector |
2280 | collector "UPDATE " |
2281 | collector = visit o.relation, collector |
2282 | unless o.values.empty? |
2283 | collector " SET " |
2284 | collector = inject_join o.values, collector, ', ' |
2285 | end |
2286 | unless o.wheres.empty? |
2287 | collector " WHERE " |
2288 | end |
2289 | unless o.orders.empty? |
2290 | collector " ORDER BY " |
2291 | collector = inject_join o.orders, collector, ', ' |
2292 | end |
2293 | maybe_visit o.limit, collector |
2294 | end |
2295 | end |
2296 | end |
2297 | end |
2298 | module Arel |
2299 | module Visitors |
2300 | class Oracle Arel::Visitors::ToSql |
2301 | private |
2302 | def visit_Arel_Nodes_SelectStatement o, collector |
2303 | o = order_hacks(o) |
2304 | Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr |
2305 | ) |
2306 | return super |
2307 | end |
2308 | if o.limit && o.offset |
2309 | o = o.dup |
2310 | limit = o.limit.expr.expr |
2311 | offset = o.offset |
2312 | o.offset = nil |
2313 | collector " |
2314 | SELECT * FROM ( |
2315 | SELECT raw_sql_.*, rownum raw_rnum_ |
2316 | FROM (" |
2317 | collector = super(o, collector) |
2318 | collector ") raw_sql_ |
2319 | WHERE rownum = #{offset.expr.to_i + limit} |
2320 | ) |
2321 | WHERE " |
2322 | return visit(offset, collector) |
2323 | end |
2324 | if o.limit |
2325 | o = o.dup |
2326 | limit = o.limit.expr |
2327 | collector "SELECT * FROM (" |
2328 | collector = super(o, collector) |
2329 | collector ") WHERE ROWNUM = " |
2330 | return visit limit, collector |
2331 | end |
2332 | if o.offset |
2333 | o = o.dup |
2334 | offset = o.offset |
2335 | o.offset = nil |
2336 | collector "SELECT * FROM ( |
2337 | SELECT raw_sql_.*, rownum raw_rnum_ |
2338 | FROM (" |
2339 | collector = super(o, collector) |
2340 | collector ") raw_sql_ |
2341 | ) |
2342 | WHERE " |
2343 | return visit offset, collector |
2344 | end |
2345 | super |
2346 | end |
2347 | def visit_Arel_Nodes_Limit o, collector |
2348 | collector |
2349 | end |
2350 | def visit_Arel_Nodes_Offset o, collector |
2351 | collector "raw_rnum_ " |
2352 | visit o.expr, collector |
2353 | end |
2354 | def visit_Arel_Nodes_Except o, collector |
2355 | collector "( " |
2356 | collector = infix_value o, collector, " MINUS " |
2357 | collector " )" |
2358 | end |
2359 | def visit_Arel_Nodes_UpdateStatement o, collector |
2360 | if o.orders.any? && o.limit.nil? |
2361 | o = o.dup |
2362 | o.orders = [] |
2363 | end |
2364 | super |
2365 | end |
2366 | def order_hacks o |
2367 | return o if o.orders.empty? |
2368 | return o unless o.cores.any? do |core| |
2369 | core.projections.any? do |projection| |
2370 | /FIRST_VALUE/ === projection |
2371 | end |
2372 | end |
2373 | orders = o.orders.map do |x| |
2374 | if string.include?(',') |
2375 | split_order_string(string) |
2376 | else |
2377 | string |
2378 | end |
2379 | end.flatten |
2380 | o.orders = [] |
2381 | orders.each_with_index do |order, i| |
2382 | o.orders |
2383 | end |
2384 | o |
2385 | end |
2386 | def split_order_string(string) |
2387 | array = [] |
2388 | i = 0 |
2389 | string.split(',').each do |part| |
2390 | if array[i] |
2391 | array[i] ',' part |
2392 | else |
2393 | array[i] = '' part |
2394 | end |
2395 | end |
2396 | array |
2397 | end |
2398 | def visit_Arel_Nodes_BindParam o, collector |
2399 | collector.add_bind(o) { |i| ":a#{i}" } |
2400 | end |
2401 | end |
2402 | end |
2403 | end |
2404 | module Arel |
2405 | module Visitors |
2406 | class PostgreSQL Arel::Visitors::ToSql |
2407 | private |
2408 | def visit_Arel_Nodes_Matches o, collector |
2409 | collector = infix_value o, collector, ' ILIKE ' |
2410 | if o.escape |
2411 | collector ' ESCAPE ' |
2412 | visit o.escape, collector |
2413 | else |
2414 | collector |
2415 | end |
2416 | end |
2417 | def visit_Arel_Nodes_DoesNotMatch o, collector |
2418 | if o.escape |
2419 | collector ' ESCAPE ' |
2420 | visit o.escape, collector |
2421 | else |
2422 | collector |
2423 | end |
2424 | end |
2425 | def visit_Arel_Nodes_Regexp o, collector |
2426 | infix_value o, collector, ' ~ ' |
2427 | end |
2428 | def visit_Arel_Nodes_NotRegexp o, collector |
2429 | infix_value o, collector, ' !~ ' |
2430 | end |
2431 | def visit_Arel_Nodes_DistinctOn o, collector |
2432 | collector "DISTINCT ON ( " |
2433 | visit(o.expr, collector) " )" |
2434 | end |
2435 | def visit_Arel_Nodes_BindParam o, collector |
2436 | collector.add_bind(o) { |i| "$#{i}" } |
2437 | end |
2438 | end |
2439 | end |
2440 | end |
2441 | require 'arel/visitors/visitor' |
2442 | module Arel |
2443 | module Visitors |
2444 | class Reduce Arel::Visitors::Visitor |
2445 | def accept object, collector |
2446 | visit object, collector |
2447 | end |
2448 | private |
2449 | def visit object, collector |
2450 | send dispatch[object.class], object, collector |
2451 | rescue NoMethodError = e |
2452 | respond_to?(dispatch[klass], true) |
2453 | } |
2454 | dispatch[object.class] = dispatch[superklass] |
2455 | retry |
2456 | end |
2457 | end |
2458 | end |
2459 | end |
2460 | module Arel |
2461 | module Visitors |
2462 | class SQLite Arel::Visitors::ToSql |
2463 | private |
2464 | def visit_Arel_Nodes_Lock o, collector |
2465 | collector |
2466 | end |
2467 | def visit_Arel_Nodes_SelectStatement o, collector |
2468 | super |
2469 | end |
2470 | end |
2471 | end |
2472 | end |
2473 | require 'bigdecimal' |
2474 | require 'date' |
2475 | require 'arel/visitors/reduce' |
2476 | module Arel |
2477 | module Visitors |
2478 | class ToSql Arel::Visitors::Reduce |
2479 | WHERE = ' WHERE ' # :nodoc: |
2480 | SPACE = ' ' # :nodoc: |
2481 | COMMA = ', ' # :nodoc: |
2482 | GROUP_BY = ' GROUP BY ' # :nodoc: |
2483 | ORDER_BY = ' ORDER BY ' # :nodoc: |
2484 | WINDOW = ' WINDOW ' # :nodoc: |
2485 | AND = ' AND ' # :nodoc: |
2486 | DISTINCT = 'DISTINCT' # :nodoc: |
2487 | def initialize connection |
2488 | super() |
2489 | @connection = connection |
2490 | end |
2491 | def compile node, &block |
2492 | end |
2493 | private |
2494 | def schema_cache |
2495 | @connection.schema_cache |
2496 | end |
2497 | def visit_Arel_Nodes_DeleteStatement o, collector |
2498 | collector "DELETE FROM " |
2499 | collector = visit o.relation, collector |
2500 | if o.wheres.any? |
2501 | collector " WHERE " |
2502 | inject_join o.wheres, collector, AND |
2503 | else |
2504 | collector |
2505 | end |
2506 | end |
2507 | def build_subselect key, o |
2508 | stmt = Nodes::SelectStatement.new |
2509 | core = stmt.cores.first |
2510 | core.froms = o.relation |
2511 | core.wheres = o.wheres |
2512 | core.projections = [key] |
2513 | stmt.limit = o.limit |
2514 | stmt.orders = o.orders |
2515 | stmt |
2516 | end |
2517 | def visit_Arel_Nodes_UpdateStatement o, collector |
2518 | if o.orders.empty? && o.limit.nil? |
2519 | wheres = o.wheres |
2520 | else |
2521 | end |
2522 | collector "UPDATE " |
2523 | collector = visit o.relation, collector |
2524 | unless o.values.empty? |
2525 | collector " SET " |
2526 | collector = inject_join o.values, collector, ", " |
2527 | end |
2528 | unless wheres.empty? |
2529 | collector " WHERE " |
2530 | end |
2531 | collector |
2532 | end |
2533 | def visit_Arel_Nodes_InsertStatement o, collector |
2534 | collector "INSERT INTO " |
2535 | collector = visit o.relation, collector |
2536 | if o.columns.any? |
2537 | collector " (#{o.columns.map { |x| |
2538 | quote_column_name x.name |
2539 | }.join ', '})" |
2540 | end |
2541 | if o.values |
2542 | maybe_visit o.values, collector |
2543 | elsif o.select |
2544 | maybe_visit o.select, collector |
2545 | else |
2546 | collector |
2547 | end |
2548 | end |
2549 | def visit_Arel_Nodes_Exists o, collector |
2550 | collector "EXISTS (" |
2551 | collector = visit(o.expressions, collector) ")" |
2552 | if o.alias |
2553 | collector " AS " |
2554 | visit o.alias, collector |
2555 | else |
2556 | collector |
2557 | end |
2558 | end |
2559 | def visit_Arel_Nodes_Casted o, collector |
2560 | collector quoted(o.val, o.attribute).to_s |
2561 | end |
2562 | def visit_Arel_Nodes_Quoted o, collector |
2563 | collector quoted(o.expr, nil).to_s |
2564 | end |
2565 | def visit_Arel_Nodes_True o, collector |
2566 | collector "TRUE" |
2567 | end |
2568 | def visit_Arel_Nodes_False o, collector |
2569 | collector "FALSE" |
2570 | end |
2571 | def table_exists? name |
2572 | schema_cache.table_exists? name |
2573 | end |
2574 | def column_for attr |
2575 | return unless attr |
2576 | name = attr.name.to_s |
2577 | table = attr.relation.table_name |
2578 | return nil unless table_exists? table |
2579 | column_cache(table)[name] |
2580 | end |
2581 | def column_cache(table) |
2582 | schema_cache.columns_hash(table) |
2583 | end |
2584 | def visit_Arel_Nodes_Values o, collector |
2585 | collector "VALUES (" |
2586 | len = o.expressions.length - 1 |
2587 | case value |
2588 | when Nodes::SqlLiteral, Nodes::BindParam |
2589 | collector = visit value, collector |
2590 | else |
2591 | end |
2592 | unless i == len |
2593 | collector ', ' |
2594 | end |
2595 | } |
2596 | collector ")" |
2597 | end |
2598 | def visit_Arel_Nodes_SelectStatement o, collector |
2599 | if o.with |
2600 | collector = visit o.with, collector |
2601 | collector SPACE |
2602 | end |
2603 | collector = o.cores.inject(collector) { |c,x| |
2604 | visit_Arel_Nodes_SelectCore(x, c) |
2605 | } |
2606 | unless o.orders.empty? |
2607 | collector ORDER_BY |
2608 | len = o.orders.length - 1 |
2609 | o.orders.each_with_index { |x, i| |
2610 | collector = visit(x, collector) |
2611 | collector COMMA unless len == i |
2612 | } |
2613 | end |
2614 | collector = maybe_visit o.limit, collector |
2615 | collector = maybe_visit o.offset, collector |
2616 | collector = maybe_visit o.lock, collector |
2617 | collector |
2618 | end |
2619 | def visit_Arel_Nodes_SelectCore o, collector |
2620 | collector "SELECT" |
2621 | collector = maybe_visit o.top, collector |
2622 | unless o.projections.empty? |
2623 | collector SPACE |
2624 | len = o.projections.length - 1 |
2625 | o.projections.each_with_index do |x, i| |
2626 | collector = visit(x, collector) |
2627 | collector COMMA unless len == i |
2628 | end |
2629 | end |
2630 | if o.source && !o.source.empty? |
2631 | collector " FROM " |
2632 | collector = visit o.source, collector |
2633 | end |
2634 | unless o.wheres.empty? |
2635 | collector WHERE |
2636 | len = o.wheres.length - 1 |
2637 | o.wheres.each_with_index do |x, i| |
2638 | collector = visit(x, collector) |
2639 | collector AND unless len == i |
2640 | end |
2641 | end |
2642 | unless o.groups.empty? |
2643 | collector GROUP_BY |
2644 | len = o.groups.length - 1 |
2645 | o.groups.each_with_index do |x, i| |
2646 | collector = visit(x, collector) |
2647 | collector COMMA unless len == i |
2648 | end |
2649 | end |
2650 | unless o.havings.empty? |
2651 | collector " HAVING " |
2652 | inject_join o.havings, collector, AND |
2653 | end |
2654 | unless o.windows.empty? |
2655 | collector WINDOW |
2656 | len = o.windows.length - 1 |
2657 | o.windows.each_with_index do |x, i| |
2658 | collector = visit(x, collector) |
2659 | collector COMMA unless len == i |
2660 | end |
2661 | end |
2662 | collector |
2663 | end |
2664 | def visit_Arel_Nodes_Bin o, collector |
2665 | visit o.expr, collector |
2666 | end |
2667 | def visit_Arel_Nodes_Distinct o, collector |
2668 | collector DISTINCT |
2669 | end |
2670 | def visit_Arel_Nodes_DistinctOn o, collector |
2671 | end |
2672 | def visit_Arel_Nodes_With o, collector |
2673 | collector "WITH " |
2674 | inject_join o.children, collector, ', ' |
2675 | end |
2676 | def visit_Arel_Nodes_WithRecursive o, collector |
2677 | collector "WITH RECURSIVE " |
2678 | inject_join o.children, collector, ', ' |
2679 | end |
2680 | def visit_Arel_Nodes_Union o, collector |
2681 | collector "( " |
2682 | infix_value(o, collector, " UNION ") " )" |
2683 | end |
2684 | def visit_Arel_Nodes_UnionAll o, collector |
2685 | collector "( " |
2686 | infix_value(o, collector, " UNION ALL ") " )" |
2687 | end |
2688 | def visit_Arel_Nodes_Intersect o, collector |
2689 | collector "( " |
2690 | infix_value(o, collector, " INTERSECT ") " )" |
2691 | end |
2692 | def visit_Arel_Nodes_Except o, collector |
2693 | collector "( " |
2694 | infix_value(o, collector, " EXCEPT ") " )" |
2695 | end |
2696 | def visit_Arel_Nodes_NamedWindow o, collector |
2697 | collector quote_column_name(o.name) |
2698 | collector " AS " |
2699 | visit_Arel_Nodes_Window o, collector |
2700 | end |
2701 | def visit_Arel_Nodes_Window o, collector |
2702 | collector "(" |
2703 | if o.partitions.any? |
2704 | collector "PARTITION BY " |
2705 | end |
2706 | if o.orders.any? |
2707 | collector ' ' if o.partitions.any? |
2708 | collector "ORDER BY " |
2709 | collector = inject_join o.orders, collector, ", " |
2710 | end |
2711 | if o.framing |
2712 | collector = visit o.framing, collector |
2713 | end |
2714 | collector ")" |
2715 | end |
2716 | def visit_Arel_Nodes_Rows o, collector |
2717 | if o.expr |
2718 | collector "ROWS " |
2719 | visit o.expr, collector |
2720 | else |
2721 | collector "ROWS" |
2722 | end |
2723 | end |
2724 | def visit_Arel_Nodes_Range o, collector |
2725 | if o.expr |
2726 | collector "RANGE " |
2727 | visit o.expr, collector |
2728 | else |
2729 | collector "RANGE" |
2730 | end |
2731 | end |
2732 | def visit_Arel_Nodes_Preceding o, collector |
2733 | collector = if o.expr |
2734 | visit o.expr, collector |
2735 | else |
2736 | collector "UNBOUNDED" |
2737 | end |
2738 | collector " PRECEDING" |
2739 | end |
2740 | def visit_Arel_Nodes_Following o, collector |
2741 | collector = if o.expr |
2742 | visit o.expr, collector |
2743 | else |
2744 | collector "UNBOUNDED" |
2745 | end |
2746 | collector " FOLLOWING" |
2747 | end |
2748 | def visit_Arel_Nodes_CurrentRow o, collector |
2749 | collector "CURRENT ROW" |
2750 | end |
2751 | def visit_Arel_Nodes_Over o, collector |
2752 | case o.right |
2753 | when nil |
2754 | visit(o.left, collector) " OVER ()" |
2755 | when Arel::Nodes::SqlLiteral |
2756 | infix_value o, collector, " OVER " |
2757 | when String, Symbol |
2758 | else |
2759 | infix_value o, collector, " OVER " |
2760 | end |
2761 | end |
2762 | def visit_Arel_Nodes_Offset o, collector |
2763 | collector "OFFSET " |
2764 | visit o.expr, collector |
2765 | end |
2766 | def visit_Arel_Nodes_Limit o, collector |
2767 | collector "LIMIT " |
2768 | visit o.expr, collector |
2769 | end |
2770 | def visit_Arel_Nodes_Top o, collector |
2771 | collector |
2772 | end |
2773 | def visit_Arel_Nodes_Lock o, collector |
2774 | visit o.expr, collector |
2775 | end |
2776 | def visit_Arel_Nodes_Grouping o, collector |
2777 | if o.expr.is_a? Nodes::Grouping |
2778 | visit(o.expr, collector) |
2779 | else |
2780 | collector "(" |
2781 | visit(o.expr, collector) ")" |
2782 | end |
2783 | end |
2784 | def visit_Arel_SelectManager o, collector |
2785 | collector "(#{o.to_sql.rstrip})" |
2786 | end |
2787 | def visit_Arel_Nodes_Ascending o, collector |
2788 | visit(o.expr, collector) " ASC" |
2789 | end |
2790 | def visit_Arel_Nodes_Descending o, collector |
2791 | visit(o.expr, collector) " DESC" |
2792 | end |
2793 | def visit_Arel_Nodes_Group o, collector |
2794 | visit o.expr, collector |
2795 | end |
2796 | def visit_Arel_Nodes_NamedFunction o, collector |
2797 | collector o.name |
2798 | collector "(" |
2799 | collector "DISTINCT " if o.distinct |
2800 | if o.alias |
2801 | collector " AS " |
2802 | visit o.alias, collector |
2803 | else |
2804 | collector |
2805 | end |
2806 | end |
2807 | def visit_Arel_Nodes_Extract o, collector |
2808 | collector "EXTRACT(#{o.field.to_s.upcase} FROM " |
2809 | visit(o.expr, collector) ")" |
2810 | end |
2811 | def visit_Arel_Nodes_Count o, collector |
2812 | aggregate "COUNT", o, collector |
2813 | end |
2814 | def visit_Arel_Nodes_Sum o, collector |
2815 | aggregate "SUM", o, collector |
2816 | end |
2817 | def visit_Arel_Nodes_Max o, collector |
2818 | aggregate "MAX", o, collector |
2819 | end |
2820 | def visit_Arel_Nodes_Min o, collector |
2821 | aggregate "MIN", o, collector |
2822 | end |
2823 | def visit_Arel_Nodes_Avg o, collector |
2824 | aggregate "AVG", o, collector |
2825 | end |
2826 | def visit_Arel_Nodes_TableAlias o, collector |
2827 | collector = visit o.relation, collector |
2828 | collector " " |
2829 | collector quote_table_name(o.name) |
2830 | end |
2831 | def visit_Arel_Nodes_Between o, collector |
2832 | collector = visit o.left, collector |
2833 | collector " BETWEEN " |
2834 | visit o.right, collector |
2835 | end |
2836 | collector = visit o.left, collector |
2837 | collector " = " |
2838 | visit o.right, collector |
2839 | end |
2840 | def visit_Arel_Nodes_GreaterThan o, collector |
2841 | collector = visit o.left, collector |
2842 | collector " " |
2843 | visit o.right, collector |
2844 | end |
2845 | def visit_Arel_Nodes_LessThanOrEqual o, collector |
2846 | collector = visit o.left, collector |
2847 | collector " = " |
2848 | visit o.right, collector |
2849 | end |
2850 | def visit_Arel_Nodes_LessThan o, collector |
2851 | collector = visit o.left, collector |
2852 | collector " " |
2853 | visit o.right, collector |
2854 | end |
2855 | def visit_Arel_Nodes_Matches o, collector |
2856 | collector = visit o.left, collector |
2857 | collector " LIKE " |
2858 | collector = visit o.right, collector |
2859 | if o.escape |
2860 | collector ' ESCAPE ' |
2861 | visit o.escape, collector |
2862 | else |
2863 | collector |
2864 | end |
2865 | end |
2866 | def visit_Arel_Nodes_DoesNotMatch o, collector |
2867 | collector = visit o.left, collector |
2868 | collector " NOT LIKE " |
2869 | collector = visit o.right, collector |
2870 | if o.escape |
2871 | collector ' ESCAPE ' |
2872 | visit o.escape, collector |
2873 | else |
2874 | collector |
2875 | end |
2876 | end |
2877 | def visit_Arel_Nodes_JoinSource o, collector |
2878 | if o.left |
2879 | collector = visit o.left, collector |
2880 | end |
2881 | if o.right.any? |
2882 | collector " " if o.left |
2883 | collector = inject_join o.right, collector, ' ' |
2884 | end |
2885 | collector |
2886 | end |
2887 | def visit_Arel_Nodes_Regexp o, collector |
2888 | end |
2889 | def visit_Arel_Nodes_NotRegexp o, collector |
2890 | end |
2891 | def visit_Arel_Nodes_StringJoin o, collector |
2892 | visit o.left, collector |
2893 | end |
2894 | def visit_Arel_Nodes_FullOuterJoin o |
2895 | end |
2896 | def visit_Arel_Nodes_OuterJoin o, collector |
2897 | collector "LEFT OUTER JOIN " |
2898 | collector = visit o.left, collector |
2899 | collector " " |
2900 | visit o.right, collector |
2901 | end |
2902 | def visit_Arel_Nodes_RightOuterJoin o |
2903 | end |
2904 | def visit_Arel_Nodes_InnerJoin o, collector |
2905 | collector "INNER JOIN " |
2906 | collector = visit o.left, collector |
2907 | if o.right |
2908 | collector SPACE |
2909 | visit(o.right, collector) |
2910 | else |
2911 | collector |
2912 | end |
2913 | end |
2914 | def visit_Arel_Nodes_On o, collector |
2915 | collector "ON " |
2916 | visit o.expr, collector |
2917 | end |
2918 | def visit_Arel_Nodes_Not o, collector |
2919 | collector "NOT (" |
2920 | visit(o.expr, collector) ")" |
2921 | end |
2922 | def visit_Arel_Table o, collector |
2923 | if o.table_alias |
2924 | else |
2925 | collector quote_table_name(o.name) |
2926 | end |
2927 | end |
2928 | def visit_Arel_Nodes_In o, collector |
2929 | if Array === o.right && o.right.empty? |
2930 | collector '1=0' |
2931 | else |
2932 | collector = visit o.left, collector |
2933 | collector " IN (" |
2934 | visit(o.right, collector) ")" |
2935 | end |
2936 | end |
2937 | def visit_Arel_Nodes_NotIn o, collector |
2938 | if Array === o.right && o.right.empty? |
2939 | collector '1=1' |
2940 | else |
2941 | collector = visit o.left, collector |
2942 | collector " NOT IN (" |
2943 | collector = visit o.right, collector |
2944 | collector ")" |
2945 | end |
2946 | end |
2947 | def visit_Arel_Nodes_And o, collector |
2948 | inject_join o.children, collector, " AND " |
2949 | end |
2950 | def visit_Arel_Nodes_Or o, collector |
2951 | collector = visit o.left, collector |
2952 | collector " OR " |
2953 | visit o.right, collector |
2954 | end |
2955 | def visit_Arel_Nodes_Assignment o, collector |
2956 | case o.right |
2957 | collector = visit o.left, collector |
2958 | collector " = " |
2959 | visit o.right, collector |
2960 | else |
2961 | collector = visit o.left, collector |
2962 | collector " = " |
2963 | collector quote(o.right, column_for(o.left)).to_s |
2964 | end |
2965 | end |
2966 | def visit_Arel_Nodes_Equality o, collector |
2967 | right = o.right |
2968 | collector = visit o.left, collector |
2969 | if right.nil? |
2970 | collector " IS NULL" |
2971 | else |
2972 | collector " = " |
2973 | visit right, collector |
2974 | end |
2975 | end |
2976 | def visit_Arel_Nodes_NotEqual o, collector |
2977 | right = o.right |
2978 | collector = visit o.left, collector |
2979 | if right.nil? |
2980 | collector " IS NOT NULL" |
2981 | else |
2982 | collector " != " |
2983 | visit right, collector |
2984 | end |
2985 | end |
2986 | def visit_Arel_Nodes_As o, collector |
2987 | collector = visit o.left, collector |
2988 | collector " AS " |
2989 | visit o.right, collector |
2990 | end |
2991 | collector "#{quote_column_name o.name}" |
2992 | collector |
2993 | end |
2994 | def visit_Arel_Attributes_Attribute o, collector |
2995 | end |
2996 | def literal o, collector; collector o.to_s; end |
2997 | def visit_Arel_Nodes_BindParam o, collector |
2998 | collector.add_bind(o) { "?" } |
2999 | end |
3000 | alias :visit_Arel_Nodes_SqlLiteral :literal |
3001 | alias :visit_Bignum :literal |
3002 | alias :visit_Fixnum :literal |
3003 | def quoted o, a |
3004 | if a && a.able_to_type_cast? |
3005 | quote(a.type_cast_for_database(o)) |
3006 | else |
3007 | quote(o, column_for(a)) |
3008 | end |
3009 | end |
3010 | def unsupported o, collector |
3011 | raise "unsupported: #{o.class.name}" |
3012 | end |
3013 | alias :visit_BigDecimal :unsupported |
3014 | alias :visit_Class :unsupported |
3015 | alias :visit_Date :unsupported |
3016 | alias :visit_DateTime :unsupported |
3017 | alias :visit_FalseClass :unsupported |
3018 | alias :visit_Float :unsupported |
3019 | alias :visit_Hash :unsupported |
3020 | alias :visit_NilClass :unsupported |
3021 | alias :visit_String :unsupported |
3022 | alias :visit_Symbol :unsupported |
3023 | alias :visit_Time :unsupported |
3024 | alias :visit_TrueClass :unsupported |
3025 | def visit_Arel_Nodes_InfixOperation o, collector |
3026 | collector = visit o.left, collector |
3027 | collector " #{o.operator} " |
3028 | visit o.right, collector |
3029 | end |
3030 | def visit_Array o, collector |
3031 | inject_join o, collector, ", " |
3032 | end |
3033 | alias :visit_Set :visit_Array |
3034 | def quote value, column = nil |
3035 | return value if Arel::Nodes::SqlLiteral === value |
3036 | if column |
3037 | print_type_cast_deprecation |
3038 | end |
3039 | @connection.quote value, column |
3040 | end |
3041 | def quote_table_name name |
3042 | return name if Arel::Nodes::SqlLiteral === name |
3043 | @connection.quote_table_name(name) |
3044 | end |
3045 | def quote_column_name name |
3046 | return name if Arel::Nodes::SqlLiteral === name |
3047 | @connection.quote_column_name(name) |
3048 | end |
3049 | def maybe_visit thing, collector |
3050 | return collector unless thing |
3051 | collector " " |
3052 | visit thing, collector |
3053 | end |
3054 | def inject_join list, collector, join_str |
3055 | len = list.length - 1 |
3056 | if i == len |
3057 | visit x, c |
3058 | else |
3059 | visit(x, c) join_str |
3060 | end |
3061 | } |
3062 | end |
3063 | def infix_value o, collector, value |
3064 | collector = visit o.left, collector |
3065 | collector value |
3066 | visit o.right, collector |
3067 | end |
3068 | def aggregate name, o, collector |
3069 | collector "#{name}(" |
3070 | if o.distinct |
3071 | collector "DISTINCT " |
3072 | end |
3073 | if o.alias |
3074 | collector " AS " |
3075 | visit o.alias, collector |
3076 | else |
3077 | collector |
3078 | end |
3079 | end |
3080 | def print_type_cast_deprecation |
3081 | warn -eowarn |
3082 | eowarn |
3083 | end |
3084 | end |
3085 | end |
3086 | end |
3087 | end |
3088 | module Arel |
3089 | module Visitors |
3090 | class Visitor |
3091 | def initialize |
3092 | @dispatch = get_dispatch_cache |
3093 | end |
3094 | def accept object |
3095 | visit object |
3096 | end |
3097 | private |
3098 | def self.dispatch_cache |
3099 | Hash.new do |hash, klass| |
3100 | end |
3101 | end |
3102 | def get_dispatch_cache |
3103 | self.class.dispatch_cache |
3104 | end |
3105 | def dispatch |
3106 | @dispatch |
3107 | end |
3108 | def visit object |
3109 | send dispatch[object.class], object |
3110 | rescue NoMethodError = e |
3111 | respond_to?(dispatch[klass], true) |
3112 | } |
3113 | dispatch[object.class] = dispatch[superklass] |
3114 | retry |
3115 | end |
3116 | end |
3117 | end |
3118 | end |
3119 | module Arel |
3120 | module Visitors |
3121 | class WhereSql Arel::Visitors::ToSql |
3122 | private |
3123 | def visit_Arel_Nodes_SelectCore o, collector |
3124 | collector "WHERE " |
3125 | inject_join o.wheres, collector, ' AND ' |
3126 | end |
3127 | end |
3128 | end |
3129 | end |
3130 | require 'arel/visitors/visitor' |
3131 | require 'arel/visitors/depth_first' |
3132 | require 'arel/visitors/to_sql' |
3133 | require 'arel/visitors/sqlite' |
3134 | require 'arel/visitors/postgresql' |
3135 | require 'arel/visitors/mysql' |
3136 | require 'arel/visitors/mssql' |
3137 | require 'arel/visitors/oracle' |
3138 | require 'arel/visitors/where_sql' |
3139 | require 'arel/visitors/dot' |
3140 | require 'arel/visitors/ibm_db' |
3141 | require 'arel/visitors/informix' |
3142 | module Arel |
3143 | module Visitors |
3144 | VISITORS = { |
3145 | 'postgresql' = Arel::Visitors::PostgreSQL, |
3146 | 'mysql' = Arel::Visitors::MySQL, |
3147 | 'mysql2' = Arel::Visitors::MySQL, |
3148 | 'mssql' = Arel::Visitors::MSSQL, |
3149 | 'sqlserver' = Arel::Visitors::MSSQL, |
3150 | 'oracle_enhanced' = Arel::Visitors::Oracle, |
3151 | 'sqlite' = Arel::Visitors::SQLite, |
3152 | 'sqlite3' = Arel::Visitors::SQLite, |
3153 | 'ibm_db' = Arel::Visitors::IBM_DB, |
3154 | 'informix' = Arel::Visitors::Informix, |
3155 | } |
3156 | ENGINE_VISITORS = Hash.new do |hash, engine| |
3157 | pool = engine.connection_pool |
3158 | adapter = pool.spec.config[:adapter] |
3159 | end |
3160 | def self.visitor_for engine |
3161 | ENGINE_VISITORS[engine] |
3162 | end |
3163 | class self; alias :for :visitor_for; end |
3164 | end |
3165 | end |
3166 | module Arel |
3167 | module WindowPredications |
3168 | def over(expr = nil) |
3169 | Nodes::Over.new(self, expr) |
3170 | end |
3171 | end |
3172 | endrequire 'arel/crud' |
3173 | require 'arel/factory_methods' |
3174 | require 'arel/expressions' |
3175 | require 'arel/predications' |
3176 | require 'arel/window_predications' |
3177 | require 'arel/math' |
3178 | require 'arel/alias_predication' |
3179 | require 'arel/order_predications' |
3180 | require 'arel/table' |
3181 | require 'arel/attributes' |
3182 | require 'arel/compatibility/wheres' |
3183 | require 'arel/visitors' |
3184 | require 'arel/tree_manager' |
3185 | require 'arel/insert_manager' |
3186 | require 'arel/select_manager' |
3187 | require 'arel/update_manager' |
3188 | require 'arel/delete_manager' |
3189 | require 'arel/nodes' |
3190 | module Arel |
3191 | VERSION = '7.0.0.alpha' |
3192 | def self.sql raw_sql |
3193 | Arel::Nodes::SqlLiteral.new raw_sql |
3194 | end |
3195 | def self.star |
3196 | sql '*' |
3197 | end |
3198 | Node = Arel::Nodes::Node |
3199 | end |
3200 | require 'helper' |
3201 | require 'ostruct' |
3202 | module Arel |
3203 | module Attributes |
3204 | describe 'attribute' do |
3205 | describe '#not_eq' do |
3206 | relation = Table.new(:users) |
3207 | end |
3208 | relation = Table.new(:users) |
3209 | mgr = relation.project relation[:id] |
3210 | mgr.where relation[:id].not_eq(10) |
3211 | mgr.to_sql.must_be_like %{ |
3212 | } |
3213 | end |
3214 | relation = Table.new(:users) |
3215 | mgr = relation.project relation[:id] |
3216 | mgr.where relation[:id].not_eq(nil) |
3217 | mgr.to_sql.must_be_like %{ |
3218 | } |
3219 | end |
3220 | end |
3221 | describe '#not_eq_any' do |
3222 | relation = Table.new(:users) |
3223 | end |
3224 | relation = Table.new(:users) |
3225 | mgr = relation.project relation[:id] |
3226 | mgr.where relation[:id].not_eq_any([1,2]) |
3227 | mgr.to_sql.must_be_like %{ |
3228 | } |
3229 | end |
3230 | end |
3231 | describe '#not_eq_all' do |
3232 | relation = Table.new(:users) |
3233 | end |
3234 | relation = Table.new(:users) |
3235 | mgr = relation.project relation[:id] |
3236 | mgr.where relation[:id].not_eq_all([1,2]) |
3237 | mgr.to_sql.must_be_like %{ |
3238 | } |
3239 | end |
3240 | end |
3241 | describe '#gt' do |
3242 | relation = Table.new(:users) |
3243 | end |
3244 | relation = Table.new(:users) |
3245 | mgr = relation.project relation[:id] |
3246 | mgr.where relation[:id].gt(10) |
3247 | mgr.to_sql.must_be_like %{ |
3248 | } |
3249 | end |
3250 | users = Table.new(:users) |
3251 | avg = users.project(users[:karma].average) |
3252 | mgr.to_sql.must_be_like %{ |
3253 | } |
3254 | end |
3255 | relation = Table.new(:users) |
3256 | mgr = relation.project relation[:id] |
3257 | mgr.where relation[:name].gt('fake_name') |
3258 | current_time = ::Time.now |
3259 | mgr.where relation[:created_at].gt(current_time) |
3260 | end |
3261 | end |
3262 | describe '#gt_any' do |
3263 | relation = Table.new(:users) |
3264 | end |
3265 | relation = Table.new(:users) |
3266 | mgr = relation.project relation[:id] |
3267 | mgr.where relation[:id].gt_any([1,2]) |
3268 | mgr.to_sql.must_be_like %{ |
3269 | } |
3270 | end |
3271 | end |
3272 | describe '#gt_all' do |
3273 | relation = Table.new(:users) |
3274 | end |
3275 | relation = Table.new(:users) |
3276 | mgr = relation.project relation[:id] |
3277 | mgr.where relation[:id].gt_all([1,2]) |
3278 | mgr.to_sql.must_be_like %{ |
3279 | } |
3280 | end |
3281 | end |
3282 | describe '#gteq' do |
3283 | relation = Table.new(:users) |
3284 | end |
3285 | relation = Table.new(:users) |
3286 | mgr = relation.project relation[:id] |
3287 | mgr.where relation[:id].gteq(10) |
3288 | mgr.to_sql.must_be_like %{ |
3289 | } |
3290 | end |
3291 | relation = Table.new(:users) |
3292 | mgr = relation.project relation[:id] |
3293 | mgr.where relation[:name].gteq('fake_name') |
3294 | current_time = ::Time.now |
3295 | end |
3296 | end |
3297 | describe '#gteq_any' do |
3298 | relation = Table.new(:users) |
3299 | end |
3300 | relation = Table.new(:users) |
3301 | mgr = relation.project relation[:id] |
3302 | mgr.where relation[:id].gteq_any([1,2]) |
3303 | mgr.to_sql.must_be_like %{ |
3304 | } |
3305 | end |
3306 | end |
3307 | describe '#gteq_all' do |
3308 | relation = Table.new(:users) |
3309 | end |
3310 | relation = Table.new(:users) |
3311 | mgr = relation.project relation[:id] |
3312 | mgr.where relation[:id].gteq_all([1,2]) |
3313 | mgr.to_sql.must_be_like %{ |
3314 | } |
3315 | end |
3316 | end |
3317 | describe '#lt' do |
3318 | relation = Table.new(:users) |
3319 | end |
3320 | relation = Table.new(:users) |
3321 | mgr = relation.project relation[:id] |
3322 | mgr.where relation[:id].lt(10) |
3323 | mgr.to_sql.must_be_like %{ |
3324 | } |
3325 | end |
3326 | relation = Table.new(:users) |
3327 | mgr = relation.project relation[:id] |
3328 | mgr.where relation[:name].lt('fake_name') |
3329 | current_time = ::Time.now |
3330 | mgr.where relation[:created_at].lt(current_time) |
3331 | end |
3332 | end |
3333 | describe '#lt_any' do |
3334 | relation = Table.new(:users) |
3335 | end |
3336 | relation = Table.new(:users) |
3337 | mgr = relation.project relation[:id] |
3338 | mgr.where relation[:id].lt_any([1,2]) |
3339 | mgr.to_sql.must_be_like %{ |
3340 | } |
3341 | end |
3342 | end |
3343 | describe '#lt_all' do |
3344 | relation = Table.new(:users) |
3345 | end |
3346 | relation = Table.new(:users) |
3347 | mgr = relation.project relation[:id] |
3348 | mgr.where relation[:id].lt_all([1,2]) |
3349 | mgr.to_sql.must_be_like %{ |
3350 | } |
3351 | end |
3352 | end |
3353 | describe '#lteq' do |
3354 | relation = Table.new(:users) |
3355 | end |
3356 | relation = Table.new(:users) |
3357 | mgr = relation.project relation[:id] |
3358 | mgr.where relation[:id].lteq(10) |
3359 | mgr.to_sql.must_be_like %{ |
3360 | } |
3361 | end |
3362 | relation = Table.new(:users) |
3363 | mgr = relation.project relation[:id] |
3364 | mgr.where relation[:name].lteq('fake_name') |
3365 | current_time = ::Time.now |
3366 | end |
3367 | end |
3368 | describe '#lteq_any' do |
3369 | relation = Table.new(:users) |
3370 | end |
3371 | relation = Table.new(:users) |
3372 | mgr = relation.project relation[:id] |
3373 | mgr.where relation[:id].lteq_any([1,2]) |
3374 | mgr.to_sql.must_be_like %{ |
3375 | } |
3376 | end |
3377 | end |
3378 | describe '#lteq_all' do |
3379 | relation = Table.new(:users) |
3380 | end |
3381 | relation = Table.new(:users) |
3382 | mgr = relation.project relation[:id] |
3383 | mgr.where relation[:id].lteq_all([1,2]) |
3384 | mgr.to_sql.must_be_like %{ |
3385 | } |
3386 | end |
3387 | end |
3388 | describe '#average' do |
3389 | relation = Table.new(:users) |
3390 | relation[:id].average.must_be_kind_of Nodes::Avg |
3391 | end |
3392 | relation = Table.new(:users) |
3393 | mgr = relation.project relation[:id].average |
3394 | mgr.to_sql.must_be_like %{ |
3395 | SELECT AVG("users"."id") |
3396 | FROM "users" |
3397 | } |
3398 | end |
3399 | end |
3400 | describe '#maximum' do |
3401 | relation = Table.new(:users) |
3402 | relation[:id].maximum.must_be_kind_of Nodes::Max |
3403 | end |
3404 | relation = Table.new(:users) |
3405 | mgr = relation.project relation[:id].maximum |
3406 | mgr.to_sql.must_be_like %{ |
3407 | SELECT MAX("users"."id") |
3408 | FROM "users" |
3409 | } |
3410 | end |
3411 | end |
3412 | describe '#minimum' do |
3413 | relation = Table.new(:users) |
3414 | relation[:id].minimum.must_be_kind_of Nodes::Min |
3415 | end |
3416 | end |
3417 | describe '#sum' do |
3418 | relation = Table.new(:users) |
3419 | relation[:id].sum.must_be_kind_of Nodes::Sum |
3420 | end |
3421 | relation = Table.new(:users) |
3422 | mgr = relation.project relation[:id].sum |
3423 | mgr.to_sql.must_be_like %{ |
3424 | SELECT SUM("users"."id") |
3425 | FROM "users" |
3426 | } |
3427 | end |
3428 | end |
3429 | describe '#count' do |
3430 | relation = Table.new(:users) |
3431 | relation[:id].count.must_be_kind_of Nodes::Count |
3432 | end |
3433 | relation = Table.new(:users) |
3434 | count = relation[:id].count(nil) |
3435 | count.must_be_kind_of Nodes::Count |
3436 | count.distinct.must_be_nil |
3437 | end |
3438 | end |
3439 | describe '#eq' do |
3440 | attribute = Attribute.new nil, nil |
3441 | equality = attribute.eq 1 |
3442 | equality.left.must_equal attribute |
3443 | equality.right.val.must_equal 1 |
3444 | equality.must_be_kind_of Nodes::Equality |
3445 | end |
3446 | relation = Table.new(:users) |
3447 | mgr = relation.project relation[:id] |
3448 | mgr.where relation[:id].eq(10) |
3449 | mgr.to_sql.must_be_like %{ |
3450 | } |
3451 | end |
3452 | relation = Table.new(:users) |
3453 | mgr = relation.project relation[:id] |
3454 | mgr.where relation[:id].eq(nil) |
3455 | mgr.to_sql.must_be_like %{ |
3456 | } |
3457 | end |
3458 | end |
3459 | describe '#eq_any' do |
3460 | relation = Table.new(:users) |
3461 | end |
3462 | relation = Table.new(:users) |
3463 | mgr = relation.project relation[:id] |
3464 | mgr.where relation[:id].eq_any([1,2]) |
3465 | mgr.to_sql.must_be_like %{ |
3466 | } |
3467 | end |
3468 | relation = Table.new(:users) |
3469 | mgr = relation.project relation[:id] |
3470 | values = [1,2] |
3471 | mgr.where relation[:id].eq_any(values) |
3472 | values.must_equal [1,2] |
3473 | end |
3474 | end |
3475 | describe '#eq_all' do |
3476 | relation = Table.new(:users) |
3477 | end |
3478 | relation = Table.new(:users) |
3479 | mgr = relation.project relation[:id] |
3480 | mgr.where relation[:id].eq_all([1,2]) |
3481 | mgr.to_sql.must_be_like %{ |
3482 | } |
3483 | end |
3484 | relation = Table.new(:users) |
3485 | mgr = relation.project relation[:id] |
3486 | values = [1,2] |
3487 | mgr.where relation[:id].eq_all(values) |
3488 | values.must_equal [1,2] |
3489 | end |
3490 | end |
3491 | describe '#matches' do |
3492 | relation = Table.new(:users) |
3493 | end |
3494 | relation = Table.new(:users) |
3495 | mgr = relation.project relation[:id] |
3496 | mgr.where relation[:name].matches('%bacon%') |
3497 | mgr.to_sql.must_be_like %{ |
3498 | } |
3499 | end |
3500 | end |
3501 | describe '#matches_any' do |
3502 | relation = Table.new(:users) |
3503 | end |
3504 | relation = Table.new(:users) |
3505 | mgr = relation.project relation[:id] |
3506 | mgr.to_sql.must_be_like %{ |
3507 | } |
3508 | end |
3509 | end |
3510 | describe '#matches_all' do |
3511 | relation = Table.new(:users) |
3512 | end |
3513 | relation = Table.new(:users) |
3514 | mgr = relation.project relation[:id] |
3515 | mgr.to_sql.must_be_like %{ |
3516 | } |
3517 | end |
3518 | end |
3519 | describe '#does_not_match' do |
3520 | relation = Table.new(:users) |
3521 | end |
3522 | relation = Table.new(:users) |
3523 | mgr = relation.project relation[:id] |
3524 | mgr.to_sql.must_be_like %{ |
3525 | } |
3526 | end |
3527 | end |
3528 | describe '#does_not_match_any' do |
3529 | relation = Table.new(:users) |
3530 | end |
3531 | relation = Table.new(:users) |
3532 | mgr = relation.project relation[:id] |
3533 | mgr.to_sql.must_be_like %{ |
3534 | } |
3535 | end |
3536 | end |
3537 | describe '#does_not_match_all' do |
3538 | relation = Table.new(:users) |
3539 | end |
3540 | relation = Table.new(:users) |
3541 | mgr = relation.project relation[:id] |
3542 | mgr.to_sql.must_be_like %{ |
3543 | } |
3544 | end |
3545 | end |
3546 | describe 'with a range' do |
3547 | attribute = Attribute.new nil, nil |
3548 | node = attribute.between(1..3) |
3549 | node.must_equal Nodes::Between.new( |
3550 | attribute, |
3551 | Nodes::And.new([ |
3552 | Nodes::Casted.new(1, attribute), |
3553 | Nodes::Casted.new(3, attribute) |
3554 | ]) |
3555 | ) |
3556 | end |
3557 | attribute = Attribute.new nil, nil |
3558 | node = attribute.between(-::Float::INFINITY..3) |
3559 | node.must_equal Nodes::LessThanOrEqual.new( |
3560 | attribute, |
3561 | Nodes::Casted.new(3, attribute) |
3562 | ) |
3563 | end |
3564 | attribute = Attribute.new nil, nil |
3565 | node.must_equal Nodes::LessThanOrEqual.new( |
3566 | attribute, |
3567 | Nodes::Quoted.new(3) |
3568 | ) |
3569 | end |
3570 | attribute = Attribute.new nil, nil |
3571 | node = attribute.between(-::Float::INFINITY...3) |
3572 | node.must_equal Nodes::LessThan.new( |
3573 | attribute, |
3574 | Nodes::Casted.new(3, attribute) |
3575 | ) |
3576 | end |
3577 | attribute = Attribute.new nil, nil |
3578 | node.must_equal Nodes::LessThan.new( |
3579 | attribute, |
3580 | Nodes::Quoted.new(3) |
3581 | ) |
3582 | end |
3583 | attribute = Attribute.new nil, nil |
3584 | node.must_equal Nodes::NotIn.new(attribute, []) |
3585 | end |
3586 | attribute = Attribute.new nil, nil |
3587 | node.must_equal Nodes::NotIn.new(attribute, []) |
3588 | end |
3589 | attribute = Attribute.new nil, nil |
3590 | node = attribute.between(0..::Float::INFINITY) |
3591 | node.must_equal Nodes::GreaterThanOrEqual.new( |
3592 | attribute, |
3593 | Nodes::Casted.new(0, attribute) |
3594 | ) |
3595 | end |
3596 | attribute = Attribute.new nil, nil |
3597 | node.must_equal Nodes::GreaterThanOrEqual.new( |
3598 | attribute, |
3599 | Nodes::Quoted.new(0) |
3600 | ) |
3601 | end |
3602 | attribute = Attribute.new nil, nil |
3603 | node = attribute.between(0...3) |
3604 | node.must_equal Nodes::And.new([ |
3605 | Nodes::GreaterThanOrEqual.new( |
3606 | attribute, |
3607 | Nodes::Casted.new(0, attribute) |
3608 | ), |
3609 | Nodes::LessThan.new( |
3610 | attribute, |
3611 | Nodes::Casted.new(3, attribute) |
3612 | ) |
3613 | ]) |
3614 | end |
3615 | def quoted_range(begin_val, end_val, exclude) |
3616 | OpenStruct.new( |
3617 | begin: Nodes::Quoted.new(begin_val), |
3618 | end: Nodes::Quoted.new(end_val), |
3619 | exclude_end?: exclude, |
3620 | ) |
3621 | end |
3622 | end |
3623 | describe '#in' do |
3624 | relation = Table.new(:users) |
3625 | mgr = relation.project relation[:id] |
3626 | attribute = Attribute.new nil, nil |
3627 | node = attribute.in(mgr) |
3628 | node.must_equal Nodes::In.new(attribute, mgr.ast) |
3629 | end |
3630 | attribute = Attribute.new nil, nil |
3631 | node = attribute.in([1, 2, 3]) |
3632 | node.must_equal Nodes::In.new( |
3633 | attribute, |
3634 | [ |
3635 | Nodes::Casted.new(1, attribute), |
3636 | Nodes::Casted.new(2, attribute), |
3637 | Nodes::Casted.new(3, attribute), |
3638 | ] |
3639 | ) |
3640 | end |
3641 | attribute = Attribute.new nil, nil |
3642 | random_object = Object.new |
3643 | node = attribute.in(random_object) |
3644 | node.must_equal Nodes::In.new( |
3645 | attribute, |
3646 | Nodes::Casted.new(random_object, attribute) |
3647 | ) |
3648 | end |
3649 | relation = Table.new(:users) |
3650 | mgr = relation.project relation[:id] |
3651 | mgr.where relation[:id].in([1,2,3]) |
3652 | mgr.to_sql.must_be_like %{ |
3653 | } |
3654 | end |
3655 | end |
3656 | describe '#in_any' do |
3657 | relation = Table.new(:users) |
3658 | end |
3659 | relation = Table.new(:users) |
3660 | mgr = relation.project relation[:id] |
3661 | mgr.where relation[:id].in_any([[1,2], [3,4]]) |
3662 | mgr.to_sql.must_be_like %{ |
3663 | } |
3664 | end |
3665 | end |
3666 | describe '#in_all' do |
3667 | relation = Table.new(:users) |
3668 | end |
3669 | relation = Table.new(:users) |
3670 | mgr = relation.project relation[:id] |
3671 | mgr.where relation[:id].in_all([[1,2], [3,4]]) |
3672 | mgr.to_sql.must_be_like %{ |
3673 | } |
3674 | end |
3675 | end |
3676 | describe 'with a range' do |
3677 | attribute = Attribute.new nil, nil |
3678 | node = attribute.not_between(1..3) |
3679 | Nodes::LessThan.new( |
3680 | attribute, |
3681 | Nodes::Casted.new(1, attribute) |
3682 | ), |
3683 | Nodes::GreaterThan.new( |
3684 | attribute, |
3685 | Nodes::Casted.new(3, attribute) |
3686 | ) |
3687 | )) |
3688 | end |
3689 | attribute = Attribute.new nil, nil |
3690 | node.must_equal Nodes::GreaterThan.new( |
3691 | attribute, |
3692 | Nodes::Casted.new(3, attribute) |
3693 | ) |
3694 | end |
3695 | attribute = Attribute.new nil, nil |
3696 | node.must_equal Nodes::GreaterThanOrEqual.new( |
3697 | attribute, |
3698 | Nodes::Casted.new(3, attribute) |
3699 | ) |
3700 | end |
3701 | attribute = Attribute.new nil, nil |
3702 | node.must_equal Nodes::In.new(attribute, []) |
3703 | end |
3704 | attribute = Attribute.new nil, nil |
3705 | node.must_equal Nodes::LessThan.new( |
3706 | attribute, |
3707 | Nodes::Casted.new(0, attribute) |
3708 | ) |
3709 | end |
3710 | attribute = Attribute.new nil, nil |
3711 | node = attribute.not_between(0...3) |
3712 | Nodes::LessThan.new( |
3713 | attribute, |
3714 | Nodes::Casted.new(0, attribute) |
3715 | ), |
3716 | Nodes::GreaterThanOrEqual.new( |
3717 | attribute, |
3718 | Nodes::Casted.new(3, attribute) |
3719 | ) |
3720 | )) |
3721 | end |
3722 | end |
3723 | describe '#not_in' do |
3724 | relation = Table.new(:users) |
3725 | mgr = relation.project relation[:id] |
3726 | attribute = Attribute.new nil, nil |
3727 | node = attribute.not_in(mgr) |
3728 | end |
3729 | attribute = Attribute.new nil, nil |
3730 | node = attribute.not_in([1, 2, 3]) |
3731 | node.must_equal Nodes::NotIn.new( |
3732 | attribute, |
3733 | [ |
3734 | Nodes::Casted.new(1, attribute), |
3735 | Nodes::Casted.new(2, attribute), |
3736 | Nodes::Casted.new(3, attribute), |
3737 | ] |
3738 | ) |
3739 | end |
3740 | attribute = Attribute.new nil, nil |
3741 | random_object = Object.new |
3742 | node = attribute.not_in(random_object) |
3743 | node.must_equal Nodes::NotIn.new( |
3744 | attribute, |
3745 | Nodes::Casted.new(random_object, attribute) |
3746 | ) |
3747 | end |
3748 | relation = Table.new(:users) |
3749 | mgr = relation.project relation[:id] |
3750 | mgr.where relation[:id].not_in([1,2,3]) |
3751 | mgr.to_sql.must_be_like %{ |
3752 | } |
3753 | end |
3754 | end |
3755 | describe '#not_in_any' do |
3756 | relation = Table.new(:users) |
3757 | end |
3758 | relation = Table.new(:users) |
3759 | mgr = relation.project relation[:id] |
3760 | mgr.to_sql.must_be_like %{ |
3761 | } |
3762 | end |
3763 | end |
3764 | describe '#not_in_all' do |
3765 | relation = Table.new(:users) |
3766 | end |
3767 | relation = Table.new(:users) |
3768 | mgr = relation.project relation[:id] |
3769 | mgr.to_sql.must_be_like %{ |
3770 | } |
3771 | end |
3772 | end |
3773 | describe '#eq_all' do |
3774 | relation = Table.new(:users) |
3775 | end |
3776 | relation = Table.new(:users) |
3777 | mgr = relation.project relation[:id] |
3778 | mgr.where relation[:id].eq_all([1,2]) |
3779 | mgr.to_sql.must_be_like %{ |
3780 | } |
3781 | end |
3782 | end |
3783 | describe '#asc' do |
3784 | relation = Table.new(:users) |
3785 | end |
3786 | relation = Table.new(:users) |
3787 | mgr = relation.project relation[:id] |
3788 | mgr.order relation[:id].asc |
3789 | mgr.to_sql.must_be_like %{ |
3790 | } |
3791 | end |
3792 | end |
3793 | describe '#desc' do |
3794 | relation = Table.new(:users) |
3795 | end |
3796 | relation = Table.new(:users) |
3797 | mgr = relation.project relation[:id] |
3798 | mgr.order relation[:id].desc |
3799 | mgr.to_sql.must_be_like %{ |
3800 | } |
3801 | end |
3802 | end |
3803 | end |
3804 | describe 'equality' do |
3805 | describe '#to_sql' do |
3806 | table = Table.new :users |
3807 | condition = table['id'].eq 1 |
3808 | condition.to_sql.must_equal '"users"."id" = 1' |
3809 | end |
3810 | end |
3811 | end |
3812 | describe 'type casting' do |
3813 | table = Table.new(:foo) |
3814 | condition = table["id"].eq("1") |
3815 | refute table.able_to_type_cast? |
3816 | condition.to_sql.must_equal %("foo"."id" = '1') |
3817 | end |
3818 | fake_caster = Object.new |
3819 | if attr_name == "id" |
3820 | value.to_i |
3821 | else |
3822 | value |
3823 | end |
3824 | end |
3825 | table = Table.new(:foo, type_caster: fake_caster) |
3826 | assert table.able_to_type_cast? |
3827 | end |
3828 | table = Table.new(:users) |
3829 | condition = table["id"].eq("1") |
3830 | refute table.able_to_type_cast? |
3831 | condition.to_sql.must_equal %("users"."id" = 1) |
3832 | end |
3833 | end |
3834 | end |
3835 | end |
3836 | require 'helper' |
3837 | require 'arel/collectors/bind' |
3838 | module Arel |
3839 | module Collectors |
3840 | class TestBindCollector Arel::Test |
3841 | def setup |
3842 | @conn = FakeRecord::Base.new |
3843 | @visitor = Visitors::ToSql.new @conn.connection |
3844 | super |
3845 | end |
3846 | def collect node |
3847 | @visitor.accept(node, Collectors::Bind.new) |
3848 | end |
3849 | def compile node |
3850 | collect(node).value |
3851 | end |
3852 | def ast_with_binds bv |
3853 | table = Table.new(:users) |
3854 | manager = Arel::SelectManager.new table |
3855 | manager.where(table[:age].eq(bv)) |
3856 | manager.where(table[:name].eq(bv)) |
3857 | manager.ast |
3858 | end |
3859 | def test_leaves_binds |
3860 | node = Nodes::BindParam.new |
3861 | list = compile node |
3862 | assert_equal node, list.first |
3863 | assert_equal node.class, list.first.class |
3864 | end |
3865 | def test_adds_strings |
3866 | bv = Nodes::BindParam.new |
3867 | list = compile ast_with_binds bv |
3868 | assert_operator list.length, :, 0 |
3869 | end |
3870 | def test_substitute_binds |
3871 | bv = Nodes::BindParam.new |
3872 | collector = collect ast_with_binds bv |
3873 | values = collector.value |
3874 | offsets = values.map.with_index { |v,i| |
3875 | [v,i] |
3876 | assert_equal "hello", list[offsets[0]] |
3877 | assert_equal "world", list[offsets[1]] |
3878 | end |
3879 | def test_compile |
3880 | bv = Nodes::BindParam.new |
3881 | collector = collect ast_with_binds bv |
3882 | sql = collector.compile ["hello", "world"] |
3883 | end |
3884 | end |
3885 | end |
3886 | end |
3887 | require 'helper' |
3888 | require 'arel/collectors/bind' |
3889 | module Arel |
3890 | module Collectors |
3891 | class TestSqlString Arel::Test |
3892 | def setup |
3893 | @conn = FakeRecord::Base.new |
3894 | @visitor = Visitors::ToSql.new @conn.connection |
3895 | super |
3896 | end |
3897 | def collect node |
3898 | @visitor.accept(node, Collectors::SQLString.new) |
3899 | end |
3900 | def compile node |
3901 | collect(node).value |
3902 | end |
3903 | def ast_with_binds bv |
3904 | table = Table.new(:users) |
3905 | manager = Arel::SelectManager.new table |
3906 | manager.where(table[:age].eq(bv)) |
3907 | manager.where(table[:name].eq(bv)) |
3908 | manager.ast |
3909 | end |
3910 | def test_compile |
3911 | bv = Nodes::BindParam.new |
3912 | collector = collect ast_with_binds bv |
3913 | sql = collector.compile ["hello", "world"] |
3914 | end |
3915 | end |
3916 | end |
3917 | end |
3918 | require 'rubygems' |
3919 | require 'minitest/autorun' |
3920 | require 'fileutils' |
3921 | require 'arel' |
3922 | require 'support/fake_record' |
3923 | Arel::Table.engine = FakeRecord::Base.new |
3924 | $arel_silence_type_casting_deprecation = true |
3925 | class Object |
3926 | def must_be_like other |
3927 | end |
3928 | end |
3929 | module Arel |
3930 | class Test MiniTest::Test |
3931 | def assert_like expected, actual |
3932 | assert_equal expected.gsub(/\s+/, ' ').strip, |
3933 | actual.gsub(/\s+/, ' ').strip |
3934 | end |
3935 | end |
3936 | end |
3937 | require 'helper' |
3938 | module Arel |
3939 | module Nodes |
3940 | describe 'And' do |
3941 | describe 'equality' do |
3942 | assert_equal 1, array.uniq.size |
3943 | end |
3944 | assert_equal 2, array.uniq.size |
3945 | end |
3946 | end |
3947 | end |
3948 | end |
3949 | end |
3950 | require 'helper' |
3951 | module Arel |
3952 | module Nodes |
3953 | describe 'As' do |
3954 | describe '#as' do |
3955 | attr = Table.new(:users)[:id] |
3956 | as = attr.as(Arel.sql('foo')) |
3957 | assert_equal attr, as.left |
3958 | assert_equal 'foo', as.right |
3959 | end |
3960 | attr = Table.new(:users)[:id] |
3961 | as = attr.as('foo') |
3962 | assert_kind_of Arel::Nodes::SqlLiteral, as.right |
3963 | end |
3964 | end |
3965 | describe 'equality' do |
3966 | assert_equal 1, array.uniq.size |
3967 | end |
3968 | assert_equal 2, array.uniq.size |
3969 | end |
3970 | end |
3971 | end |
3972 | end |
3973 | end |
3974 | require 'helper' |
3975 | module Arel |
3976 | module Nodes |
3977 | class TestAscending Minitest::Test |
3978 | def test_construct |
3979 | ascending = Ascending.new 'zomg' |
3980 | assert_equal 'zomg', ascending.expr |
3981 | end |
3982 | def test_reverse |
3983 | ascending = Ascending.new 'zomg' |
3984 | descending = ascending.reverse |
3985 | assert_kind_of Descending, descending |
3986 | assert_equal ascending.expr, descending.expr |
3987 | end |
3988 | def test_direction |
3989 | ascending = Ascending.new 'zomg' |
3990 | assert_equal :asc, ascending.direction |
3991 | end |
3992 | def test_ascending? |
3993 | ascending = Ascending.new 'zomg' |
3994 | assert ascending.ascending? |
3995 | end |
3996 | def test_descending? |
3997 | ascending = Ascending.new 'zomg' |
3998 | assert !ascending.descending? |
3999 | end |
4000 | def test_equality_with_same_ivars |
4001 | assert_equal 1, array.uniq.size |
4002 | end |
4003 | def test_inequality_with_different_ivars |
4004 | assert_equal 2, array.uniq.size |
4005 | end |
4006 | end |
4007 | end |
4008 | end |
4009 | require 'helper' |
4010 | module Arel |
4011 | module Nodes |
4012 | class TestBin Minitest::Test |
4013 | def test_new |
4014 | assert Arel::Nodes::Bin.new('zomg') |
4015 | end |
4016 | def test_default_to_sql |
4017 | node = Arel::Nodes::Bin.new(Arel.sql('zomg')) |
4018 | end |
4019 | def test_mysql_to_sql |
4020 | node = Arel::Nodes::Bin.new(Arel.sql('zomg')) |
4021 | end |
4022 | def test_equality_with_same_ivars |
4023 | array = [Bin.new('zomg'), Bin.new('zomg')] |
4024 | assert_equal 1, array.uniq.size |
4025 | end |
4026 | def test_inequality_with_different_ivars |
4027 | array = [Bin.new('zomg'), Bin.new('zomg!')] |
4028 | assert_equal 2, array.uniq.size |
4029 | end |
4030 | end |
4031 | end |
4032 | end |
4033 | require 'helper' |
4034 | require 'set' |
4035 | module Arel |
4036 | module Nodes |
4037 | describe 'Binary' do |
4038 | describe '#hash' do |
4039 | eq = Equality.new('foo', 'bar') |
4040 | eq2 = Equality.new('foo', 'bar') |
4041 | eq3 = Equality.new('bar', 'baz') |
4042 | assert_equal eq.hash, eq2.hash |
4043 | refute_equal eq.hash, eq3.hash |
4044 | end |
4045 | eq = Equality.new('foo', 'bar') |
4046 | neq = NotEqual.new('foo', 'bar') |
4047 | refute_equal eq.hash, neq.hash |
4048 | end |
4049 | end |
4050 | end |
4051 | end |
4052 | end |
4053 | require 'helper' |
4054 | module Arel |
4055 | module Nodes |
4056 | describe 'BindParam' do |
4057 | BindParam.new.must_equal(BindParam.new) |
4058 | end |
4059 | BindParam.new.wont_equal(Node.new) |
4060 | end |
4061 | end |
4062 | end |
4063 | end |
4064 | require 'helper' |
4065 | describe Arel::Nodes::Count do |
4066 | describe "as" do |
4067 | table = Arel::Table.new :users |
4068 | table[:id].count.as('foo').to_sql.must_be_like %{ |
4069 | COUNT("users"."id") AS foo |
4070 | } |
4071 | end |
4072 | end |
4073 | describe "eq" do |
4074 | table = Arel::Table.new :users |
4075 | table[:id].count.eq(2).to_sql.must_be_like %{ |
4076 | COUNT("users"."id") = 2 |
4077 | } |
4078 | end |
4079 | end |
4080 | describe 'equality' do |
4081 | assert_equal 1, array.uniq.size |
4082 | end |
4083 | assert_equal 2, array.uniq.size |
4084 | end |
4085 | end |
4086 | end |
4087 | require 'helper' |
4088 | describe Arel::Nodes::DeleteStatement do |
4089 | describe "#clone" do |
4090 | statement = Arel::Nodes::DeleteStatement.new |
4091 | statement.wheres = %w[a b c] |
4092 | dolly = statement.clone |
4093 | dolly.wheres.must_equal statement.wheres |
4094 | dolly.wheres.wont_be_same_as statement.wheres |
4095 | end |
4096 | end |
4097 | describe 'equality' do |
4098 | statement1 = Arel::Nodes::DeleteStatement.new |
4099 | statement1.wheres = %w[a b c] |
4100 | statement2 = Arel::Nodes::DeleteStatement.new |
4101 | statement2.wheres = %w[a b c] |
4102 | array = [statement1, statement2] |
4103 | assert_equal 1, array.uniq.size |
4104 | end |
4105 | statement1 = Arel::Nodes::DeleteStatement.new |
4106 | statement1.wheres = %w[a b c] |
4107 | statement2 = Arel::Nodes::DeleteStatement.new |
4108 | statement2.wheres = %w[1 2 3] |
4109 | array = [statement1, statement2] |
4110 | assert_equal 2, array.uniq.size |
4111 | end |
4112 | end |
4113 | end |
4114 | require 'helper' |
4115 | module Arel |
4116 | module Nodes |
4117 | class TestDescending Minitest::Test |
4118 | def test_construct |
4119 | descending = Descending.new 'zomg' |
4120 | assert_equal 'zomg', descending.expr |
4121 | end |
4122 | def test_reverse |
4123 | descending = Descending.new 'zomg' |
4124 | ascending = descending.reverse |
4125 | assert_kind_of Ascending, ascending |
4126 | assert_equal descending.expr, ascending.expr |
4127 | end |
4128 | def test_direction |
4129 | descending = Descending.new 'zomg' |
4130 | assert_equal :desc, descending.direction |
4131 | end |
4132 | def test_ascending? |
4133 | descending = Descending.new 'zomg' |
4134 | assert !descending.ascending? |
4135 | end |
4136 | def test_descending? |
4137 | descending = Descending.new 'zomg' |
4138 | assert descending.descending? |
4139 | end |
4140 | def test_equality_with_same_ivars |
4141 | assert_equal 1, array.uniq.size |
4142 | end |
4143 | def test_inequality_with_different_ivars |
4144 | assert_equal 2, array.uniq.size |
4145 | end |
4146 | end |
4147 | end |
4148 | end |
4149 | require 'helper' |
4150 | module Arel |
4151 | module Nodes |
4152 | describe 'Distinct' do |
4153 | describe 'equality' do |
4154 | array = [Distinct.new, Distinct.new] |
4155 | assert_equal 1, array.uniq.size |
4156 | end |
4157 | array = [Distinct.new, Node.new] |
4158 | assert_equal 2, array.uniq.size |
4159 | end |
4160 | end |
4161 | end |
4162 | end |
4163 | end |
4164 | require 'helper' |
4165 | module Arel |
4166 | module Nodes |
4167 | describe 'equality' do |
4168 | describe 'backwards compat' do |
4169 | describe 'operator' do |
4170 | attr = Table.new(:users)[:id] |
4171 | left = attr.eq(10) |
4172 | left.operator.must_equal :== |
4173 | end |
4174 | end |
4175 | describe 'operand1' do |
4176 | attr = Table.new(:users)[:id] |
4177 | left = attr.eq(10) |
4178 | left.left.must_equal left.operand1 |
4179 | end |
4180 | end |
4181 | describe 'operand2' do |
4182 | attr = Table.new(:users)[:id] |
4183 | left = attr.eq(10) |
4184 | left.right.must_equal left.operand2 |
4185 | end |
4186 | end |
4187 | describe 'to_sql' do |
4188 | engine = FakeRecord::Base.new |
4189 | engine.connection.extend Module.new { |
4190 | attr_accessor :quote_count |
4191 | def quote(*args) @quote_count += 1; super; end |
4192 | } |
4193 | engine.connection.quote_count = 0 |
4194 | attr = Table.new(:users)[:id] |
4195 | test = attr.eq(10) |
4196 | test.to_sql engine |
4197 | engine.connection.quote_count.must_equal 3 |
4198 | end |
4199 | end |
4200 | end |
4201 | describe 'or' do |
4202 | attr = Table.new(:users)[:id] |
4203 | left = attr.eq(10) |
4204 | right = attr.eq(11) |
4205 | node = left.or right |
4206 | node.expr.left.must_equal left |
4207 | node.expr.right.must_equal right |
4208 | end |
4209 | end |
4210 | describe 'and' do |
4211 | attr = Table.new(:users)[:id] |
4212 | left = attr.eq(10) |
4213 | right = attr.eq(11) |
4214 | node = left.and right |
4215 | node.left.must_equal left |
4216 | node.right.must_equal right |
4217 | end |
4218 | end |
4219 | assert_equal 1, array.uniq.size |
4220 | end |
4221 | assert_equal 2, array.uniq.size |
4222 | end |
4223 | end |
4224 | end |
4225 | end |
4226 | require 'helper' |
4227 | describe Arel::Nodes::Extract do |
4228 | table = Arel::Table.new :users |
4229 | EXTRACT(DATE FROM "users"."timestamp") |
4230 | } |
4231 | end |
4232 | describe "as" do |
4233 | table = Arel::Table.new :users |
4234 | EXTRACT(DATE FROM "users"."timestamp") AS foo |
4235 | } |
4236 | end |
4237 | table = Arel::Table.new :users |
4238 | extract = table[:timestamp].extract('date') |
4239 | before = extract.dup |
4240 | extract.as('foo') |
4241 | assert_equal extract, before |
4242 | end |
4243 | end |
4244 | describe 'equality' do |
4245 | table = Arel::Table.new :users |
4246 | assert_equal 1, array.uniq.size |
4247 | end |
4248 | table = Arel::Table.new :users |
4249 | assert_equal 2, array.uniq.size |
4250 | end |
4251 | end |
4252 | end |
4253 | require 'helper' |
4254 | module Arel |
4255 | module Nodes |
4256 | describe 'False' do |
4257 | describe 'equality' do |
4258 | array = [False.new, False.new] |
4259 | assert_equal 1, array.uniq.size |
4260 | end |
4261 | array = [False.new, Node.new] |
4262 | assert_equal 2, array.uniq.size |
4263 | end |
4264 | end |
4265 | end |
4266 | end |
4267 | end |
4268 | require 'helper' |
4269 | module Arel |
4270 | module Nodes |
4271 | describe 'Grouping' do |
4272 | end |
4273 | describe 'equality' do |
4274 | assert_equal 1, array.uniq.size |
4275 | end |
4276 | assert_equal 2, array.uniq.size |
4277 | end |
4278 | end |
4279 | end |
4280 | end |
4281 | end |
4282 | require 'helper' |
4283 | module Arel |
4284 | module Nodes |
4285 | class TestInfixOperation Minitest::Test |
4286 | def test_construct |
4287 | operation = InfixOperation.new :+, 1, 2 |
4288 | assert_equal :+, operation.operator |
4289 | assert_equal 1, operation.left |
4290 | assert_equal 2, operation.right |
4291 | end |
4292 | def test_operation_alias |
4293 | operation = InfixOperation.new :+, 1, 2 |
4294 | aliaz = operation.as('zomg') |
4295 | assert_kind_of As, aliaz |
4296 | assert_equal operation, aliaz.left |
4297 | assert_equal 'zomg', aliaz.right |
4298 | end |
4299 | def test_operation_ordering |
4300 | operation = InfixOperation.new :+, 1, 2 |
4301 | ordering = operation.desc |
4302 | assert_kind_of Descending, ordering |
4303 | assert_equal operation, ordering.expr |
4304 | assert ordering.descending? |
4305 | end |
4306 | def test_equality_with_same_ivars |
4307 | assert_equal 1, array.uniq.size |
4308 | end |
4309 | def test_inequality_with_different_ivars |
4310 | assert_equal 2, array.uniq.size |
4311 | end |
4312 | end |
4313 | end |
4314 | end |
4315 | require 'helper' |
4316 | describe Arel::Nodes::InsertStatement do |
4317 | describe "#clone" do |
4318 | statement = Arel::Nodes::InsertStatement.new |
4319 | statement.columns = %w[a b c] |
4320 | statement.values = %w[x y z] |
4321 | dolly = statement.clone |
4322 | dolly.columns.must_equal statement.columns |
4323 | dolly.values.must_equal statement.values |
4324 | dolly.columns.wont_be_same_as statement.columns |
4325 | dolly.values.wont_be_same_as statement.values |
4326 | end |
4327 | end |
4328 | describe 'equality' do |
4329 | statement1 = Arel::Nodes::InsertStatement.new |
4330 | statement1.columns = %w[a b c] |
4331 | statement1.values = %w[x y z] |
4332 | statement2 = Arel::Nodes::InsertStatement.new |
4333 | statement2.columns = %w[a b c] |
4334 | statement2.values = %w[x y z] |
4335 | array = [statement1, statement2] |
4336 | assert_equal 1, array.uniq.size |
4337 | end |
4338 | statement1 = Arel::Nodes::InsertStatement.new |
4339 | statement1.columns = %w[a b c] |
4340 | statement1.values = %w[x y z] |
4341 | statement2 = Arel::Nodes::InsertStatement.new |
4342 | statement2.columns = %w[a b c] |
4343 | statement2.values = %w[1 2 3] |
4344 | array = [statement1, statement2] |
4345 | assert_equal 2, array.uniq.size |
4346 | end |
4347 | end |
4348 | end |
4349 | require 'helper' |
4350 | module Arel |
4351 | module Nodes |
4352 | class TestNamedFunction Minitest::Test |
4353 | def test_construct |
4354 | function = NamedFunction.new 'omg', 'zomg' |
4355 | assert_equal 'omg', function.name |
4356 | assert_equal 'zomg', function.expressions |
4357 | end |
4358 | def test_function_alias |
4359 | function = NamedFunction.new 'omg', 'zomg' |
4360 | function = function.as('wth') |
4361 | assert_equal 'omg', function.name |
4362 | assert_equal 'zomg', function.expressions |
4363 | assert_kind_of SqlLiteral, function.alias |
4364 | assert_equal 'wth', function.alias |
4365 | end |
4366 | def test_construct_with_alias |
4367 | function = NamedFunction.new 'omg', 'zomg', 'wth' |
4368 | assert_equal 'omg', function.name |
4369 | assert_equal 'zomg', function.expressions |
4370 | assert_kind_of SqlLiteral, function.alias |
4371 | assert_equal 'wth', function.alias |
4372 | end |
4373 | def test_equality_with_same_ivars |
4374 | array = [ |
4375 | NamedFunction.new('omg', 'zomg', 'wth'), |
4376 | NamedFunction.new('omg', 'zomg', 'wth') |
4377 | ] |
4378 | assert_equal 1, array.uniq.size |
4379 | end |
4380 | def test_inequality_with_different_ivars |
4381 | array = [ |
4382 | NamedFunction.new('omg', 'zomg', 'wth'), |
4383 | NamedFunction.new('zomg', 'zomg', 'wth') |
4384 | ] |
4385 | assert_equal 2, array.uniq.size |
4386 | end |
4387 | end |
4388 | end |
4389 | end |
4390 | require 'helper' |
4391 | module Arel |
4392 | class TestNode Minitest::Test |
4393 | def test_includes_factory_methods |
4394 | assert Node.new.respond_to?(:create_join) |
4395 | end |
4396 | def test_all_nodes_are_nodes |
4397 | Nodes.constants.map { |k| |
4398 | Nodes.const_get(k) |
4399 | }.grep(Class).each do |klass| |
4400 | next if Nodes::SqlLiteral == klass |
4401 | next if Nodes::BindParam == klass |
4402 | next if klass.name =~ /^Arel::Nodes::Test/ |
4403 | end |
4404 | end |
4405 | def test_each |
4406 | list = [] |
4407 | node = Nodes::Node.new |
4408 | node.each { |n| list n } |
4409 | assert_equal [node], list |
4410 | end |
4411 | def test_generator |
4412 | list = [] |
4413 | node = Nodes::Node.new |
4414 | node.each.each { |n| list n } |
4415 | assert_equal [node], list |
4416 | end |
4417 | def test_enumerable |
4418 | node = Nodes::Node.new |
4419 | assert_kind_of Enumerable, node |
4420 | end |
4421 | end |
4422 | end |
4423 | require 'helper' |
4424 | module Arel |
4425 | module Nodes |
4426 | describe 'not' do |
4427 | describe '#not' do |
4428 | attr = Table.new(:users)[:id] |
4429 | expr = attr.eq(10) |
4430 | node = expr.not |
4431 | node.must_be_kind_of Not |
4432 | node.expr.must_equal expr |
4433 | end |
4434 | end |
4435 | describe 'equality' do |
4436 | array = [Not.new('foo'), Not.new('foo')] |
4437 | assert_equal 1, array.uniq.size |
4438 | end |
4439 | array = [Not.new('foo'), Not.new('baz')] |
4440 | assert_equal 2, array.uniq.size |
4441 | end |
4442 | end |
4443 | end |
4444 | end |
4445 | end |
4446 | require 'helper' |
4447 | module Arel |
4448 | module Nodes |
4449 | describe 'or' do |
4450 | describe '#or' do |
4451 | attr = Table.new(:users)[:id] |
4452 | left = attr.eq(10) |
4453 | right = attr.eq(11) |
4454 | node = left.or right |
4455 | node.expr.left.must_equal left |
4456 | node.expr.right.must_equal right |
4457 | oror = node.or(right) |
4458 | oror.expr.left.must_equal node |
4459 | oror.expr.right.must_equal right |
4460 | end |
4461 | end |
4462 | describe 'equality' do |
4463 | assert_equal 1, array.uniq.size |
4464 | end |
4465 | assert_equal 2, array.uniq.size |
4466 | end |
4467 | end |
4468 | end |
4469 | end |
4470 | end |
4471 | require 'helper' |
4472 | describe Arel::Nodes::Over do |
4473 | describe 'as' do |
4474 | table = Arel::Table.new :users |
4475 | COUNT("users"."id") OVER () AS foo |
4476 | } |
4477 | end |
4478 | end |
4479 | describe 'with literal' do |
4480 | table = Arel::Table.new :users |
4481 | COUNT("users"."id") OVER "foo" |
4482 | } |
4483 | end |
4484 | end |
4485 | describe 'with SQL literal' do |
4486 | table = Arel::Table.new :users |
4487 | COUNT("users"."id") OVER foo |
4488 | } |
4489 | end |
4490 | end |
4491 | describe 'with no expression' do |
4492 | table = Arel::Table.new :users |
4493 | table[:id].count.over.to_sql.must_be_like %{ |
4494 | COUNT("users"."id") OVER () |
4495 | } |
4496 | end |
4497 | end |
4498 | describe 'with expression' do |
4499 | table = Arel::Table.new :users |
4500 | } |
4501 | end |
4502 | end |
4503 | describe 'equality' do |
4504 | array = [ |
4505 | Arel::Nodes::Over.new('foo', 'bar'), |
4506 | Arel::Nodes::Over.new('foo', 'bar') |
4507 | ] |
4508 | assert_equal 1, array.uniq.size |
4509 | end |
4510 | array = [ |
4511 | Arel::Nodes::Over.new('foo', 'bar'), |
4512 | Arel::Nodes::Over.new('foo', 'baz') |
4513 | ] |
4514 | assert_equal 2, array.uniq.size |
4515 | end |
4516 | end |
4517 | end |
4518 | require 'helper' |
4519 | module Arel |
4520 | module Nodes |
4521 | class TestSelectCore Minitest::Test |
4522 | def test_clone |
4523 | core = Arel::Nodes::SelectCore.new |
4524 | core.froms = %w[a b c] |
4525 | core.projections = %w[d e f] |
4526 | core.wheres = %w[g h i] |
4527 | dolly = core.clone |
4528 | assert_equal core.froms, dolly.froms |
4529 | assert_equal core.projections, dolly.projections |
4530 | assert_equal core.wheres, dolly.wheres |
4531 | refute_same core.froms, dolly.froms |
4532 | refute_same core.projections, dolly.projections |
4533 | refute_same core.wheres, dolly.wheres |
4534 | end |
4535 | def test_set_quantifier |
4536 | core = Arel::Nodes::SelectCore.new |
4537 | core.set_quantifier = Arel::Nodes::Distinct.new |
4538 | end |
4539 | def test_equality_with_same_ivars |
4540 | core1 = SelectCore.new |
4541 | core1.froms = %w[a b c] |
4542 | core1.projections = %w[d e f] |
4543 | core1.wheres = %w[g h i] |
4544 | core1.groups = %w[j k l] |
4545 | core1.windows = %w[m n o] |
4546 | core1.havings = %w[p q r] |
4547 | core2 = SelectCore.new |
4548 | core2.froms = %w[a b c] |
4549 | core2.projections = %w[d e f] |
4550 | core2.wheres = %w[g h i] |
4551 | core2.groups = %w[j k l] |
4552 | core2.windows = %w[m n o] |
4553 | core2.havings = %w[p q r] |
4554 | array = [core1, core2] |
4555 | assert_equal 1, array.uniq.size |
4556 | end |
4557 | def test_inequality_with_different_ivars |
4558 | core1 = SelectCore.new |
4559 | core1.froms = %w[a b c] |
4560 | core1.projections = %w[d e f] |
4561 | core1.wheres = %w[g h i] |
4562 | core1.groups = %w[j k l] |
4563 | core1.windows = %w[m n o] |
4564 | core1.havings = %w[p q r] |
4565 | core2 = SelectCore.new |
4566 | core2.froms = %w[a b c] |
4567 | core2.projections = %w[d e f] |
4568 | core2.wheres = %w[g h i] |
4569 | core2.groups = %w[j k l] |
4570 | core2.windows = %w[m n o] |
4571 | core2.havings = %w[l o l] |
4572 | array = [core1, core2] |
4573 | assert_equal 2, array.uniq.size |
4574 | end |
4575 | end |
4576 | end |
4577 | end |
4578 | require 'helper' |
4579 | describe Arel::Nodes::SelectStatement do |
4580 | describe "#clone" do |
4581 | dolly = statement.clone |
4582 | dolly.cores.must_equal statement.cores |
4583 | dolly.cores.wont_be_same_as statement.cores |
4584 | end |
4585 | end |
4586 | describe 'equality' do |
4587 | statement1.offset = 1 |
4588 | statement1.limit = 2 |
4589 | statement1.lock = false |
4590 | statement1.orders = %w[x y z] |
4591 | statement1.with = 'zomg' |
4592 | statement2.offset = 1 |
4593 | statement2.limit = 2 |
4594 | statement2.lock = false |
4595 | statement2.orders = %w[x y z] |
4596 | statement2.with = 'zomg' |
4597 | array = [statement1, statement2] |
4598 | assert_equal 1, array.uniq.size |
4599 | end |
4600 | statement1.offset = 1 |
4601 | statement1.limit = 2 |
4602 | statement1.lock = false |
4603 | statement1.orders = %w[x y z] |
4604 | statement1.with = 'zomg' |
4605 | statement2.offset = 1 |
4606 | statement2.limit = 2 |
4607 | statement2.lock = false |
4608 | statement2.orders = %w[x y z] |
4609 | statement2.with = 'wth' |
4610 | array = [statement1, statement2] |
4611 | assert_equal 2, array.uniq.size |
4612 | end |
4613 | end |
4614 | end |
4615 | require 'helper' |
4616 | require 'yaml' |
4617 | module Arel |
4618 | module Nodes |
4619 | describe 'sql literal' do |
4620 | before do |
4621 | end |
4622 | def compile node |
4623 | end |
4624 | describe 'sql' do |
4625 | sql = Arel.sql 'foo' |
4626 | sql.must_be_kind_of Arel::Nodes::SqlLiteral |
4627 | end |
4628 | end |
4629 | describe 'count' do |
4630 | node = SqlLiteral.new('*').count |
4631 | compile(node).must_be_like %{ COUNT(*) } |
4632 | end |
4633 | node = SqlLiteral.new('*').count true |
4634 | compile(node).must_be_like %{ COUNT(DISTINCT *) } |
4635 | end |
4636 | end |
4637 | describe 'equality' do |
4638 | node = SqlLiteral.new('foo').eq(1) |
4639 | compile(node).must_be_like %{ foo = 1 } |
4640 | end |
4641 | assert_equal 1, array.uniq.size |
4642 | end |
4643 | assert_equal 2, array.uniq.size |
4644 | end |
4645 | end |
4646 | describe 'grouped "or" equality' do |
4647 | node = SqlLiteral.new('foo').eq_any([1,2]) |
4648 | end |
4649 | end |
4650 | describe 'grouped "and" equality' do |
4651 | node = SqlLiteral.new('foo').eq_all([1,2]) |
4652 | end |
4653 | end |
4654 | describe 'serialization' do |
4655 | yaml_literal = SqlLiteral.new('foo').to_yaml |
4656 | assert_equal('foo', YAML.load(yaml_literal)) |
4657 | end |
4658 | end |
4659 | end |
4660 | end |
4661 | end |
4662 | require 'helper' |
4663 | describe Arel::Nodes::Sum do |
4664 | describe "as" do |
4665 | table = Arel::Table.new :users |
4666 | table[:id].sum.as('foo').to_sql.must_be_like %{ |
4667 | SUM("users"."id") AS foo |
4668 | } |
4669 | end |
4670 | end |
4671 | describe 'equality' do |
4672 | assert_equal 1, array.uniq.size |
4673 | end |
4674 | assert_equal 2, array.uniq.size |
4675 | end |
4676 | end |
4677 | end |
4678 | require 'helper' |
4679 | require 'ostruct' |
4680 | module Arel |
4681 | module Nodes |
4682 | describe 'table alias' do |
4683 | describe 'equality' do |
4684 | relation1 = Table.new(:users) |
4685 | node1 = TableAlias.new relation1, :foo |
4686 | relation2 = Table.new(:users) |
4687 | node2 = TableAlias.new relation2, :foo |
4688 | array = [node1, node2] |
4689 | assert_equal 1, array.uniq.size |
4690 | end |
4691 | relation1 = Table.new(:users) |
4692 | node1 = TableAlias.new relation1, :foo |
4693 | relation2 = Table.new(:users) |
4694 | node2 = TableAlias.new relation2, :bar |
4695 | array = [node1, node2] |
4696 | assert_equal 2, array.uniq.size |
4697 | end |
4698 | end |
4699 | end |
4700 | end |
4701 | end |
4702 | require 'helper' |
4703 | module Arel |
4704 | module Nodes |
4705 | describe 'True' do |
4706 | describe 'equality' do |
4707 | array = [True.new, True.new] |
4708 | assert_equal 1, array.uniq.size |
4709 | end |
4710 | array = [True.new, Node.new] |
4711 | assert_equal 2, array.uniq.size |
4712 | end |
4713 | end |
4714 | end |
4715 | end |
4716 | end |
4717 | require 'helper' |
4718 | describe Arel::Nodes::UpdateStatement do |
4719 | describe "#clone" do |
4720 | statement = Arel::Nodes::UpdateStatement.new |
4721 | statement.wheres = %w[a b c] |
4722 | statement.values = %w[x y z] |
4723 | dolly = statement.clone |
4724 | dolly.wheres.must_equal statement.wheres |
4725 | dolly.wheres.wont_be_same_as statement.wheres |
4726 | dolly.values.must_equal statement.values |
4727 | dolly.values.wont_be_same_as statement.values |
4728 | end |
4729 | end |
4730 | describe 'equality' do |
4731 | statement1 = Arel::Nodes::UpdateStatement.new |
4732 | statement1.relation = 'zomg' |
4733 | statement1.wheres = 2 |
4734 | statement1.values = false |
4735 | statement1.orders = %w[x y z] |
4736 | statement1.limit = 42 |
4737 | statement1.key = 'zomg' |
4738 | statement2 = Arel::Nodes::UpdateStatement.new |
4739 | statement2.relation = 'zomg' |
4740 | statement2.wheres = 2 |
4741 | statement2.values = false |
4742 | statement2.orders = %w[x y z] |
4743 | statement2.limit = 42 |
4744 | statement2.key = 'zomg' |
4745 | array = [statement1, statement2] |
4746 | assert_equal 1, array.uniq.size |
4747 | end |
4748 | statement1 = Arel::Nodes::UpdateStatement.new |
4749 | statement1.relation = 'zomg' |
4750 | statement1.wheres = 2 |
4751 | statement1.values = false |
4752 | statement1.orders = %w[x y z] |
4753 | statement1.limit = 42 |
4754 | statement1.key = 'zomg' |
4755 | statement2 = Arel::Nodes::UpdateStatement.new |
4756 | statement2.relation = 'zomg' |
4757 | statement2.wheres = 2 |
4758 | statement2.values = false |
4759 | statement2.orders = %w[x y z] |
4760 | statement2.limit = 42 |
4761 | statement2.key = 'wth' |
4762 | array = [statement1, statement2] |
4763 | assert_equal 2, array.uniq.size |
4764 | end |
4765 | end |
4766 | end |
4767 | require 'helper' |
4768 | module Arel |
4769 | module Nodes |
4770 | describe 'Window' do |
4771 | describe 'equality' do |
4772 | window1 = Window.new |
4773 | window1.orders = [1, 2] |
4774 | window1.partitions = [1] |
4775 | window1.frame 3 |
4776 | window2 = Window.new |
4777 | window2.orders = [1, 2] |
4778 | window2.partitions = [1] |
4779 | window2.frame 3 |
4780 | array = [window1, window2] |
4781 | assert_equal 1, array.uniq.size |
4782 | end |
4783 | window1 = Window.new |
4784 | window1.orders = [1, 2] |
4785 | window1.partitions = [1] |
4786 | window1.frame 3 |
4787 | window2 = Window.new |
4788 | window2.orders = [1, 2] |
4789 | window1.partitions = [1] |
4790 | window2.frame 4 |
4791 | array = [window1, window2] |
4792 | assert_equal 2, array.uniq.size |
4793 | end |
4794 | end |
4795 | end |
4796 | describe 'NamedWindow' do |
4797 | describe 'equality' do |
4798 | window1 = NamedWindow.new 'foo' |
4799 | window1.orders = [1, 2] |
4800 | window1.partitions = [1] |
4801 | window1.frame 3 |
4802 | window2 = NamedWindow.new 'foo' |
4803 | window2.orders = [1, 2] |
4804 | window2.partitions = [1] |
4805 | window2.frame 3 |
4806 | array = [window1, window2] |
4807 | assert_equal 1, array.uniq.size |
4808 | end |
4809 | window1 = NamedWindow.new 'foo' |
4810 | window1.orders = [1, 2] |
4811 | window1.partitions = [1] |
4812 | window1.frame 3 |
4813 | window2 = NamedWindow.new 'bar' |
4814 | window2.orders = [1, 2] |
4815 | window2.partitions = [1] |
4816 | window2.frame 3 |
4817 | array = [window1, window2] |
4818 | assert_equal 2, array.uniq.size |
4819 | end |
4820 | end |
4821 | end |
4822 | describe 'CurrentRow' do |
4823 | describe 'equality' do |
4824 | array = [CurrentRow.new, CurrentRow.new] |
4825 | assert_equal 1, array.uniq.size |
4826 | end |
4827 | array = [CurrentRow.new, Node.new] |
4828 | assert_equal 2, array.uniq.size |
4829 | end |
4830 | end |
4831 | end |
4832 | end |
4833 | endmodule FakeRecord |
4834 | class Column Struct.new(:name, :type) |
4835 | end |
4836 | class Connection |
4837 | attr_reader :tables |
4838 | attr_accessor :visitor |
4839 | def initialize(visitor = nil) |
4840 | @tables = %w{ users photos developers products} |
4841 | @columns = { |
4842 | 'users' = [ |
4843 | Column.new('id', :integer), |
4844 | Column.new('name', :string), |
4845 | Column.new('bool', :boolean), |
4846 | Column.new('created_at', :date) |
4847 | ], |
4848 | 'products' = [ |
4849 | Column.new('id', :integer), |
4850 | Column.new('price', :decimal) |
4851 | ] |
4852 | } |
4853 | @columns_hash = { |
4854 | } |
4855 | @primary_keys = { |
4856 | 'users' = 'id', |
4857 | 'products' = 'id' |
4858 | } |
4859 | @visitor = visitor |
4860 | end |
4861 | def columns_hash table_name |
4862 | @columns_hash[table_name] |
4863 | end |
4864 | def primary_key name |
4865 | @primary_keys[name.to_s] |
4866 | end |
4867 | def table_exists? name |
4868 | @tables.include? name.to_s |
4869 | end |
4870 | def columns name, message = nil |
4871 | @columns[name.to_s] |
4872 | end |
4873 | def quote_table_name name |
4874 | "\"#{name.to_s}\"" |
4875 | end |
4876 | def quote_column_name name |
4877 | "\"#{name.to_s}\"" |
4878 | end |
4879 | def schema_cache |
4880 | self |
4881 | end |
4882 | def quote thing, column = nil |
4883 | if column && !thing.nil? |
4884 | case column.type |
4885 | when :integer |
4886 | thing = thing.to_i |
4887 | when :string |
4888 | thing = thing.to_s |
4889 | end |
4890 | end |
4891 | case thing |
4892 | when DateTime |
4893 | "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'" |
4894 | when Date |
4895 | "'#{thing.strftime("%Y-%m-%d")}'" |
4896 | when true |
4897 | "'t'" |
4898 | when false |
4899 | "'f'" |
4900 | when nil |
4901 | 'NULL' |
4902 | when Numeric |
4903 | thing |
4904 | else |
4905 | "'#{thing.to_s.gsub("'", "\\\\'")}'" |
4906 | end |
4907 | end |
4908 | end |
4909 | class ConnectionPool |
4910 | class Spec Struct.new(:config) |
4911 | end |
4912 | attr_reader :spec, :connection |
4913 | def initialize |
4914 | @spec = Spec.new(:adapter = 'america') |
4915 | @connection = Connection.new |
4916 | end |
4917 | def with_connection |
4918 | yield connection |
4919 | end |
4920 | def table_exists? name |
4921 | connection.tables.include? name.to_s |
4922 | end |
4923 | def columns_hash |
4924 | connection.columns_hash |
4925 | end |
4926 | def schema_cache |
4927 | connection |
4928 | end |
4929 | def quote thing, column = nil |
4930 | connection.quote thing, column |
4931 | end |
4932 | end |
4933 | class Base |
4934 | attr_accessor :connection_pool |
4935 | def initialize |
4936 | @connection_pool = ConnectionPool.new |
4937 | end |
4938 | def connection |
4939 | connection_pool.connection |
4940 | end |
4941 | end |
4942 | end |
4943 | require 'helper' |
4944 | module Arel |
4945 | describe 'Attributes' do |
4946 | relation = Table.new(:users) |
4947 | attribute = relation[:foo] |
4948 | node = attribute.lower |
4949 | assert_equal 'LOWER', node.name |
4950 | assert_equal [attribute], node.expressions |
4951 | end |
4952 | describe 'equality' do |
4953 | assert_equal 1, array.uniq.size |
4954 | end |
4955 | assert_equal 2, array.uniq.size |
4956 | end |
4957 | end |
4958 | describe 'for' do |
4959 | column = Struct.new(:type).new :crazy |
4960 | end |
4961 | [:string, :text, :binary].each do |type| |
4962 | column = Struct.new(:type).new type |
4963 | end |
4964 | end |
4965 | column = Struct.new(:type).new :integer |
4966 | end |
4967 | column = Struct.new(:type).new :float |
4968 | end |
4969 | column = Struct.new(:type).new :decimal |
4970 | end |
4971 | column = Struct.new(:type).new :boolean |
4972 | end |
4973 | column = Struct.new(:type).new type |
4974 | end |
4975 | end |
4976 | end |
4977 | end |
4978 | end |
4979 | require 'helper' |
4980 | module Arel |
4981 | class FakeCrudder SelectManager |
4982 | class FakeEngine |
4983 | def initialize |
4984 | @calls = [] |
4985 | @connection_pool = self |
4986 | @spec = self |
4987 | @config = { :adapter = 'sqlite3' } |
4988 | end |
4989 | def connection; self end |
4990 | def method_missing name, *args |
4991 | @calls [name, args] |
4992 | end |
4993 | end |
4994 | include Crud |
4995 | attr_reader :engine |
4996 | attr_accessor :ctx |
4997 | def initialize engine = FakeEngine.new |
4998 | super |
4999 | end |
5000 | end |
5001 | describe 'crud' do |
5002 | describe 'insert' do |
5003 | table = Table.new :users |
5004 | fc = FakeCrudder.new |
5005 | fc.from table |
5006 | im = fc.compile_insert [[table[:id], 'foo']] |
5007 | assert_instance_of Arel::InsertManager, im |
5008 | end |
5009 | end |
5010 | describe 'update' do |
5011 | table = Table.new :users |
5012 | fc = FakeCrudder.new |
5013 | fc.from table |
5014 | assert_instance_of Arel::UpdateManager, stmt |
5015 | end |
5016 | end |
5017 | describe 'delete' do |
5018 | table = Table.new :users |
5019 | fc = FakeCrudder.new |
5020 | fc.from table |
5021 | stmt = fc.compile_delete |
5022 | assert_instance_of Arel::DeleteManager, stmt |
5023 | end |
5024 | end |
5025 | end |
5026 | end |
5027 | require 'helper' |
5028 | module Arel |
5029 | describe 'delete manager' do |
5030 | describe 'new' do |
5031 | Arel::DeleteManager.new |
5032 | end |
5033 | end |
5034 | describe 'from' do |
5035 | table = Table.new(:users) |
5036 | dm = Arel::DeleteManager.new |
5037 | dm.from table |
5038 | dm.to_sql.must_be_like %{ DELETE FROM "users" } |
5039 | end |
5040 | table = Table.new(:users) |
5041 | dm = Arel::DeleteManager.new |
5042 | dm.from(table).must_equal dm |
5043 | end |
5044 | end |
5045 | describe 'where' do |
5046 | table = Table.new(:users) |
5047 | dm = Arel::DeleteManager.new |
5048 | dm.from table |
5049 | dm.where table[:id].eq(10) |
5050 | end |
5051 | table = Table.new(:users) |
5052 | dm = Arel::DeleteManager.new |
5053 | dm.where(table[:id].eq(10)).must_equal dm |
5054 | end |
5055 | end |
5056 | end |
5057 | end |
5058 | require 'helper' |
5059 | module Arel |
5060 | module FactoryMethods |
5061 | class TestFactoryMethods Minitest::Test |
5062 | class Factory |
5063 | include Arel::FactoryMethods |
5064 | end |
5065 | def setup |
5066 | @factory = Factory.new |
5067 | end |
5068 | def test_create_join |
5069 | join = @factory.create_join :one, :two |
5070 | assert_kind_of Nodes::Join, join |
5071 | assert_equal :two, join.right |
5072 | end |
5073 | def test_create_on |
5074 | on = @factory.create_on :one |
5075 | assert_instance_of Nodes::On, on |
5076 | assert_equal :one, on.expr |
5077 | end |
5078 | def test_create_true |
5079 | true_node = @factory.create_true |
5080 | assert_instance_of Nodes::True, true_node |
5081 | end |
5082 | def test_create_false |
5083 | false_node = @factory.create_false |
5084 | assert_instance_of Nodes::False, false_node |
5085 | end |
5086 | def test_lower |
5087 | lower = @factory.lower :one |
5088 | assert_instance_of Nodes::NamedFunction, lower |
5089 | assert_equal 'LOWER', lower.name |
5090 | end |
5091 | end |
5092 | end |
5093 | end |
5094 | require 'helper' |
5095 | module Arel |
5096 | describe 'insert manager' do |
5097 | describe 'new' do |
5098 | Arel::InsertManager.new |
5099 | end |
5100 | end |
5101 | describe 'insert' do |
5102 | manager = Arel::InsertManager.new |
5103 | assert_kind_of Arel::Nodes::Values, values |
5104 | assert_equal %w{ a b }, values.left |
5105 | assert_equal %w{ c d }, values.right |
5106 | end |
5107 | manager = Arel::InsertManager.new |
5108 | manager.into Table.new(:users) |
5109 | manager.to_sql.must_be_like %{ |
5110 | INSERT INTO \"users\" VALUES (*) |
5111 | } |
5112 | end |
5113 | table = Table.new(:users) |
5114 | manager = Arel::InsertManager.new |
5115 | manager.insert [[table[:bool], false]] |
5116 | manager.to_sql.must_be_like %{ |
5117 | INSERT INTO "users" ("bool") VALUES ('f') |
5118 | } |
5119 | end |
5120 | table = Table.new(:users) |
5121 | manager = Arel::InsertManager.new |
5122 | manager.insert [[table[:id], nil]] |
5123 | manager.to_sql.must_be_like %{ |
5124 | INSERT INTO "users" ("id") VALUES (NULL) |
5125 | } |
5126 | end |
5127 | table = Table.new(:users) |
5128 | manager = Arel::InsertManager.new |
5129 | time = Time.now |
5130 | attribute = table[:created_at] |
5131 | manager.insert [[attribute, time]] |
5132 | manager.to_sql.must_be_like %{ |
5133 | } |
5134 | end |
5135 | table = Table.new(:users) |
5136 | manager = Arel::InsertManager.new |
5137 | manager.into table |
5138 | manager.to_sql.must_be_like %{ |
5139 | } |
5140 | end |
5141 | table = Table.new(:users) |
5142 | manager = Arel::InsertManager.new |
5143 | manager.to_sql.must_be_like %{ |
5144 | } |
5145 | end |
5146 | table = Table.new(:users) |
5147 | manager = Arel::InsertManager.new |
5148 | manager.insert [[table[:id], 1]] |
5149 | manager.insert [] |
5150 | manager.to_sql.must_be_like %{ |
5151 | INSERT INTO "users" ("id") VALUES (1) |
5152 | } |
5153 | end |
5154 | end |
5155 | describe 'into' do |
5156 | manager = Arel::InsertManager.new |
5157 | end |
5158 | table = Table.new :users |
5159 | manager = Arel::InsertManager.new |
5160 | manager.into table |
5161 | manager.to_sql.must_be_like %{ |
5162 | INSERT INTO "users" |
5163 | } |
5164 | end |
5165 | end |
5166 | describe 'columns' do |
5167 | table = Table.new :users |
5168 | manager = Arel::InsertManager.new |
5169 | manager.into table |
5170 | manager.columns table[:id] |
5171 | manager.to_sql.must_be_like %{ |
5172 | INSERT INTO "users" ("id") |
5173 | } |
5174 | end |
5175 | end |
5176 | describe "values" do |
5177 | table = Table.new :users |
5178 | manager = Arel::InsertManager.new |
5179 | manager.into table |
5180 | manager.values = Nodes::Values.new [1] |
5181 | manager.to_sql.must_be_like %{ |
5182 | INSERT INTO "users" VALUES (1) |
5183 | } |
5184 | end |
5185 | end |
5186 | describe "combo" do |
5187 | table = Table.new :users |
5188 | manager = Arel::InsertManager.new |
5189 | manager.into table |
5190 | manager.values = Nodes::Values.new [1, 'aaron'] |
5191 | manager.columns table[:id] |
5192 | manager.columns table[:name] |
5193 | manager.to_sql.must_be_like %{ |
5194 | } |
5195 | end |
5196 | end |
5197 | describe "select" do |
5198 | table = Table.new :users |
5199 | manager = Arel::InsertManager.new |
5200 | manager.into table |
5201 | select = Arel::SelectManager.new |
5202 | select.project Arel.sql('1') |
5203 | select.project Arel.sql('"aaron"') |
5204 | manager.select select |
5205 | manager.columns table[:id] |
5206 | manager.columns table[:name] |
5207 | manager.to_sql.must_be_like %{ |
5208 | } |
5209 | end |
5210 | end |
5211 | end |
5212 | end |
5213 | require 'helper' |
5214 | module Arel |
5215 | describe 'select manager' do |
5216 | def test_join_sources |
5217 | manager = Arel::SelectManager.new |
5218 | assert_equal "SELECT FROM 'foo'", manager.to_sql |
5219 | end |
5220 | def test_manager_stores_bind_values |
5221 | manager = Arel::SelectManager.new |
5222 | assert_equal [], manager.bind_values |
5223 | manager.bind_values = [1] |
5224 | assert_equal [1], manager.bind_values |
5225 | end |
5226 | describe 'backwards compatibility' do |
5227 | describe 'project' do |
5228 | table = Table.new :users |
5229 | manager = Arel::SelectManager.new |
5230 | manager.project :id |
5231 | manager.from table |
5232 | manager.to_sql.must_be_like %{ |
5233 | SELECT id FROM "users" |
5234 | } |
5235 | end |
5236 | end |
5237 | describe 'order' do |
5238 | table = Table.new :users |
5239 | manager = Arel::SelectManager.new |
5240 | manager.project Nodes::SqlLiteral.new '*' |
5241 | manager.from table |
5242 | manager.order :foo |
5243 | end |
5244 | end |
5245 | describe 'group' do |
5246 | table = Table.new :users |
5247 | manager = Arel::SelectManager.new |
5248 | manager.from table |
5249 | manager.group :foo |
5250 | end |
5251 | end |
5252 | describe 'as' do |
5253 | manager = Arel::SelectManager.new |
5254 | as = manager.as(Arel.sql('foo')) |
5255 | assert_kind_of Arel::Nodes::Grouping, as.left |
5256 | assert_equal manager.ast, as.left.expr |
5257 | assert_equal 'foo', as.right |
5258 | end |
5259 | manager = Arel::SelectManager.new |
5260 | as = manager.as('foo') |
5261 | assert_kind_of Arel::Nodes::SqlLiteral, as.right |
5262 | end |
5263 | manager = Arel::SelectManager.new |
5264 | manager.project Arel.star |
5265 | manager.from Arel.sql('zomg') |
5266 | as = manager.as(Arel.sql('foo')) |
5267 | manager = Arel::SelectManager.new |
5268 | manager.project Arel.sql('name') |
5269 | manager.from as |
5270 | end |
5271 | end |
5272 | describe 'from' do |
5273 | table = Table.new :users |
5274 | manager = Arel::SelectManager.new |
5275 | manager.from table |
5276 | manager.from 'users' |
5277 | manager.project table['id'] |
5278 | end |
5279 | table = Table.new :users |
5280 | manager1 = Arel::SelectManager.new |
5281 | manager2 = Arel::SelectManager.new |
5282 | manager2.project(Arel.sql('*')) |
5283 | manager2.from table |
5284 | manager1.project Arel.sql('lol') |
5285 | as = manager2.as Arel.sql('omg') |
5286 | manager1.from(as) |
5287 | manager1.to_sql.must_be_like %{ |
5288 | SELECT lol FROM (SELECT * FROM "users") omg |
5289 | } |
5290 | end |
5291 | end |
5292 | describe 'having' do |
5293 | table = Table.new :users |
5294 | mgr = table.from |
5295 | mgr.having Arel.sql('foo') |
5296 | end |
5297 | table = Table.new :users |
5298 | mgr = table.from |
5299 | mgr.having Arel.sql('foo') |
5300 | mgr.having Arel.sql('bar') |
5301 | end |
5302 | table = Table.new :users |
5303 | mgr = table.from |
5304 | end |
5305 | end |
5306 | describe 'on' do |
5307 | table = Table.new :users |
5308 | right = table.alias |
5309 | mgr = table.from |
5310 | mgr.join(right).on("omg") |
5311 | end |
5312 | table = Table.new :users |
5313 | right = table.alias |
5314 | mgr = table.from |
5315 | mgr.join(right).on("omg", "123") |
5316 | end |
5317 | end |
5318 | end |
5319 | describe 'clone' do |
5320 | table = Table.new :users, :as = 'foo' |
5321 | mgr = table.from |
5322 | m2 = mgr.clone |
5323 | m2.project "foo" |
5324 | mgr.to_sql.wont_equal m2.to_sql |
5325 | end |
5326 | table = Table.new :users, :as = 'foo' |
5327 | mgr = table.from |
5328 | m2 = mgr.clone |
5329 | m3 = m2.clone |
5330 | m2.project "foo" |
5331 | mgr.to_sql.wont_equal m2.to_sql |
5332 | m3.to_sql.must_equal mgr.to_sql |
5333 | end |
5334 | end |
5335 | describe 'initialize' do |
5336 | table = Table.new :users, :as = 'foo' |
5337 | mgr = table.from |
5338 | mgr.skip 10 |
5339 | end |
5340 | end |
5341 | describe 'skip' do |
5342 | table = Table.new :users |
5343 | mgr = table.from |
5344 | mgr.skip 10 |
5345 | end |
5346 | table = Table.new :users |
5347 | mgr = table.from |
5348 | end |
5349 | end |
5350 | describe 'offset' do |
5351 | table = Table.new :users |
5352 | mgr = table.from |
5353 | mgr.offset = 10 |
5354 | end |
5355 | table = Table.new :users |
5356 | mgr = table.from |
5357 | mgr.offset = 10 |
5358 | mgr.offset = nil |
5359 | mgr.to_sql.must_be_like %{ SELECT FROM "users" } |
5360 | end |
5361 | table = Table.new :users |
5362 | mgr = table.from |
5363 | mgr.offset = 10 |
5364 | assert_equal 10, mgr.offset |
5365 | end |
5366 | end |
5367 | describe 'exists' do |
5368 | table = Table.new(:users) |
5369 | manager = Arel::SelectManager.new table |
5370 | manager.project Nodes::SqlLiteral.new '*' |
5371 | m2 = Arel::SelectManager.new(manager.engine) |
5372 | m2.project manager.exists |
5373 | end |
5374 | table = Table.new(:users) |
5375 | manager = Arel::SelectManager.new table |
5376 | manager.project Nodes::SqlLiteral.new '*' |
5377 | m2 = Arel::SelectManager.new(manager.engine) |
5378 | m2.project manager.exists.as('foo') |
5379 | end |
5380 | end |
5381 | describe 'union' do |
5382 | before do |
5383 | table = Table.new :users |
5384 | @m1 = Arel::SelectManager.new table |
5385 | @m1.project Arel.star |
5386 | @m1.where(table[:age].lt(18)) |
5387 | @m2 = Arel::SelectManager.new table |
5388 | @m2.project Arel.star |
5389 | @m2.where(table[:age].gt(99)) |
5390 | end |
5391 | node = @m1.union @m2 |
5392 | node.to_sql.must_be_like %{ |
5393 | } |
5394 | end |
5395 | node = @m1.union :all, @m2 |
5396 | node.to_sql.must_be_like %{ |
5397 | } |
5398 | end |
5399 | end |
5400 | describe 'intersect' do |
5401 | before do |
5402 | table = Table.new :users |
5403 | @m1 = Arel::SelectManager.new table |
5404 | @m1.project Arel.star |
5405 | @m1.where(table[:age].gt(18)) |
5406 | @m2 = Arel::SelectManager.new table |
5407 | @m2.project Arel.star |
5408 | @m2.where(table[:age].lt(99)) |
5409 | end |
5410 | node = @m1.intersect @m2 |
5411 | node.to_sql.must_be_like %{ |
5412 | } |
5413 | end |
5414 | end |
5415 | describe 'except' do |
5416 | before do |
5417 | table = Table.new :users |
5418 | @m1 = Arel::SelectManager.new table |
5419 | @m1.project Arel.star |
5420 | @m1.where(table[:age].between(18..60)) |
5421 | @m2 = Arel::SelectManager.new table |
5422 | @m2.project Arel.star |
5423 | @m2.where(table[:age].between(40..99)) |
5424 | end |
5425 | node = @m1.except @m2 |
5426 | node.to_sql.must_be_like %{ |
5427 | } |
5428 | end |
5429 | end |
5430 | describe 'with' do |
5431 | users = Table.new(:users) |
5432 | users_top = Table.new(:users_top) |
5433 | comments = Table.new(:comments) |
5434 | users_as = Arel::Nodes::As.new(users_top, top) |
5435 | select_manager.to_sql.must_be_like %{ |
5436 | } |
5437 | end |
5438 | comments = Table.new(:comments) |
5439 | comments_id = comments[:id] |
5440 | comments_parent_id = comments[:parent_id] |
5441 | replies = Table.new(:replies) |
5442 | replies_id = replies[:id] |
5443 | recursive_term = Arel::SelectManager.new |
5444 | non_recursive_term = Arel::SelectManager.new |
5445 | union = recursive_term.union(non_recursive_term) |
5446 | as_statement = Arel::Nodes::As.new replies, union |
5447 | manager = Arel::SelectManager.new |
5448 | sql = manager.to_sql |
5449 | sql.must_be_like %{ |
5450 | WITH RECURSIVE "replies" AS ( |
5451 | UNION |
5452 | ) |
5453 | SELECT * FROM "replies" |
5454 | } |
5455 | end |
5456 | end |
5457 | describe 'ast' do |
5458 | table = Table.new :users |
5459 | mgr = table.from |
5460 | assert mgr.ast |
5461 | end |
5462 | table = Table.new :users |
5463 | mgr = table.from |
5464 | mgr.project Arel.sql '*' |
5465 | mgr.from table |
5466 | mgr.ast.grep(Arel::Nodes::OuterJoin) |
5467 | end |
5468 | end |
5469 | describe 'taken' do |
5470 | manager = Arel::SelectManager.new |
5471 | manager.take 10 |
5472 | manager.taken.must_equal 10 |
5473 | end |
5474 | end |
5475 | describe 'lock' do |
5476 | table = Table.new :users |
5477 | mgr = table.from |
5478 | end |
5479 | end |
5480 | describe 'orders' do |
5481 | table = Table.new :users |
5482 | manager = Arel::SelectManager.new |
5483 | order = table[:id] |
5484 | manager.order table[:id] |
5485 | manager.orders.must_equal [order] |
5486 | end |
5487 | end |
5488 | describe 'order' do |
5489 | table = Table.new :users |
5490 | manager = Arel::SelectManager.new |
5491 | manager.project Nodes::SqlLiteral.new '*' |
5492 | manager.from table |
5493 | manager.order table[:id] |
5494 | manager.to_sql.must_be_like %{ |
5495 | SELECT * FROM "users" ORDER BY "users"."id" |
5496 | } |
5497 | end |
5498 | table = Table.new :users |
5499 | manager = Arel::SelectManager.new |
5500 | manager.project Nodes::SqlLiteral.new '*' |
5501 | manager.from table |
5502 | manager.order table[:id], table[:name] |
5503 | manager.to_sql.must_be_like %{ |
5504 | } |
5505 | end |
5506 | table = Table.new :users |
5507 | manager = Arel::SelectManager.new |
5508 | manager.order(table[:id]).must_equal manager |
5509 | end |
5510 | table = Table.new :users |
5511 | manager = Arel::SelectManager.new |
5512 | manager.project Nodes::SqlLiteral.new '*' |
5513 | manager.from table |
5514 | manager.order table[:id].desc |
5515 | manager.to_sql.must_be_like %{ |
5516 | SELECT * FROM "users" ORDER BY "users"."id" DESC |
5517 | } |
5518 | end |
5519 | end |
5520 | describe 'on' do |
5521 | left = Table.new :users |
5522 | right = left.alias |
5523 | predicate = left[:id].eq(right[:id]) |
5524 | manager = Arel::SelectManager.new |
5525 | manager.from left |
5526 | manager.join(right).on(predicate, predicate) |
5527 | manager.to_sql.must_be_like %{ |
5528 | SELECT FROM "users" |
5529 | INNER JOIN "users" "users_2" |
5530 | ON "users"."id" = "users_2"."id" AND |
5531 | "users"."id" = "users_2"."id" |
5532 | } |
5533 | end |
5534 | left = Table.new :users |
5535 | right = left.alias |
5536 | predicate = left[:id].eq(right[:id]) |
5537 | manager = Arel::SelectManager.new |
5538 | manager.from left |
5539 | manager.join(right).on( |
5540 | predicate, |
5541 | predicate, |
5542 | left[:name].eq(right[:name]) |
5543 | ) |
5544 | manager.to_sql.must_be_like %{ |
5545 | SELECT FROM "users" |
5546 | INNER JOIN "users" "users_2" |
5547 | ON "users"."id" = "users_2"."id" AND |
5548 | "users"."id" = "users_2"."id" AND |
5549 | "users"."name" = "users_2"."name" |
5550 | } |
5551 | end |
5552 | end |
5553 | relation = Arel::SelectManager.new |
5554 | assert_equal [], relation.froms |
5555 | end |
5556 | relation = Arel::SelectManager.new |
5557 | children = ['foo', 'bar', 'baz'] |
5558 | clause = relation.create_and children |
5559 | assert_kind_of Arel::Nodes::And, clause |
5560 | assert_equal children, clause.children |
5561 | end |
5562 | relation = Arel::SelectManager.new |
5563 | insert = relation.create_insert |
5564 | assert_kind_of Arel::InsertManager, insert |
5565 | end |
5566 | relation = Arel::SelectManager.new |
5567 | join = relation.create_join 'foo', 'bar' |
5568 | assert_kind_of Arel::Nodes::InnerJoin, join |
5569 | assert_equal 'foo', join.left |
5570 | assert_equal 'bar', join.right |
5571 | end |
5572 | relation = Arel::SelectManager.new |
5573 | assert_kind_of Arel::Nodes::FullOuterJoin, join |
5574 | assert_equal 'foo', join.left |
5575 | assert_equal 'bar', join.right |
5576 | end |
5577 | relation = Arel::SelectManager.new |
5578 | assert_kind_of Arel::Nodes::OuterJoin, join |
5579 | assert_equal 'foo', join.left |
5580 | assert_equal 'bar', join.right |
5581 | end |
5582 | relation = Arel::SelectManager.new |
5583 | assert_kind_of Arel::Nodes::RightOuterJoin, join |
5584 | assert_equal 'foo', join.left |
5585 | assert_equal 'bar', join.right |
5586 | end |
5587 | describe 'join' do |
5588 | left = Table.new :users |
5589 | right = left.alias |
5590 | predicate = left[:id].eq(right[:id]) |
5591 | manager = Arel::SelectManager.new |
5592 | manager.from left |
5593 | manager.join(right).on(predicate) |
5594 | manager.to_sql.must_be_like %{ |
5595 | SELECT FROM "users" |
5596 | INNER JOIN "users" "users_2" |
5597 | ON "users"."id" = "users_2"."id" |
5598 | } |
5599 | end |
5600 | left = Table.new :users |
5601 | right = left.alias |
5602 | predicate = left[:id].eq(right[:id]) |
5603 | manager = Arel::SelectManager.new |
5604 | manager.from left |
5605 | manager.to_sql.must_be_like %{ |
5606 | SELECT FROM "users" |
5607 | LEFT OUTER JOIN "users" "users_2" |
5608 | ON "users"."id" = "users_2"."id" |
5609 | } |
5610 | end |
5611 | manager = Arel::SelectManager.new |
5612 | manager.join(nil).must_equal manager |
5613 | end |
5614 | end |
5615 | describe 'outer join' do |
5616 | left = Table.new :users |
5617 | right = left.alias |
5618 | predicate = left[:id].eq(right[:id]) |
5619 | manager = Arel::SelectManager.new |
5620 | manager.from left |
5621 | manager.outer_join(right).on(predicate) |
5622 | manager.to_sql.must_be_like %{ |
5623 | SELECT FROM "users" |
5624 | LEFT OUTER JOIN "users" "users_2" |
5625 | ON "users"."id" = "users_2"."id" |
5626 | } |
5627 | end |
5628 | manager = Arel::SelectManager.new |
5629 | manager.outer_join(nil).must_equal manager |
5630 | end |
5631 | end |
5632 | describe 'joins' do |
5633 | table = Table.new :users |
5634 | aliaz = table.alias |
5635 | manager = Arel::SelectManager.new |
5636 | manager.to_sql |
5637 | end |
5638 | table = Table.new :users |
5639 | aliaz = table.alias |
5640 | manager = Arel::SelectManager.new |
5641 | manager.to_sql |
5642 | end |
5643 | users = Table.new :users |
5644 | comments = Table.new :comments |
5645 | counts = comments.from. |
5646 | group(comments[:user_id]). |
5647 | project( |
5648 | comments[:user_id].as("user_id"), |
5649 | comments[:user_id].count.as("count") |
5650 | ).as("counts") |
5651 | joins.to_sql.must_be_like %{ |
5652 | } |
5653 | end |
5654 | left = Table.new :users |
5655 | right = left.alias |
5656 | predicate = left[:id].eq(right[:id]) |
5657 | mgr = left.join(right) |
5658 | mgr.project Nodes::SqlLiteral.new('*') |
5659 | mgr.on(predicate).must_equal mgr |
5660 | mgr.to_sql.must_be_like %{ |
5661 | SELECT * FROM "users" |
5662 | INNER JOIN "users" "users_2" |
5663 | ON "users"."id" = "users_2"."id" |
5664 | } |
5665 | end |
5666 | manager = Arel::SelectManager.new |
5667 | assert_match "'hello'", manager.to_sql |
5668 | end |
5669 | end |
5670 | describe 'group' do |
5671 | table = Table.new :users |
5672 | manager = Arel::SelectManager.new |
5673 | manager.from table |
5674 | manager.group table[:id] |
5675 | manager.to_sql.must_be_like %{ |
5676 | SELECT FROM "users" GROUP BY "users"."id" |
5677 | } |
5678 | end |
5679 | table = Table.new :users |
5680 | manager = Arel::SelectManager.new |
5681 | manager.group(table[:id]).must_equal manager |
5682 | end |
5683 | table = Table.new :users |
5684 | manager = Arel::SelectManager.new |
5685 | manager.from table |
5686 | manager.group table[:id], table[:name] |
5687 | manager.to_sql.must_be_like %{ |
5688 | } |
5689 | end |
5690 | table = Table.new :users |
5691 | manager = Arel::SelectManager.new |
5692 | manager.from table |
5693 | manager.group 'foo' |
5694 | end |
5695 | end |
5696 | describe 'window definition' do |
5697 | table = Table.new :users |
5698 | manager = Arel::SelectManager.new |
5699 | manager.from table |
5700 | manager.window('a_window') |
5701 | manager.to_sql.must_be_like %{ |
5702 | SELECT FROM "users" WINDOW "a_window" AS () |
5703 | } |
5704 | end |
5705 | table = Table.new :users |
5706 | manager = Arel::SelectManager.new |
5707 | manager.from table |
5708 | manager.to_sql.must_be_like %{ |
5709 | } |
5710 | end |
5711 | table = Table.new :users |
5712 | manager = Arel::SelectManager.new |
5713 | manager.from table |
5714 | manager.to_sql.must_be_like %{ |
5715 | } |
5716 | end |
5717 | table = Table.new :users |
5718 | manager = Arel::SelectManager.new |
5719 | manager.from table |
5720 | manager.to_sql.must_be_like %{ |
5721 | } |
5722 | end |
5723 | table = Table.new :users |
5724 | manager = Arel::SelectManager.new |
5725 | manager.from table |
5726 | manager.to_sql.must_be_like %{ |
5727 | ORDER BY "users"."foo" ASC) |
5728 | } |
5729 | end |
5730 | table = Table.new :users |
5731 | manager = Arel::SelectManager.new |
5732 | manager.from table |
5733 | manager.to_sql.must_be_like %{ |
5734 | } |
5735 | end |
5736 | table = Table.new :users |
5737 | manager = Arel::SelectManager.new |
5738 | manager.from table |
5739 | manager.to_sql.must_be_like %{ |
5740 | } |
5741 | end |
5742 | table = Table.new :users |
5743 | manager = Arel::SelectManager.new |
5744 | manager.from table |
5745 | manager.to_sql.must_be_like %{ |
5746 | } |
5747 | end |
5748 | table = Table.new :users |
5749 | manager = Arel::SelectManager.new |
5750 | manager.from table |
5751 | manager.to_sql.must_be_like %{ |
5752 | } |
5753 | end |
5754 | table = Table.new :users |
5755 | manager = Arel::SelectManager.new |
5756 | manager.from table |
5757 | manager.to_sql.must_be_like %{ |
5758 | } |
5759 | end |
5760 | table = Table.new :users |
5761 | manager = Arel::SelectManager.new |
5762 | manager.from table |
5763 | manager.to_sql.must_be_like %{ |
5764 | } |
5765 | end |
5766 | table = Table.new :users |
5767 | manager = Arel::SelectManager.new |
5768 | manager.from table |
5769 | window = manager.window('a_window') |
5770 | window.frame( |
5771 | Arel::Nodes::Between.new( |
5772 | window.rows, |
5773 | Nodes::And.new([ |
5774 | Arel::Nodes::Preceding.new, |
5775 | Arel::Nodes::CurrentRow.new |
5776 | ]))) |
5777 | manager.to_sql.must_be_like %{ |
5778 | } |
5779 | end |
5780 | table = Table.new :users |
5781 | manager = Arel::SelectManager.new |
5782 | manager.from table |
5783 | manager.to_sql.must_be_like %{ |
5784 | } |
5785 | end |
5786 | table = Table.new :users |
5787 | manager = Arel::SelectManager.new |
5788 | manager.from table |
5789 | manager.to_sql.must_be_like %{ |
5790 | } |
5791 | end |
5792 | table = Table.new :users |
5793 | manager = Arel::SelectManager.new |
5794 | manager.from table |
5795 | manager.to_sql.must_be_like %{ |
5796 | } |
5797 | end |
5798 | table = Table.new :users |
5799 | manager = Arel::SelectManager.new |
5800 | manager.from table |
5801 | manager.to_sql.must_be_like %{ |
5802 | } |
5803 | end |
5804 | table = Table.new :users |
5805 | manager = Arel::SelectManager.new |
5806 | manager.from table |
5807 | manager.to_sql.must_be_like %{ |
5808 | } |
5809 | end |
5810 | table = Table.new :users |
5811 | manager = Arel::SelectManager.new |
5812 | manager.from table |
5813 | window = manager.window('a_window') |
5814 | window.frame( |
5815 | Arel::Nodes::Between.new( |
5816 | window.range, |
5817 | Nodes::And.new([ |
5818 | Arel::Nodes::Preceding.new, |
5819 | Arel::Nodes::CurrentRow.new |
5820 | ]))) |
5821 | manager.to_sql.must_be_like %{ |
5822 | } |
5823 | end |
5824 | end |
5825 | describe 'delete' do |
5826 | table = Table.new :users |
5827 | manager = Arel::SelectManager.new |
5828 | manager.from table |
5829 | stmt = manager.compile_delete |
5830 | stmt.to_sql.must_be_like %{ DELETE FROM "users" } |
5831 | end |
5832 | table = Table.new :users |
5833 | manager = Arel::SelectManager.new |
5834 | manager.from table |
5835 | manager.where table[:id].eq 10 |
5836 | stmt = manager.compile_delete |
5837 | stmt.to_sql.must_be_like %{ |
5838 | DELETE FROM "users" WHERE "users"."id" = 10 |
5839 | } |
5840 | end |
5841 | end |
5842 | describe 'where_sql' do |
5843 | table = Table.new :users |
5844 | manager = Arel::SelectManager.new |
5845 | manager.from table |
5846 | manager.where table[:id].eq 10 |
5847 | end |
5848 | table = Table.new :users |
5849 | manager = Arel::SelectManager.new |
5850 | manager.from table |
5851 | manager.where_sql.must_be_nil |
5852 | end |
5853 | end |
5854 | describe 'update' do |
5855 | table = Table.new :users |
5856 | manager = Arel::SelectManager.new |
5857 | manager.from table |
5858 | stmt.to_sql.must_be_like %{ |
5859 | UPDATE "users" SET "id" = 1 |
5860 | } |
5861 | end |
5862 | table = Table.new :users |
5863 | manager = Arel::SelectManager.new |
5864 | manager.from table |
5865 | end |
5866 | table = Table.new :users |
5867 | manager = Arel::SelectManager.new |
5868 | manager.from table |
5869 | manager.take 1 |
5870 | stmt.key = table['id'] |
5871 | stmt.to_sql.must_be_like %{ |
5872 | UPDATE "users" SET foo = bar |
5873 | } |
5874 | end |
5875 | table = Table.new :users |
5876 | manager = Arel::SelectManager.new |
5877 | manager.from table |
5878 | manager.order :foo |
5879 | stmt.key = table['id'] |
5880 | stmt.to_sql.must_be_like %{ |
5881 | UPDATE "users" SET foo = bar |
5882 | } |
5883 | end |
5884 | table = Table.new :users |
5885 | manager = Arel::SelectManager.new |
5886 | manager.where table[:id].eq 10 |
5887 | manager.from table |
5888 | stmt.to_sql.must_be_like %{ |
5889 | } |
5890 | end |
5891 | table = Table.new :users |
5892 | manager = Arel::SelectManager.new |
5893 | manager.where table[:foo].eq 10 |
5894 | manager.take 42 |
5895 | manager.from table |
5896 | stmt.to_sql.must_be_like %{ |
5897 | } |
5898 | end |
5899 | end |
5900 | describe 'project' do |
5901 | manager = Arel::SelectManager.new |
5902 | manager.project Nodes::SqlLiteral.new '*' |
5903 | manager.to_sql.must_be_like %{ SELECT * } |
5904 | end |
5905 | manager = Arel::SelectManager.new |
5906 | manager.project Nodes::SqlLiteral.new('foo'), |
5907 | Nodes::SqlLiteral.new('bar') |
5908 | manager.to_sql.must_be_like %{ SELECT foo, bar } |
5909 | end |
5910 | manager = Arel::SelectManager.new |
5911 | manager.project '*' |
5912 | manager.to_sql.must_be_like %{ SELECT * } |
5913 | end |
5914 | end |
5915 | describe 'projections' do |
5916 | manager = Arel::SelectManager.new |
5917 | manager.project Arel.sql('foo'), Arel.sql('bar') |
5918 | end |
5919 | end |
5920 | describe 'projections=' do |
5921 | manager = Arel::SelectManager.new |
5922 | manager.project Arel.sql('foo') |
5923 | manager.projections = [Arel.sql('bar')] |
5924 | manager.to_sql.must_be_like %{ SELECT bar } |
5925 | end |
5926 | end |
5927 | describe 'take' do |
5928 | table = Table.new :users |
5929 | manager = Arel::SelectManager.new |
5930 | manager.from(table).project(table['id']) |
5931 | manager.where(table['id'].eq(1)) |
5932 | manager.take 1 |
5933 | manager.to_sql.must_be_like %{ |
5934 | SELECT "users"."id" |
5935 | FROM "users" |
5936 | WHERE "users"."id" = 1 |
5937 | LIMIT 1 |
5938 | } |
5939 | end |
5940 | manager = Arel::SelectManager.new |
5941 | manager.take(1).must_equal manager |
5942 | end |
5943 | manager = Arel::SelectManager.new |
5944 | manager.limit = 10 |
5945 | assert_match('LIMIT', manager.to_sql) |
5946 | manager.limit = nil |
5947 | refute_match('LIMIT', manager.to_sql) |
5948 | end |
5949 | end |
5950 | describe 'where' do |
5951 | table = Table.new :users |
5952 | manager = Arel::SelectManager.new |
5953 | manager.from(table).project(table['id']) |
5954 | manager.where(table['id'].eq(1)) |
5955 | manager.to_sql.must_be_like %{ |
5956 | SELECT "users"."id" |
5957 | FROM "users" |
5958 | WHERE "users"."id" = 1 |
5959 | } |
5960 | end |
5961 | table = Table.new :users |
5962 | manager = Arel::SelectManager.new |
5963 | manager.from(table) |
5964 | end |
5965 | end |
5966 | describe 'from' do |
5967 | table = Table.new :users |
5968 | manager = Arel::SelectManager.new |
5969 | manager.from table |
5970 | manager.project table['id'] |
5971 | end |
5972 | table = Table.new :users |
5973 | manager = Arel::SelectManager.new |
5974 | end |
5975 | end |
5976 | describe 'source' do |
5977 | manager = Arel::SelectManager.new |
5978 | end |
5979 | end |
5980 | describe 'distinct' do |
5981 | manager = Arel::SelectManager.new |
5982 | manager.distinct |
5983 | manager.distinct(false) |
5984 | end |
5985 | manager = Arel::SelectManager.new |
5986 | manager.distinct.must_equal manager |
5987 | manager.distinct(false).must_equal manager |
5988 | end |
5989 | end |
5990 | describe 'distinct_on' do |
5991 | manager = Arel::SelectManager.new |
5992 | table = Table.new :users |
5993 | manager.distinct_on(table['id']) |
5994 | manager.distinct_on(false) |
5995 | end |
5996 | manager = Arel::SelectManager.new |
5997 | table = Table.new :users |
5998 | manager.distinct_on(false).must_equal manager |
5999 | end |
6000 | end |
6001 | end |
6002 | end |
6003 | require 'helper' |
6004 | module Arel |
6005 | describe Table do |
6006 | before do |
6007 | @relation = Table.new(:users) |
6008 | end |
6009 | join = @relation.create_string_join 'foo' |
6010 | assert_kind_of Arel::Nodes::StringJoin, join |
6011 | assert_equal 'foo', join.left |
6012 | end |
6013 | join = @relation.create_join 'foo', 'bar' |
6014 | assert_kind_of Arel::Nodes::InnerJoin, join |
6015 | assert_equal 'foo', join.left |
6016 | assert_equal 'bar', join.right |
6017 | end |
6018 | assert_kind_of Arel::Nodes::FullOuterJoin, join |
6019 | assert_equal 'foo', join.left |
6020 | assert_equal 'bar', join.right |
6021 | end |
6022 | assert_kind_of Arel::Nodes::OuterJoin, join |
6023 | assert_equal 'foo', join.left |
6024 | assert_equal 'bar', join.right |
6025 | end |
6026 | assert_kind_of Arel::Nodes::RightOuterJoin, join |
6027 | assert_equal 'foo', join.left |
6028 | assert_equal 'bar', join.right |
6029 | end |
6030 | im = @relation.compile_insert 'VALUES(NULL)' |
6031 | assert_kind_of Arel::InsertManager, im |
6032 | im.into Table.new(:users) |
6033 | end |
6034 | describe 'skip' do |
6035 | sm = @relation.skip 2 |
6036 | end |
6037 | end |
6038 | describe 'having' do |
6039 | mgr = @relation.having @relation[:id].eq(10) |
6040 | mgr.to_sql.must_be_like %{ |
6041 | SELECT FROM "users" HAVING "users"."id" = 10 |
6042 | } |
6043 | end |
6044 | end |
6045 | describe 'backwards compat' do |
6046 | describe 'join' do |
6047 | mgr = @relation.join nil |
6048 | mgr.to_sql.must_be_like %{ SELECT FROM "users" } |
6049 | end |
6050 | right = @relation.alias |
6051 | predicate = @relation[:id].eq(right[:id]) |
6052 | mgr.to_sql.must_be_like %{ |
6053 | SELECT FROM "users" |
6054 | LEFT OUTER JOIN "users" "users_2" |
6055 | ON "users"."id" = "users_2"."id" |
6056 | } |
6057 | end |
6058 | end |
6059 | describe 'join' do |
6060 | right = @relation.alias |
6061 | predicate = @relation[:id].eq(right[:id]) |
6062 | mgr = @relation.outer_join(right).on(predicate) |
6063 | mgr.to_sql.must_be_like %{ |
6064 | SELECT FROM "users" |
6065 | LEFT OUTER JOIN "users" "users_2" |
6066 | ON "users"."id" = "users_2"."id" |
6067 | } |
6068 | end |
6069 | end |
6070 | end |
6071 | describe 'group' do |
6072 | manager = @relation.group @relation[:id] |
6073 | manager.to_sql.must_be_like %{ |
6074 | SELECT FROM "users" GROUP BY "users"."id" |
6075 | } |
6076 | end |
6077 | end |
6078 | describe 'alias' do |
6079 | @relation.aliases.must_equal [] |
6080 | node = @relation.alias |
6081 | @relation.aliases.must_equal [node] |
6082 | node.name.must_equal 'users_2' |
6083 | node[:id].relation.must_equal node |
6084 | end |
6085 | end |
6086 | describe 'new' do |
6087 | rel = Table.new :users, :as = 'foo' |
6088 | rel.table_alias.must_equal 'foo' |
6089 | end |
6090 | rel = Table.new :users, :as = 'users' |
6091 | rel.table_alias.must_be_nil |
6092 | end |
6093 | end |
6094 | describe 'order' do |
6095 | manager = @relation.order "foo" |
6096 | end |
6097 | end |
6098 | describe 'take' do |
6099 | manager = @relation.take 1 |
6100 | manager.project Nodes::SqlLiteral.new '*' |
6101 | end |
6102 | end |
6103 | describe 'project' do |
6104 | end |
6105 | end |
6106 | end |
6107 | describe 'where' do |
6108 | manager = @relation.where @relation[:id].eq 1 |
6109 | manager.project @relation[:id] |
6110 | manager.must_be_kind_of TreeManager |
6111 | manager.to_sql.must_be_like %{ |
6112 | SELECT "users"."id" |
6113 | FROM "users" |
6114 | WHERE "users"."id" = 1 |
6115 | } |
6116 | end |
6117 | end |
6118 | @relation.name.must_equal 'users' |
6119 | end |
6120 | @relation.table_name.must_equal 'users' |
6121 | end |
6122 | describe '[]' do |
6123 | describe 'when given a Symbol' do |
6124 | column = @relation[:id] |
6125 | column.name.must_equal :id |
6126 | end |
6127 | end |
6128 | end |
6129 | describe 'equality' do |
6130 | relation1 = Table.new(:users) |
6131 | relation1.aliases = %w[a b c] |
6132 | relation1.table_alias = 'zomg' |
6133 | relation2 = Table.new(:users) |
6134 | relation2.aliases = %w[a b c] |
6135 | relation2.table_alias = 'zomg' |
6136 | array = [relation1, relation2] |
6137 | assert_equal 1, array.uniq.size |
6138 | end |
6139 | relation1 = Table.new(:users) |
6140 | relation1.aliases = %w[a b c] |
6141 | relation1.table_alias = 'zomg' |
6142 | relation2 = Table.new(:users) |
6143 | relation2.aliases = %w[x y z] |
6144 | relation2.table_alias = 'zomg' |
6145 | array = [relation1, relation2] |
6146 | assert_equal 2, array.uniq.size |
6147 | end |
6148 | end |
6149 | end |
6150 | end |
6151 | require 'helper' |
6152 | module Arel |
6153 | describe 'update manager' do |
6154 | describe 'new' do |
6155 | Arel::UpdateManager.new |
6156 | end |
6157 | end |
6158 | table = Table.new(:users) |
6159 | um = Arel::UpdateManager.new |
6160 | um.table table |
6161 | end |
6162 | table = Table.new(:users) |
6163 | um = Arel::UpdateManager.new |
6164 | um.key = 'id' |
6165 | um.take 10 |
6166 | um.table table |
6167 | um.set [[table[:name], nil]] |
6168 | assert_match(/LIMIT 10/, um.to_sql) |
6169 | end |
6170 | describe 'set' do |
6171 | table = Table.new(:users) |
6172 | um = Arel::UpdateManager.new |
6173 | um.table table |
6174 | um.set [[table[:name], nil]] |
6175 | end |
6176 | table = Table.new(:users) |
6177 | um = Arel::UpdateManager.new |
6178 | um.table table |
6179 | um.set Nodes::SqlLiteral.new "foo = bar" |
6180 | end |
6181 | table = Table.new(:users) |
6182 | um = Arel::UpdateManager.new |
6183 | um.table table |
6184 | um.set [[table[:id], 1], [table[:name], 'hello']] |
6185 | um.to_sql.must_be_like %{ |
6186 | UPDATE "users" SET "id" = 1, "name" = 'hello' |
6187 | } |
6188 | end |
6189 | table = Table.new(:users) |
6190 | um = Arel::UpdateManager.new |
6191 | end |
6192 | end |
6193 | describe 'table' do |
6194 | um = Arel::UpdateManager.new |
6195 | um.table Table.new(:users) |
6196 | um.to_sql.must_be_like %{ UPDATE "users" } |
6197 | end |
6198 | um = Arel::UpdateManager.new |
6199 | um.table(Table.new(:users)).must_equal um |
6200 | end |
6201 | um = Arel::UpdateManager.new |
6202 | table = Table.new(:users) |
6203 | join_source = Arel::Nodes::JoinSource.new( |
6204 | table, |
6205 | [table.create_join(Table.new(:posts))] |
6206 | ) |
6207 | um.table join_source |
6208 | end |
6209 | end |
6210 | describe 'where' do |
6211 | table = Table.new :users |
6212 | um = Arel::UpdateManager.new |
6213 | um.table table |
6214 | um.where table[:id].eq(1) |
6215 | um.to_sql.must_be_like %{ |
6216 | UPDATE "users" WHERE "users"."id" = 1 |
6217 | } |
6218 | end |
6219 | table = Table.new :users |
6220 | um = Arel::UpdateManager.new |
6221 | um.table table |
6222 | um.where(table[:id].eq(1)).must_equal um |
6223 | end |
6224 | end |
6225 | describe 'key' do |
6226 | before do |
6227 | @table = Table.new :users |
6228 | @um = Arel::UpdateManager.new |
6229 | @um.key = @table[:foo] |
6230 | end |
6231 | @um.ast.key.must_equal @table[:foo] |
6232 | end |
6233 | @um.key.must_equal @table[:foo] |
6234 | end |
6235 | end |
6236 | end |
6237 | end |
6238 | require 'helper' |
6239 | require 'arel/visitors/bind_visitor' |
6240 | require 'support/fake_record' |
6241 | module Arel |
6242 | module Visitors |
6243 | class TestBindVisitor Arel::Test |
6244 | attr_reader :collector |
6245 | def setup |
6246 | @collector = Collectors::SQLString.new |
6247 | super |
6248 | end |
6249 | def test_assignment_binds_are_substituted |
6250 | table = Table.new(:users) |
6251 | um = Arel::UpdateManager.new |
6252 | bp = Nodes::BindParam.new |
6253 | um.set [[table[:name], bp]] |
6254 | visitor = Class.new(Arel::Visitors::ToSql) { |
6255 | include Arel::Visitors::BindVisitor |
6256 | }.new Table.engine.connection |
6257 | assignment = um.ast.values[0] |
6258 | actual = visitor.accept(assignment, collector) { |
6259 | "replace" |
6260 | } |
6261 | assert actual |
6262 | value = actual.value |
6263 | assert_like "\"name\" = replace", value |
6264 | end |
6265 | def test_visitor_yields_on_binds |
6266 | visitor = Class.new(Arel::Visitors::ToSql) { |
6267 | include Arel::Visitors::BindVisitor |
6268 | }.new nil |
6269 | bp = Nodes::BindParam.new |
6270 | called = false |
6271 | visitor.accept(bp, collector) { called = true } |
6272 | assert called |
6273 | end |
6274 | def test_visitor_only_yields_on_binds |
6275 | visitor = Class.new(Arel::Visitors::ToSql) { |
6276 | include Arel::Visitors::BindVisitor |
6277 | }.new(nil) |
6278 | bp = Arel.sql 'omg' |
6279 | called = false |
6280 | visitor.accept(bp, collector) { called = true } |
6281 | refute called |
6282 | end |
6283 | end |
6284 | end |
6285 | end |
6286 | require 'helper' |
6287 | require 'set' |
6288 | module Arel |
6289 | module Visitors |
6290 | class TestDepthFirst Minitest::Test |
6291 | Collector = Struct.new(:calls) do |
6292 | def call object |
6293 | calls object |
6294 | end |
6295 | end |
6296 | def setup |
6297 | @collector = Collector.new [] |
6298 | @visitor = Visitors::DepthFirst.new @collector |
6299 | end |
6300 | def test_raises_with_object |
6301 | assert_raises(TypeError) do |
6302 | @visitor.accept(Object.new) |
6303 | end |
6304 | end |
6305 | [ |
6306 | Arel::Nodes::Not, |
6307 | Arel::Nodes::Group, |
6308 | Arel::Nodes::On, |
6309 | Arel::Nodes::Grouping, |
6310 | Arel::Nodes::Offset, |
6311 | Arel::Nodes::Ordering, |
6312 | Arel::Nodes::StringJoin, |
6313 | Arel::Nodes::UnqualifiedColumn, |
6314 | Arel::Nodes::Top, |
6315 | Arel::Nodes::Limit, |
6316 | ].each do |klass| |
6317 | op = klass.new(:a) |
6318 | @visitor.accept op |
6319 | assert_equal [:a, op], @collector.calls |
6320 | end |
6321 | end |
6322 | [ |
6323 | Arel::Nodes::Exists, |
6324 | Arel::Nodes::Avg, |
6325 | Arel::Nodes::Min, |
6326 | Arel::Nodes::Max, |
6327 | Arel::Nodes::Sum, |
6328 | ].each do |klass| |
6329 | func = klass.new(:a, "b") |
6330 | @visitor.accept func |
6331 | end |
6332 | end |
6333 | def test_named_function |
6334 | @visitor.accept func |
6335 | end |
6336 | def test_lock |
6337 | lock = Nodes::Lock.new true |
6338 | @visitor.accept lock |
6339 | assert_equal [lock], @collector.calls |
6340 | end |
6341 | def test_count |
6342 | count = Nodes::Count.new :a, :b, "c" |
6343 | @visitor.accept count |
6344 | end |
6345 | def test_inner_join |
6346 | join = Nodes::InnerJoin.new :a, :b |
6347 | @visitor.accept join |
6348 | assert_equal [:a, :b, join], @collector.calls |
6349 | end |
6350 | def test_full_outer_join |
6351 | join = Nodes::FullOuterJoin.new :a, :b |
6352 | @visitor.accept join |
6353 | assert_equal [:a, :b, join], @collector.calls |
6354 | end |
6355 | def test_outer_join |
6356 | join = Nodes::OuterJoin.new :a, :b |
6357 | @visitor.accept join |
6358 | assert_equal [:a, :b, join], @collector.calls |
6359 | end |
6360 | def test_right_outer_join |
6361 | join = Nodes::RightOuterJoin.new :a, :b |
6362 | @visitor.accept join |
6363 | assert_equal [:a, :b, join], @collector.calls |
6364 | end |
6365 | [ |
6366 | Arel::Nodes::Assignment, |
6367 | Arel::Nodes::Between, |
6368 | Arel::Nodes::DoesNotMatch, |
6369 | Arel::Nodes::Equality, |
6370 | Arel::Nodes::GreaterThan, |
6371 | Arel::Nodes::GreaterThanOrEqual, |
6372 | Arel::Nodes::In, |
6373 | Arel::Nodes::LessThan, |
6374 | Arel::Nodes::LessThanOrEqual, |
6375 | Arel::Nodes::Matches, |
6376 | Arel::Nodes::NotEqual, |
6377 | Arel::Nodes::NotIn, |
6378 | Arel::Nodes::Or, |
6379 | Arel::Nodes::TableAlias, |
6380 | Arel::Nodes::Values, |
6381 | Arel::Nodes::As, |
6382 | Arel::Nodes::DeleteStatement, |
6383 | Arel::Nodes::JoinSource, |
6384 | ].each do |klass| |
6385 | binary = klass.new(:a, :b) |
6386 | @visitor.accept binary |
6387 | assert_equal [:a, :b, binary], @collector.calls |
6388 | end |
6389 | end |
6390 | def test_Arel_Nodes_InfixOperation |
6391 | @visitor.accept binary |
6392 | assert_equal [:a, :b, binary], @collector.calls |
6393 | end |
6394 | [ |
6395 | Arel::Nodes::And, |
6396 | ].each do |klass| |
6397 | binary = klass.new([:a, :b, :c]) |
6398 | @visitor.accept binary |
6399 | end |
6400 | end |
6401 | [ |
6402 | Arel::Attributes::Integer, |
6403 | Arel::Attributes::Float, |
6404 | Arel::Attributes::String, |
6405 | Arel::Attributes::Time, |
6406 | Arel::Attributes::Boolean, |
6407 | Arel::Attributes::Attribute |
6408 | ].each do |klass| |
6409 | binary = klass.new(:a, :b) |
6410 | @visitor.accept binary |
6411 | assert_equal [:a, :b, binary], @collector.calls |
6412 | end |
6413 | end |
6414 | def test_table |
6415 | relation = Arel::Table.new(:users) |
6416 | @visitor.accept relation |
6417 | end |
6418 | def test_array |
6419 | node = Nodes::Or.new(:a, :b) |
6420 | list = [node] |
6421 | @visitor.accept list |
6422 | end |
6423 | def test_set |
6424 | node = Nodes::Or.new(:a, :b) |
6425 | set = Set.new([node]) |
6426 | @visitor.accept set |
6427 | end |
6428 | def test_hash |
6429 | node = Nodes::Or.new(:a, :b) |
6430 | hash = { node = node } |
6431 | @visitor.accept hash |
6432 | end |
6433 | def test_update_statement |
6434 | stmt = Nodes::UpdateStatement.new |
6435 | stmt.relation = :a |
6436 | stmt.values :b |
6437 | stmt.wheres :c |
6438 | stmt.orders :d |
6439 | stmt.limit = :e |
6440 | @visitor.accept stmt |
6441 | :e, stmt], @collector.calls |
6442 | end |
6443 | def test_select_core |
6444 | core = Nodes::SelectCore.new |
6445 | core.projections :a |
6446 | core.froms = :b |
6447 | core.wheres :c |
6448 | core.groups :d |
6449 | core.windows :e |
6450 | core.havings :f |
6451 | @visitor.accept core |
6452 | assert_equal [ |
6453 | :a, core.projections, |
6454 | :b, [], |
6455 | core.source, |
6456 | :c, core.wheres, |
6457 | :d, core.groups, |
6458 | :e, core.windows, |
6459 | :f, core.havings, |
6460 | core], @collector.calls |
6461 | end |
6462 | def test_select_statement |
6463 | ss = Nodes::SelectStatement.new |
6464 | ss.cores.replace [:a] |
6465 | ss.orders :b |
6466 | ss.limit = :c |
6467 | ss.lock = :d |
6468 | ss.offset = :e |
6469 | @visitor.accept ss |
6470 | assert_equal [ |
6471 | :a, ss.cores, |
6472 | :b, ss.orders, |
6473 | :c, |
6474 | :d, |
6475 | :e, |
6476 | ss], @collector.calls |
6477 | end |
6478 | def test_insert_statement |
6479 | stmt = Nodes::InsertStatement.new |
6480 | stmt.relation = :a |
6481 | stmt.columns :b |
6482 | stmt.values = :c |
6483 | @visitor.accept stmt |
6484 | end |
6485 | def test_node |
6486 | node = Nodes::Node.new |
6487 | @visitor.accept node |
6488 | assert_equal [node], @collector.calls |
6489 | end |
6490 | end |
6491 | end |
6492 | end |
6493 | require 'helper' |
6494 | module Arel |
6495 | module Visitors |
6496 | before do |
6497 | @connection = Table.engine.connection |
6498 | @table = Table.new(:users) |
6499 | end |
6500 | assert_equal "( TRUE UNION FALSE )", node.to_sql |
6501 | node.first # from Nodes::Node's Enumerable mixin |
6502 | assert_equal "( TRUE UNION FALSE )", node.to_sql |
6503 | end |
6504 | end |
6505 | end |
6506 | end |
6507 | require 'helper' |
6508 | module Arel |
6509 | module Visitors |
6510 | class TestDot Minitest::Test |
6511 | def setup |
6512 | @visitor = Visitors::Dot.new |
6513 | end |
6514 | [ |
6515 | Nodes::Sum, |
6516 | Nodes::Exists, |
6517 | Nodes::Max, |
6518 | Nodes::Min, |
6519 | Nodes::Avg, |
6520 | ].each do |klass| |
6521 | op = klass.new(:a, "z") |
6522 | @visitor.accept op, Collectors::PlainString.new |
6523 | end |
6524 | end |
6525 | def test_named_function |
6526 | func = Nodes::NamedFunction.new 'omg', 'omg' |
6527 | @visitor.accept func, Collectors::PlainString.new |
6528 | end |
6529 | [ |
6530 | Arel::Nodes::Not, |
6531 | Arel::Nodes::Group, |
6532 | Arel::Nodes::On, |
6533 | Arel::Nodes::Grouping, |
6534 | Arel::Nodes::Offset, |
6535 | Arel::Nodes::Ordering, |
6536 | Arel::Nodes::UnqualifiedColumn, |
6537 | Arel::Nodes::Top, |
6538 | Arel::Nodes::Limit, |
6539 | ].each do |klass| |
6540 | op = klass.new(:a) |
6541 | @visitor.accept op, Collectors::PlainString.new |
6542 | end |
6543 | end |
6544 | [ |
6545 | Arel::Nodes::Assignment, |
6546 | Arel::Nodes::Between, |
6547 | Arel::Nodes::DoesNotMatch, |
6548 | Arel::Nodes::Equality, |
6549 | Arel::Nodes::GreaterThan, |
6550 | Arel::Nodes::GreaterThanOrEqual, |
6551 | Arel::Nodes::In, |
6552 | Arel::Nodes::LessThan, |
6553 | Arel::Nodes::LessThanOrEqual, |
6554 | Arel::Nodes::Matches, |
6555 | Arel::Nodes::NotEqual, |
6556 | Arel::Nodes::NotIn, |
6557 | Arel::Nodes::Or, |
6558 | Arel::Nodes::TableAlias, |
6559 | Arel::Nodes::Values, |
6560 | Arel::Nodes::As, |
6561 | Arel::Nodes::DeleteStatement, |
6562 | Arel::Nodes::JoinSource, |
6563 | ].each do |klass| |
6564 | binary = klass.new(:a, :b) |
6565 | end |
6566 | end |
6567 | end |
6568 | end |
6569 | end |
6570 | require 'helper' |
6571 | module Arel |
6572 | module Visitors |
6573 | describe 'the ibm_db visitor' do |
6574 | before do |
6575 | @visitor = IBM_DB.new Table.engine.connection |
6576 | end |
6577 | def compile node |
6578 | end |
6579 | stmt = Nodes::SelectStatement.new |
6580 | stmt.limit = Nodes::Limit.new(1) |
6581 | sql = compile(stmt) |
6582 | sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY" |
6583 | end |
6584 | table = Table.new(:users) |
6585 | stmt = Nodes::UpdateStatement.new |
6586 | stmt.relation = table |
6587 | stmt.key = table[:id] |
6588 | sql = compile(stmt) |
6589 | end |
6590 | end |
6591 | end |
6592 | end |
6593 | require 'helper' |
6594 | module Arel |
6595 | module Visitors |
6596 | describe 'the informix visitor' do |
6597 | before do |
6598 | @visitor = Informix.new Table.engine.connection |
6599 | end |
6600 | def compile node |
6601 | end |
6602 | stmt = Nodes::SelectStatement.new |
6603 | stmt.limit = Nodes::Limit.new(1) |
6604 | sql = compile(stmt) |
6605 | sql.must_be_like "SELECT FIRST 1" |
6606 | end |
6607 | table = Table.new(:users) |
6608 | stmt = Nodes::UpdateStatement.new |
6609 | stmt.relation = table |
6610 | stmt.key = table[:id] |
6611 | sql = compile(stmt) |
6612 | end |
6613 | stmt = Nodes::SelectStatement.new |
6614 | stmt.offset = Nodes::Offset.new(10) |
6615 | sql = compile(stmt) |
6616 | sql.must_be_like "SELECT SKIP 10" |
6617 | end |
6618 | stmt = Nodes::SelectStatement.new |
6619 | stmt.limit = Nodes::Limit.new(1) |
6620 | stmt.offset = Nodes::Offset.new(1) |
6621 | sql = compile(stmt) |
6622 | sql.must_be_like "SELECT SKIP 1 FIRST 1" |
6623 | end |
6624 | core = Nodes::SelectCore.new |
6625 | table = Table.new(:posts) |
6626 | stmt = Nodes::SelectStatement.new([core]) |
6627 | sql = compile(stmt) |
6628 | end |
6629 | end |
6630 | end |
6631 | end |
6632 | require 'helper' |
6633 | module Arel |
6634 | module Visitors |
6635 | describe 'the mssql visitor' do |
6636 | before do |
6637 | @visitor = MSSQL.new Table.engine.connection |
6638 | @table = Arel::Table.new "users" |
6639 | end |
6640 | def compile node |
6641 | end |
6642 | stmt = Nodes::SelectStatement.new |
6643 | sql = compile(stmt) |
6644 | sql.must_be_like "SELECT" |
6645 | end |
6646 | stmt = Nodes::SelectStatement.new |
6647 | stmt.cores.first.from = @table |
6648 | stmt.limit = Nodes::Limit.new(10) |
6649 | sql = compile(stmt) |
6650 | end |
6651 | connection = MiniTest::Mock.new |
6652 | def connection.quote_table_name(*); ""; end |
6653 | def connection.quote_column_name(*); ""; end |
6654 | @visitor = MSSQL.new(connection) |
6655 | stmt = Nodes::SelectStatement.new |
6656 | stmt.cores.first.from = @table |
6657 | stmt.limit = Nodes::Limit.new(10) |
6658 | compile(stmt) |
6659 | compile(stmt) |
6660 | connection.verify |
6661 | end |
6662 | stmt = Nodes::SelectStatement.new |
6663 | stmt.limit = Nodes::Limit.new(10) |
6664 | stmt.orders Nodes::SqlLiteral.new('order_by') |
6665 | sql = compile(stmt) |
6666 | end |
6667 | stmt = Nodes::SelectStatement.new |
6668 | stmt.limit = Nodes::Limit.new(10) |
6669 | sql = compile(stmt) |
6670 | end |
6671 | stmt = Nodes::SelectStatement.new |
6672 | stmt.limit = Nodes::Limit.new(10) |
6673 | stmt.offset = Nodes::Offset.new(20) |
6674 | sql = compile(stmt) |
6675 | end |
6676 | stmt = Nodes::SelectStatement.new |
6677 | stmt.offset = Nodes::Offset.new(20) |
6678 | sql = compile(stmt) |
6679 | end |
6680 | stmt = Nodes::SelectStatement.new |
6681 | stmt.limit = Nodes::Limit.new(10) |
6682 | sql = compile(stmt) |
6683 | end |
6684 | end |
6685 | end |
6686 | end |
6687 | require 'helper' |
6688 | module Arel |
6689 | module Visitors |
6690 | describe 'the mysql visitor' do |
6691 | before do |
6692 | @visitor = MySQL.new Table.engine.connection |
6693 | end |
6694 | def compile node |
6695 | end |
6696 | assert_equal 1, compile(node).scan('(').length |
6697 | assert_equal 1, compile(node).scan('(').length |
6698 | end |
6699 | stmt = Nodes::SelectStatement.new |
6700 | stmt.offset = Nodes::Offset.new(1) |
6701 | sql = compile(stmt) |
6702 | end |
6703 | sc = Arel::Nodes::UpdateStatement.new |
6704 | sc.relation = Table.new(:users) |
6705 | end |
6706 | stmt = Nodes::SelectStatement.new |
6707 | sql = compile(stmt) |
6708 | sql.must_be_like "SELECT FROM DUAL" |
6709 | end |
6710 | describe 'locking' do |
6711 | node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) |
6712 | compile(node).must_be_like "FOR UPDATE" |
6713 | end |
6714 | compile(node).must_be_like "LOCK IN SHARE MODE" |
6715 | end |
6716 | end |
6717 | end |
6718 | end |
6719 | end |
6720 | require 'helper' |
6721 | module Arel |
6722 | module Visitors |
6723 | describe 'the oracle visitor' do |
6724 | before do |
6725 | @visitor = Oracle.new Table.engine.connection |
6726 | @table = Table.new(:users) |
6727 | end |
6728 | def compile node |
6729 | end |
6730 | stmt = Nodes::SelectStatement.new |
6731 | stmt.orders Nodes::SqlLiteral.new('foo') |
6732 | sql = compile(stmt) |
6733 | sql.must_be_like %{ |
6734 | SELECT #{select} ORDER BY alias_0__ |
6735 | } |
6736 | end |
6737 | stmt = Nodes::SelectStatement.new |
6738 | stmt.orders Nodes::SqlLiteral.new('foo') |
6739 | sql = compile(stmt) |
6740 | sql2 = compile(stmt) |
6741 | sql.must_equal sql2 |
6742 | end |
6743 | stmt = Nodes::SelectStatement.new |
6744 | stmt.orders Nodes::SqlLiteral.new('foo, bar') |
6745 | sql = compile(stmt) |
6746 | sql.must_be_like %{ |
6747 | SELECT #{select} ORDER BY alias_0__, alias_1__ |
6748 | } |
6749 | end |
6750 | stmt = Nodes::SelectStatement.new |
6751 | sql = compile(stmt) |
6752 | sql.must_be_like %{ |
6753 | } |
6754 | end |
6755 | describe 'Nodes::SelectStatement' do |
6756 | describe 'limit' do |
6757 | stmt = Nodes::SelectStatement.new |
6758 | stmt.limit = Nodes::Limit.new(10) |
6759 | sql = compile stmt |
6760 | sql.must_be_like %{ SELECT WHERE ROWNUM = 10 } |
6761 | end |
6762 | stmt = Nodes::SelectStatement.new |
6763 | stmt.orders Nodes::SqlLiteral.new('foo') |
6764 | stmt.limit = Nodes::Limit.new(10) |
6765 | sql = compile stmt |
6766 | sql2 = compile stmt |
6767 | sql.must_equal sql2 |
6768 | end |
6769 | stmt = Nodes::SelectStatement.new |
6770 | stmt.orders Nodes::SqlLiteral.new('foo') |
6771 | stmt.limit = Nodes::Limit.new(10) |
6772 | sql = compile stmt |
6773 | sql.must_be_like %{ |
6774 | } |
6775 | end |
6776 | stmt = Nodes::SelectStatement.new |
6777 | stmt.limit = Nodes::Limit.new(10) |
6778 | sql = compile stmt |
6779 | sql.must_be_like %{ |
6780 | } |
6781 | end |
6782 | stmt = Nodes::SelectStatement.new |
6783 | stmt.limit = Arel::Nodes::Limit.new(10) |
6784 | sql = compile stmt |
6785 | sql.must_be_like %{ |
6786 | } |
6787 | end |
6788 | stmt = Nodes::SelectStatement.new |
6789 | stmt.offset = Nodes::Offset.new(10) |
6790 | sql = compile stmt |
6791 | sql.must_be_like %{ |
6792 | SELECT * FROM ( |
6793 | SELECT raw_sql_.*, rownum raw_rnum_ |
6794 | FROM (SELECT ) raw_sql_ |
6795 | WHERE rownum = 20 |
6796 | ) |
6797 | WHERE raw_rnum_ 10 |
6798 | } |
6799 | end |
6800 | stmt = Nodes::SelectStatement.new |
6801 | stmt.offset = Nodes::Offset.new(10) |
6802 | sql = compile stmt |
6803 | sql2 = compile stmt |
6804 | sql.must_equal sql2 |
6805 | end |
6806 | end |
6807 | describe 'only offset' do |
6808 | stmt = Nodes::SelectStatement.new |
6809 | stmt.offset = Nodes::Offset.new(10) |
6810 | sql = compile stmt |
6811 | sql.must_be_like %{ |
6812 | SELECT * FROM ( |
6813 | SELECT raw_sql_.*, rownum raw_rnum_ |
6814 | FROM (SELECT) raw_sql_ |
6815 | ) |
6816 | WHERE raw_rnum_ 10 |
6817 | } |
6818 | end |
6819 | end |
6820 | end |
6821 | sql = compile Nodes::Except.new(left, right) |
6822 | sql.must_be_like %{ |
6823 | } |
6824 | end |
6825 | describe 'locking' do |
6826 | node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) |
6827 | compile(node).must_be_like "FOR UPDATE" |
6828 | end |
6829 | end |
6830 | describe "Nodes::BindParam" do |
6831 | .and(@table[:id].eq(Arel::Nodes::BindParam.new)) |
6832 | compile(query).must_be_like %{ |
6833 | "users"."name" = :a1 AND "users"."id" = :a2 |
6834 | } |
6835 | end |
6836 | end |
6837 | end |
6838 | end |
6839 | end |
6840 | require 'helper' |
6841 | module Arel |
6842 | module Visitors |
6843 | describe 'the postgres visitor' do |
6844 | before do |
6845 | @visitor = PostgreSQL.new Table.engine.connection |
6846 | @table = Table.new(:users) |
6847 | @attr = @table[:id] |
6848 | end |
6849 | def compile node |
6850 | end |
6851 | describe 'locking' do |
6852 | FOR UPDATE |
6853 | } |
6854 | end |
6855 | node = Nodes::Lock.new(Arel.sql('FOR SHARE')) |
6856 | compile(node).must_be_like %{ |
6857 | FOR SHARE |
6858 | } |
6859 | end |
6860 | end |
6861 | sc = Arel::Nodes::SelectStatement.new |
6862 | sc.orders Arel.sql("xyz") |
6863 | sql = compile(sc) |
6864 | assert_match(/LIMIT 'omg'/, sql) |
6865 | end |
6866 | core = Arel::Nodes::SelectCore.new |
6867 | end |
6868 | core = Arel::Nodes::SelectCore.new |
6869 | core.set_quantifier = Arel::Nodes::Distinct.new |
6870 | assert_equal 'SELECT DISTINCT', compile(core) |
6871 | end |
6872 | describe "Nodes::Matches" do |
6873 | node = @table[:name].matches('foo%') |
6874 | compile(node).must_be_like %{ |
6875 | "users"."name" ILIKE 'foo%' |
6876 | } |
6877 | end |
6878 | node = @table[:name].matches('foo!%', '!') |
6879 | compile(node).must_be_like %{ |
6880 | "users"."name" ILIKE 'foo!%' ESCAPE '!' |
6881 | } |
6882 | end |
6883 | node = @attr.in subquery |
6884 | compile(node).must_be_like %{ |
6885 | } |
6886 | end |
6887 | end |
6888 | describe "Nodes::DoesNotMatch" do |
6889 | node = @table[:name].does_not_match('foo%') |
6890 | compile(node).must_be_like %{ |
6891 | "users"."name" NOT ILIKE 'foo%' |
6892 | } |
6893 | end |
6894 | node = @table[:name].does_not_match('foo!%', '!') |
6895 | compile(node).must_be_like %{ |
6896 | "users"."name" NOT ILIKE 'foo!%' ESCAPE '!' |
6897 | } |
6898 | end |
6899 | node = @attr.in subquery |
6900 | compile(node).must_be_like %{ |
6901 | } |
6902 | end |
6903 | end |
6904 | describe "Nodes::Regexp" do |
6905 | compile(node).must_be_like %{ |
6906 | "users"."name" ~ 'foo%' |
6907 | } |
6908 | end |
6909 | node = @attr.in subquery |
6910 | compile(node).must_be_like %{ |
6911 | } |
6912 | end |
6913 | end |
6914 | describe "Nodes::NotRegexp" do |
6915 | compile(node).must_be_like %{ |
6916 | "users"."name" !~ 'foo%' |
6917 | } |
6918 | end |
6919 | node = @attr.in subquery |
6920 | compile(node).must_be_like %{ |
6921 | } |
6922 | end |
6923 | end |
6924 | describe "Nodes::BindParam" do |
6925 | .and(@table[:id].eq(Arel::Nodes::BindParam.new)) |
6926 | compile(query).must_be_like %{ |
6927 | "users"."name" = $1 AND "users"."id" = $2 |
6928 | } |
6929 | end |
6930 | end |
6931 | end |
6932 | end |
6933 | end |
6934 | require 'helper' |
6935 | module Arel |
6936 | module Visitors |
6937 | describe 'the sqlite visitor' do |
6938 | before do |
6939 | end |
6940 | stmt = Nodes::SelectStatement.new |
6941 | stmt.offset = Nodes::Offset.new(1) |
6942 | sql.must_be_like "SELECT LIMIT -1 OFFSET 1" |
6943 | end |
6944 | node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) |
6945 | end |
6946 | end |
6947 | end |
6948 | end |
6949 | require 'helper' |
6950 | require 'set' |
6951 | module Arel |
6952 | module Visitors |
6953 | describe 'the to_sql visitor' do |
6954 | before do |
6955 | @conn = FakeRecord::Base.new |
6956 | @visitor = ToSql.new @conn.connection |
6957 | @table = Table.new(:users) |
6958 | @attr = @table[:id] |
6959 | end |
6960 | def compile node |
6961 | end |
6962 | node = Nodes::BindParam.new |
6963 | sql = compile node |
6964 | sql.must_be_like '?' |
6965 | end |
6966 | bp = Nodes::BindParam.new |
6967 | values = Nodes::Values.new([bp]) |
6968 | sql = compile values |
6969 | sql.must_be_like 'VALUES (?)' |
6970 | end |
6971 | visited = false |
6972 | viz = Class.new(Arel::Visitors::Reduce) { |
6973 | define_method(:hello) do |node, c| |
6974 | visited = true |
6975 | end |
6976 | def dispatch |
6977 | { Arel::Table = 'hello' } |
6978 | end |
6979 | }.new |
6980 | viz.accept(@table, Collectors::SQLString.new) |
6981 | assert visited, 'hello method was called' |
6982 | end |
6983 | node = @table[Arel.star] |
6984 | sql = compile node |
6985 | sql.must_be_like '"users".*' |
6986 | end |
6987 | assert_equal 'omg(*)', compile(function) |
6988 | end |
6989 | sql = compile(function.eq(2)) |
6990 | sql.must_be_like %{ omg(*) = 2 } |
6991 | end |
6992 | function = Nodes::Count.new([Arel.star]) |
6993 | assert_equal 'COUNT(*)', compile(function) |
6994 | function = Nodes::Sum.new([Arel.star]) |
6995 | assert_equal 'SUM(*)', compile(function) |
6996 | function = Nodes::Max.new([Arel.star]) |
6997 | assert_equal 'MAX(*)', compile(function) |
6998 | function = Nodes::Min.new([Arel.star]) |
6999 | assert_equal 'MIN(*)', compile(function) |
7000 | function = Nodes::Avg.new([Arel.star]) |
7001 | assert_equal 'AVG(*)', compile(function) |
7002 | end |
7003 | function = Nodes::Count.new([Arel.star]) |
7004 | function.distinct = true |
7005 | function = Nodes::Sum.new([Arel.star]) |
7006 | function.distinct = true |
7007 | assert_equal 'SUM(DISTINCT *)', compile(function) |
7008 | function = Nodes::Max.new([Arel.star]) |
7009 | function.distinct = true |
7010 | assert_equal 'MAX(DISTINCT *)', compile(function) |
7011 | function = Nodes::Min.new([Arel.star]) |
7012 | function.distinct = true |
7013 | assert_equal 'MIN(DISTINCT *)', compile(function) |
7014 | function = Nodes::Avg.new([Arel.star]) |
7015 | function.distinct = true |
7016 | assert_equal 'AVG(DISTINCT *)', compile(function) |
7017 | end |
7018 | assert_equal 'omg(*, *)', compile(function) |
7019 | end |
7020 | describe 'Nodes::Equality' do |
7021 | compile(test).must_be_like %{ |
7022 | "users"."name" = 'Aaron Patterson' |
7023 | } |
7024 | end |
7025 | table = Table.new(:users) |
7026 | val = Nodes.build_quoted(false, table[:active]) |
7027 | sql = compile Nodes::Equality.new(val, val) |
7028 | sql.must_be_like %{ 'f' = 'f' } |
7029 | end |
7030 | table = Table.new(:users) |
7031 | val = Nodes.build_quoted('1-fooo', table[:id]) |
7032 | sql.must_be_like %{ "users"."id" = 1 } |
7033 | end |
7034 | table = Table.new(:users) |
7035 | sql = compile table[:name].eq(0) |
7036 | sql.must_be_like %{ "users"."name" = '0' } |
7037 | end |
7038 | sql.must_be_like %{ "users"."name" IS NULL } |
7039 | end |
7040 | end |
7041 | describe 'Nodes::Grouping' do |
7042 | sql.must_equal "('foo')" |
7043 | end |
7044 | end |
7045 | describe 'Nodes::NotEqual' do |
7046 | val = Nodes.build_quoted(false, @table[:active]) |
7047 | sql.must_be_like %{ "users"."active" != 'f' } |
7048 | end |
7049 | val = Nodes.build_quoted(nil, @table[:active]) |
7050 | sql.must_be_like %{ "users"."name" IS NOT NULL } |
7051 | end |
7052 | end |
7053 | [ |
7054 | Class.new(String).new(":'("), |
7055 | Class.new(Class.new(String)).new(":'("), |
7056 | ].each do |obj| |
7057 | val = Nodes.build_quoted(obj, @table[:active]) |
7058 | sql.must_be_like %{ "users"."name" != ':\\'(' } |
7059 | end |
7060 | end |
7061 | end |
7062 | sc = Arel::Nodes::SelectStatement.new |
7063 | assert_match(/LIMIT 'omg'/, compile(sc)) |
7064 | end |
7065 | table = Table.new(:users) |
7066 | test = table.order(table[:name]) |
7067 | sql = compile test |
7068 | assert_match(/"users" ORDER BY/, sql) |
7069 | end |
7070 | table = Table.new(:users) |
7071 | sc = table.where(table[:name].eq(0)).take(1).ast |
7072 | end |
7073 | called_with = nil |
7074 | @conn.connection.extend(Module.new { |
7075 | define_method(:quote) do |thing, column| |
7076 | called_with = column |
7077 | super(thing, column) |
7078 | end |
7079 | }) |
7080 | dt = DateTime.now |
7081 | table = Table.new(:users) |
7082 | test = table[:created_at].eq dt |
7083 | sql = compile test |
7084 | assert_equal "created_at", called_with.name |
7085 | end |
7086 | test = Table.new(:products)[:price].eq 2.14 |
7087 | sql = compile test |
7088 | sql.must_be_like %{"products"."price" = 2.14} |
7089 | end |
7090 | sql = compile Nodes::Not.new(Arel.sql("foo")) |
7091 | sql.must_be_like "NOT (foo)" |
7092 | end |
7093 | sql = compile Nodes::Not.new(node) |
7094 | end |
7095 | sql = compile as |
7096 | sql.must_be_like "foo AS bar" |
7097 | end |
7098 | compile 8787878092 |
7099 | end |
7100 | compile(Nodes.build_quoted({:a = 1})) |
7101 | end |
7102 | compile Nodes.build_quoted(Set.new([1, 2])) |
7103 | end |
7104 | end |
7105 | called_with = nil |
7106 | @conn.connection.extend(Module.new { |
7107 | define_method(:quote) do |thing, column| |
7108 | called_with = column |
7109 | super(thing, column) |
7110 | end |
7111 | }) |
7112 | dt = Date.today |
7113 | table = Table.new(:users) |
7114 | test = table[:created_at].eq dt |
7115 | sql = compile test |
7116 | assert_equal "created_at", called_with.name |
7117 | end |
7118 | end |
7119 | assert_match(/\Aunsupported/, error.message) |
7120 | end |
7121 | mgr = Table.new(:foo).project(:bar) |
7122 | end |
7123 | compile(node).must_be_like %{ |
7124 | "users"."id" = 10 AND "users"."id" = 11 |
7125 | } |
7126 | end |
7127 | node = Nodes::Or.new @attr.eq(10), @attr.eq(11) |
7128 | compile(node).must_be_like %{ |
7129 | "users"."id" = 10 OR "users"."id" = 11 |
7130 | } |
7131 | end |
7132 | column = @table["id"] |
7133 | node = Nodes::Assignment.new( |
7134 | Nodes::UnqualifiedColumn.new(column), |
7135 | Nodes::UnqualifiedColumn.new(column) |
7136 | ) |
7137 | compile(node).must_be_like %{ |
7138 | "id" = "id" |
7139 | } |
7140 | end |
7141 | compile attr |
7142 | end |
7143 | test = Table.new(:users)[:bool].eq(true) |
7144 | end |
7145 | describe "Nodes::Matches" do |
7146 | node = @table[:name].matches('foo%') |
7147 | compile(node).must_be_like %{ |
7148 | "users"."name" LIKE 'foo%' |
7149 | } |
7150 | end |
7151 | node = @table[:name].matches('foo!%', '!') |
7152 | compile(node).must_be_like %{ |
7153 | "users"."name" LIKE 'foo!%' ESCAPE '!' |
7154 | } |
7155 | end |
7156 | node = @attr.in subquery |
7157 | compile(node).must_be_like %{ |
7158 | } |
7159 | end |
7160 | end |
7161 | describe "Nodes::DoesNotMatch" do |
7162 | node = @table[:name].does_not_match('foo%') |
7163 | compile(node).must_be_like %{ |
7164 | "users"."name" NOT LIKE 'foo%' |
7165 | } |
7166 | end |
7167 | node = @table[:name].does_not_match('foo!%', '!') |
7168 | compile(node).must_be_like %{ |
7169 | "users"."name" NOT LIKE 'foo!%' ESCAPE '!' |
7170 | } |
7171 | end |
7172 | node = @attr.in subquery |
7173 | compile(node).must_be_like %{ |
7174 | } |
7175 | end |
7176 | end |
7177 | describe "Nodes::Ordering" do |
7178 | node = @attr.desc |
7179 | compile(node).must_be_like %{ |
7180 | "users"."id" DESC |
7181 | } |
7182 | end |
7183 | end |
7184 | describe "Nodes::In" do |
7185 | node = @attr.in [1, 2, 3] |
7186 | compile(node).must_be_like %{ |
7187 | "users"."id" IN (1, 2, 3) |
7188 | } |
7189 | end |
7190 | node = @attr.in [] |
7191 | compile(node).must_equal '1=0' |
7192 | end |
7193 | node = @attr.between 1..3 |
7194 | compile(node).must_be_like %{ |
7195 | "users"."id" BETWEEN 1 AND 3 |
7196 | } |
7197 | end |
7198 | node = @attr.between 1...3 |
7199 | compile(node).must_be_like %{ |
7200 | "users"."id" = 1 AND "users"."id" 3 |
7201 | } |
7202 | end |
7203 | node = @attr.between 1..Float::INFINITY |
7204 | compile(node).must_be_like %{ |
7205 | "users"."id" = 1 |
7206 | } |
7207 | node = @attr.between(-Float::INFINITY..3) |
7208 | compile(node).must_be_like %{ |
7209 | "users"."id" = 3 |
7210 | } |
7211 | node = @attr.between(-Float::INFINITY...3) |
7212 | compile(node).must_be_like %{ |
7213 | "users"."id" 3 |
7214 | } |
7215 | compile(node).must_be_like %{1=1} |
7216 | end |
7217 | table = Table.new(:users) |
7218 | node = @attr.in subquery |
7219 | compile(node).must_be_like %{ |
7220 | } |
7221 | end |
7222 | @attr = Table.new(:users)[:name] |
7223 | visitor = Class.new(ToSql) do |
7224 | attr_accessor :expected |
7225 | def quote value, column = nil |
7226 | raise unless column == expected |
7227 | super |
7228 | end |
7229 | end |
7230 | in_node = Nodes::In.new @attr, vals |
7231 | visitor = visitor.new(Table.engine.connection) |
7232 | x.name == 'name' |
7233 | } |
7234 | end |
7235 | end |
7236 | describe "Nodes::InfixOperation" do |
7237 | end |
7238 | end |
7239 | end |
7240 | end |
7241 | node = Arel::Nodes::InfixOperation.new( |
7242 | '||', |
7243 | ) |
7244 | end |
7245 | end |
7246 | describe "Nodes::NotIn" do |
7247 | node = @attr.not_in [1, 2, 3] |
7248 | compile(node).must_be_like %{ |
7249 | "users"."id" NOT IN (1, 2, 3) |
7250 | } |
7251 | end |
7252 | node = @attr.not_in [] |
7253 | compile(node).must_equal '1=1' |
7254 | end |
7255 | node = @attr.not_between 1..3 |
7256 | compile(node).must_equal( |
7257 | %{("users"."id" 1 OR "users"."id" 3)} |
7258 | ) |
7259 | end |
7260 | node = @attr.not_between 1...3 |
7261 | compile(node).must_equal( |
7262 | %{("users"."id" 1 OR "users"."id" = 3)} |
7263 | ) |
7264 | end |
7265 | node = @attr.not_between 1..Float::INFINITY |
7266 | compile(node).must_be_like %{ |
7267 | "users"."id" 1 |
7268 | } |
7269 | node = @attr.not_between(-Float::INFINITY..3) |
7270 | compile(node).must_be_like %{ |
7271 | "users"."id" 3 |
7272 | } |
7273 | node = @attr.not_between(-Float::INFINITY...3) |
7274 | compile(node).must_be_like %{ |
7275 | "users"."id" = 3 |
7276 | } |
7277 | compile(node).must_be_like %{1=0} |
7278 | end |
7279 | table = Table.new(:users) |
7280 | node = @attr.not_in subquery |
7281 | compile(node).must_be_like %{ |
7282 | } |
7283 | end |
7284 | @attr = Table.new(:users)[:name] |
7285 | visitor = Class.new(ToSql) do |
7286 | attr_accessor :expected |
7287 | def quote value, column = nil |
7288 | raise unless column == expected |
7289 | super |
7290 | end |
7291 | end |
7292 | in_node = Nodes::NotIn.new @attr, vals |
7293 | visitor = visitor.new(Table.engine.connection) |
7294 | x.name == 'name' |
7295 | } |
7296 | end |
7297 | end |
7298 | describe 'Constants' do |
7299 | test = Table.new(:users).create_true |
7300 | compile(test).must_be_like %{ |
7301 | TRUE |
7302 | } |
7303 | end |
7304 | test = Table.new(:users).create_false |
7305 | compile(test).must_be_like %{ |
7306 | FALSE |
7307 | } |
7308 | end |
7309 | end |
7310 | describe 'TableAlias' do |
7311 | compile(test).must_be_like %{ |
7312 | "zomgusers"."id" = 3 |
7313 | } |
7314 | end |
7315 | end |
7316 | describe 'distinct on' do |
7317 | core = Arel::Nodes::SelectCore.new |
7318 | assert_raises(NotImplementedError) do |
7319 | compile(core) |
7320 | end |
7321 | end |
7322 | end |
7323 | describe 'Nodes::Regexp' do |
7324 | assert_raises(NotImplementedError) do |
7325 | compile(node) |
7326 | end |
7327 | end |
7328 | end |
7329 | describe 'Nodes::NotRegexp' do |
7330 | assert_raises(NotImplementedError) do |
7331 | compile(node) |
7332 | end |
7333 | end |
7334 | end |
7335 | end |
7336 | end |
7337 | end |
7338 | require 'active_support' |
7339 | require 'active_support/core_ext/array/access' |
7340 | require 'global_id/uri/gid' |
7341 | class GlobalID |
7342 | class self |
7343 | attr_reader :app |
7344 | def create(model, options = {}) |
7345 | if app = options.fetch(:app) { GlobalID.app } |
7346 | params = options.except(:app, :verifier, :for) |
7347 | new URI::GID.create(app, model, params), options |
7348 | else |
7349 | end |
7350 | end |
7351 | def find(gid, options = {}) |
7352 | parse(gid, options).try(:find, options) |
7353 | end |
7354 | def parse(gid, options = {}) |
7355 | gid.is_a?(self) ? gid : new(gid, options) |
7356 | rescue URI::Error |
7357 | parse_encoded_gid(gid, options) |
7358 | end |
7359 | def app=(app) |
7360 | @app = URI::GID.validate_app(app) |
7361 | end |
7362 | private |
7363 | def parse_encoded_gid(gid, options) |
7364 | end |
7365 | def repad_gid(gid) |
7366 | gid + ('=' * padding_chars) |
7367 | end |
7368 | end |
7369 | attr_reader :uri |
7370 | def initialize(gid, options = {}) |
7371 | end |
7372 | def find(options = {}) |
7373 | Locator.locate self, options |
7374 | end |
7375 | def model_class |
7376 | model_name.constantize |
7377 | end |
7378 | def ==(other) |
7379 | other.is_a?(GlobalID) && @uri == other.uri |
7380 | end |
7381 | def to_param |
7382 | Base64.urlsafe_encode64(to_s).sub(/=+$/, '') |
7383 | end |
7384 | end |
7385 | require 'active_support/concern' |
7386 | class GlobalID |
7387 | module Identification |
7388 | extend ActiveSupport::Concern |
7389 | def to_global_id(options = {}) |
7390 | @global_id ||= GlobalID.create(self, options) |
7391 | end |
7392 | alias to_gid to_global_id |
7393 | def to_gid_param(options = {}) |
7394 | to_global_id(options).to_param |
7395 | end |
7396 | def to_signed_global_id(options = {}) |
7397 | SignedGlobalID.create(self, options) |
7398 | end |
7399 | alias to_sgid to_signed_global_id |
7400 | def to_sgid_param(options = {}) |
7401 | to_signed_global_id(options).to_param |
7402 | end |
7403 | end |
7404 | end |
7405 | require 'active_support' |
7406 | class GlobalID |
7407 | module Locator |
7408 | class self |
7409 | def locate(gid, options = {}) |
7410 | if gid = GlobalID.parse(gid) |
7411 | end |
7412 | end |
7413 | def locate_many(gids, options = {}) |
7414 | locator = locator_for(allowed_gids.first) |
7415 | locator.locate_many(allowed_gids, options) |
7416 | else |
7417 | [] |
7418 | end |
7419 | end |
7420 | def locate_signed(sgid, options = {}) |
7421 | SignedGlobalID.find sgid, options |
7422 | end |
7423 | def locate_many_signed(sgids, options = {}) |
7424 | end |
7425 | def use(app, locator = nil, &locator_block) |
7426 | URI::GID.validate_app(app) |
7427 | end |
7428 | private |
7429 | def locator_for(gid) |
7430 | end |
7431 | def find_allowed?(model_class, only = nil) |
7432 | end |
7433 | def parse_allowed(gids, only = nil) |
7434 | end |
7435 | def normalize_app(app) |
7436 | app.to_s.downcase |
7437 | end |
7438 | end |
7439 | private |
7440 | @locators = {} |
7441 | class ActiveRecordFinder |
7442 | def locate(gid) |
7443 | gid.model_class.find gid.model_id |
7444 | end |
7445 | def locate_many(gids, options = {}) |
7446 | ids_by_model = models_and_ids.group_by(&:first) |
7447 | }] |
7448 | end |
7449 | private |
7450 | def find_records(model_class, ids, options) |
7451 | if options[:ignore_missing] |
7452 | model_class.where(id: ids) |
7453 | else |
7454 | model_class.find(ids) |
7455 | end |
7456 | end |
7457 | end |
7458 | class BlockLocator |
7459 | def initialize(block) |
7460 | @locator = block |
7461 | end |
7462 | def locate(gid) |
7463 | @locator.call(gid) |
7464 | end |
7465 | def locate_many(gids, options = {}) |
7466 | gids.map { |gid| locate(gid) } |
7467 | end |
7468 | end |
7469 | end |
7470 | end |
7471 | begin |
7472 | require 'rails/railtie' |
7473 | rescue LoadError |
7474 | else |
7475 | require 'global_id' |
7476 | require 'active_support' |
7477 | class GlobalID |
7478 | class Railtie Rails::Railtie # :nodoc: |
7479 | initializer 'global_id' do |app| |
7480 | GlobalID.app = app.config.global_id.app |
7481 | app.config.global_id.expires_in ||= 1.month |
7482 | config.after_initialize do |
7483 | app.config.global_id.verifier ||= begin |
7484 | app.message_verifier(:signed_global_ids) |
7485 | rescue ArgumentError |
7486 | nil |
7487 | end |
7488 | end |
7489 | ActiveSupport.on_load(:active_record) do |
7490 | require 'global_id/identification' |
7491 | send :include, GlobalID::Identification |
7492 | end |
7493 | end |
7494 | end |
7495 | end |
7496 | end |
7497 | require 'global_id' |
7498 | require 'active_support/message_verifier' |
7499 | require 'time' |
7500 | class SignedGlobalID GlobalID |
7501 | class ExpiredMessage StandardError; end |
7502 | class self |
7503 | attr_accessor :verifier |
7504 | def parse(sgid, options = {}) |
7505 | if sgid.is_a? self |
7506 | sgid |
7507 | else |
7508 | super verify(sgid, options), options |
7509 | end |
7510 | end |
7511 | def pick_verifier(options) |
7512 | options.fetch :verifier do |
7513 | end |
7514 | end |
7515 | attr_accessor :expires_in |
7516 | DEFAULT_PURPOSE = "default" |
7517 | def pick_purpose(options) |
7518 | options.fetch :for, DEFAULT_PURPOSE |
7519 | end |
7520 | private |
7521 | def verify(sgid, options) |
7522 | metadata = pick_verifier(options).verify(sgid) |
7523 | raise_if_expired(metadata['expires_at']) |
7524 | nil |
7525 | end |
7526 | def raise_if_expired(expires_at) |
7527 | end |
7528 | end |
7529 | end |
7530 | attr_reader :verifier, :purpose, :expires_at |
7531 | def initialize(gid, options = {}) |
7532 | super |
7533 | @verifier = self.class.pick_verifier(options) |
7534 | @purpose = self.class.pick_purpose(options) |
7535 | @expires_at = pick_expiration(options) |
7536 | end |
7537 | def to_s |
7538 | @sgid ||= @verifier.generate(to_h) |
7539 | end |
7540 | alias to_param to_s |
7541 | def to_h |
7542 | end |
7543 | def ==(other) |
7544 | super && @purpose == other.purpose |
7545 | end |
7546 | private |
7547 | def encoded_expiration |
7548 | expires_at.utc.iso8601(3) if expires_at |
7549 | end |
7550 | def pick_expiration(options) |
7551 | expires_in.from_now |
7552 | end |
7553 | end |
7554 | end |
7555 | require 'uri/generic' |
7556 | require 'active_support/core_ext/module/aliasing' |
7557 | require 'active_support/core_ext/object/blank' |
7558 | module URI |
7559 | class GID Generic |
7560 | alias :app :host |
7561 | attr_reader :model_name, :model_id, :params |
7562 | class self |
7563 | def validate_app(app) |
7564 | parse("gid://#{app}/Model/1").app |
7565 | rescue URI::Error |
7566 | raise ArgumentError, 'Invalid app name. ' \ |
7567 | end |
7568 | def parse(uri) |
7569 | new(*generic_components) |
7570 | end |
7571 | def create(app, model, params = nil) |
7572 | end |
7573 | def build(args) |
7574 | parts = Util.make_components_hash(self, args) |
7575 | parts[:host] = parts[:app] |
7576 | if parts[:params] && !parts[:params].empty? |
7577 | end |
7578 | super parts |
7579 | end |
7580 | end |
7581 | def to_s |
7582 | "gid://#{app}#{path}#{'?' + query if query}" |
7583 | end |
7584 | protected |
7585 | def set_path(path) |
7586 | super |
7587 | end |
7588 | def query=(query) |
7589 | set_params parse_query_params(query) |
7590 | super |
7591 | end |
7592 | def set_query(query) |
7593 | set_params parse_query_params(query) |
7594 | super |
7595 | end |
7596 | def set_params(params) |
7597 | @params = params |
7598 | end |
7599 | private |
7600 | PATH_REGEXP = %r(\A/([^/]+)/?([^/]+)?\z) |
7601 | def check_host(host) |
7602 | validate_component(host) |
7603 | super |
7604 | end |
7605 | def check_path(path) |
7606 | validate_component(path) |
7607 | set_model_components(path, true) |
7608 | end |
7609 | def check_scheme(scheme) |
7610 | if scheme == 'gid' |
7611 | super |
7612 | else |
7613 | end |
7614 | end |
7615 | def set_model_components(path, validate = false) |
7616 | model_id = CGI.unescape(model_id) if model_id |
7617 | @model_name = model_name |
7618 | @model_id = model_id |
7619 | end |
7620 | def validate_component(component) |
7621 | return component unless component.blank? |
7622 | raise URI::InvalidComponentError, |
7623 | end |
7624 | def validate_model_id(model_id, model_name) |
7625 | return model_id unless model_id.blank? |
7626 | "#{model_name} without a model id." |
7627 | end |
7628 | def parse_query_params(query) |
7629 | end |
7630 | end |
7631 | @@schemes['GID'] = GID |
7632 | end |
7633 | require 'global_id/global_id' |
7634 | class GlobalID |
7635 | autoload :Locator, 'global_id/locator' |
7636 | end |
7637 | require 'global_id' |
7638 | require 'global_id/railtie' |
7639 | require 'helper' |
7640 | class GlobalIDTest ActiveSupport::TestCase |
7641 | test 'value equality' do |
7642 | end |
7643 | test 'invalid app name' do |
7644 | assert_raises ArgumentError do |
7645 | GlobalID.app = '' |
7646 | end |
7647 | assert_raises ArgumentError do |
7648 | GlobalID.app = 'blog_app' |
7649 | end |
7650 | assert_raises ArgumentError do |
7651 | GlobalID.app = nil |
7652 | end |
7653 | end |
7654 | end |
7655 | setup do |
7656 | model = Person.new('id') |
7657 | @gid = GlobalID.create(model) |
7658 | end |
7659 | test 'parsing' do |
7660 | assert_equal GlobalID.parse(@gid.to_param), @gid |
7661 | end |
7662 | test 'finding' do |
7663 | found = GlobalID.find(@gid.to_param) |
7664 | assert_kind_of @gid.model_class, found |
7665 | assert_equal @gid.model_id, found.id |
7666 | end |
7667 | end |
7668 | setup do |
7669 | @uuid = '7ef9b614-353c-43a1-a203-ab2307851990' |
7670 | @person_gid = GlobalID.create(Person.new(5)) |
7671 | end |
7672 | test 'find' do |
7673 | end |
7674 | test 'find with class' do |
7675 | end |
7676 | test 'find with class no match' do |
7677 | assert_nil @person_gid.find(only: Hash) |
7678 | assert_nil @person_uuid_gid.find(only: Array) |
7679 | assert_nil @person_model_gid.find(only: Float) |
7680 | end |
7681 | test 'find with subclass' do |
7682 | @person_namespaced_gid.find(only: Person) |
7683 | end |
7684 | test 'find with subclass no match' do |
7685 | end |
7686 | test 'find with module' do |
7687 | @person_model_gid.find(only: ActiveModel::Model) |
7688 | end |
7689 | test 'find with module no match' do |
7690 | assert_nil @person_gid.find(only: Enumerable) |
7691 | end |
7692 | test 'find with multiple class' do |
7693 | end |
7694 | test 'find with multiple class no match' do |
7695 | end |
7696 | test 'find with multiple module' do |
7697 | assert_equal Person.find(@person_gid.model_id), |
7698 | end |
7699 | test 'find with multiple module no match' do |
7700 | end |
7701 | test 'as string' do |
7702 | end |
7703 | test 'as param' do |
7704 | end |
7705 | test 'as URI' do |
7706 | end |
7707 | test 'model id' do |
7708 | assert_equal '5', @person_gid.model_id |
7709 | assert_equal @uuid, @person_uuid_gid.model_id |
7710 | assert_equal '4', @person_namespaced_gid.model_id |
7711 | assert_equal '1', @person_model_gid.model_id |
7712 | end |
7713 | test 'model name' do |
7714 | assert_equal 'Person', @person_gid.model_name |
7715 | end |
7716 | test 'model class' do |
7717 | assert_equal Person, @person_gid.model_class |
7718 | assert_equal Person, @person_uuid_gid.model_class |
7719 | end |
7720 | test ':app option' do |
7721 | person_gid = GlobalID.create(Person.new(5)) |
7722 | assert_raise ArgumentError do |
7723 | end |
7724 | end |
7725 | end |
7726 | test 'create custom params' do |
7727 | assert_equal 'world', gid.params[:hello] |
7728 | end |
7729 | test 'parse custom params' do |
7730 | assert_equal 'world', gid.params[:hello] |
7731 | end |
7732 | end |
7733 | require 'helper' |
7734 | setup do |
7735 | @model = PersonModel.new id: 1 |
7736 | end |
7737 | test 'creates a Global ID from self' do |
7738 | end |
7739 | test 'creates a Global ID with custom params' do |
7740 | end |
7741 | test 'creates a signed Global ID from self' do |
7742 | end |
7743 | end |
7744 | end |
7745 | end |
7746 | require 'helper' |
7747 | class GlobalLocatorTest ActiveSupport::TestCase |
7748 | setup do |
7749 | model = Person.new('id') |
7750 | @gid = model.to_gid |
7751 | @sgid = model.to_sgid |
7752 | end |
7753 | test 'by GID' do |
7754 | found = GlobalID::Locator.locate(@gid) |
7755 | assert_kind_of @gid.model_class, found |
7756 | assert_equal @gid.model_id, found.id |
7757 | end |
7758 | assert_kind_of @gid.model_class, found |
7759 | assert_equal @gid.model_id, found.id |
7760 | end |
7761 | instance = Person::Child.new |
7762 | gid = instance.to_gid |
7763 | assert_kind_of gid.model_class, found |
7764 | assert_equal gid.model_id, found.id |
7765 | end |
7766 | assert_nil found |
7767 | end |
7768 | assert_kind_of @gid.model_class, found |
7769 | assert_equal @gid.model_id, found.id |
7770 | end |
7771 | test 'by GID with only: restriction by module' do |
7772 | assert_kind_of @gid.model_class, found |
7773 | assert_equal @gid.model_id, found.id |
7774 | end |
7775 | assert_nil found |
7776 | end |
7777 | assert_kind_of @gid.model_class, found |
7778 | assert_equal @gid.model_id, found.id |
7779 | end |
7780 | test 'by many GIDs of one class' do |
7781 | end |
7782 | test 'by many GIDs of mixed classes' do |
7783 | end |
7784 | assert_equal [ Person::Child.new('1') ], |
7785 | end |
7786 | test 'by SGID' do |
7787 | found = GlobalID::Locator.locate_signed(@sgid) |
7788 | assert_kind_of @sgid.model_class, found |
7789 | assert_equal @sgid.model_id, found.id |
7790 | end |
7791 | assert_kind_of @sgid.model_class, found |
7792 | assert_equal @sgid.model_id, found.id |
7793 | end |
7794 | instance = Person::Child.new |
7795 | sgid = instance.to_sgid |
7796 | assert_kind_of sgid.model_class, found |
7797 | assert_equal sgid.model_id, found.id |
7798 | end |
7799 | assert_nil found |
7800 | end |
7801 | assert_kind_of @sgid.model_class, found |
7802 | assert_equal @sgid.model_id, found.id |
7803 | end |
7804 | assert_kind_of @sgid.model_class, found |
7805 | assert_equal @sgid.model_id, found.id |
7806 | end |
7807 | assert_nil found |
7808 | end |
7809 | assert_kind_of @sgid.model_class, found |
7810 | assert_equal @sgid.model_id, found.id |
7811 | end |
7812 | test 'by many SGIDs of one class' do |
7813 | end |
7814 | test 'by many SGIDs of mixed classes' do |
7815 | end |
7816 | assert_equal [ Person::Child.new('1') ], |
7817 | end |
7818 | test 'by GID string' do |
7819 | found = GlobalID::Locator.locate(@gid.to_s) |
7820 | assert_kind_of @gid.model_class, found |
7821 | assert_equal @gid.model_id, found.id |
7822 | end |
7823 | test 'by SGID string' do |
7824 | assert_kind_of @sgid.model_class, found |
7825 | assert_equal @sgid.model_id, found.id |
7826 | end |
7827 | assert_equal [ Person::Child.new('2') ], |
7828 | end |
7829 | test 'by to_param encoding' do |
7830 | found = GlobalID::Locator.locate(@gid.to_param) |
7831 | assert_kind_of @gid.model_class, found |
7832 | assert_equal @gid.model_id, found.id |
7833 | end |
7834 | test 'by non-GID returns nil' do |
7835 | end |
7836 | test 'by non-SGID returns nil' do |
7837 | end |
7838 | test 'by invalid GID URI returns nil' do |
7839 | end |
7840 | test 'use locator with block' do |
7841 | GlobalID::Locator.use :foo do |gid| |
7842 | :foo |
7843 | end |
7844 | with_app 'foo' do |
7845 | end |
7846 | end |
7847 | test 'use locator with class' do |
7848 | class BarLocator |
7849 | def locate(gid); :bar; end |
7850 | end |
7851 | GlobalID::Locator.use :bar, BarLocator.new |
7852 | with_app 'bar' do |
7853 | end |
7854 | end |
7855 | test 'app locator is case insensitive' do |
7856 | GlobalID::Locator.use :insensitive do |gid| |
7857 | :insensitive |
7858 | end |
7859 | with_app 'insensitive' do |
7860 | end |
7861 | end |
7862 | test 'locator name cannot have underscore' do |
7863 | assert_raises ArgumentError do |
7864 | end |
7865 | end |
7866 | test "by valid purpose returns right model" do |
7867 | instance = Person.new |
7868 | assert_kind_of login_sgid.model_class, found |
7869 | assert_equal login_sgid.model_id, found.id |
7870 | end |
7871 | test "by invalid purpose returns nil" do |
7872 | instance = Person.new |
7873 | end |
7874 | assert_raises RuntimeError do |
7875 | end |
7876 | end |
7877 | assert_nothing_raised do |
7878 | end |
7879 | end |
7880 | private |
7881 | def with_app(app) |
7882 | old_app, GlobalID.app = GlobalID.app, app |
7883 | yield |
7884 | ensure |
7885 | GlobalID.app = old_app |
7886 | end |
7887 | end |
7888 | require 'rails' |
7889 | require 'global_id/railtie' |
7890 | require 'active_support/testing/isolation' |
7891 | module BlogApp |
7892 | class Application Rails::Application; end |
7893 | end |
7894 | class RailtieTest ActiveSupport::TestCase |
7895 | include ActiveSupport::Testing::Isolation |
7896 | def setup |
7897 | Rails.env = 'development' |
7898 | @app = BlogApp::Application.new |
7899 | @app.config.eager_load = false |
7900 | @app.config.logger = Logger.new(nil) |
7901 | end |
7902 | @app.initialize! |
7903 | assert_equal 'blog-app', GlobalID.app |
7904 | end |
7905 | @app.config.global_id.app = 'foo' |
7906 | @app.initialize! |
7907 | assert_equal 'foo', GlobalID.app |
7908 | end |
7909 | @app.config.secret_token = ('x' * 30) |
7910 | @app.initialize! |
7911 | message = {id: 42} |
7912 | end |
7913 | @app.initialize! |
7914 | assert_nil SignedGlobalID.verifier |
7915 | end |
7916 | @app.initialize! |
7917 | message = {id: 42} |
7918 | end |
7919 | end |
7920 | require 'helper' |
7921 | class SignedGlobalIDTest ActiveSupport::TestCase |
7922 | setup do |
7923 | end |
7924 | test 'as string' do |
7925 | end |
7926 | test 'model id' do |
7927 | assert_equal "5", @person_sgid.model_id |
7928 | end |
7929 | test 'model class' do |
7930 | assert_equal Person, @person_sgid.model_class |
7931 | end |
7932 | test 'value equality' do |
7933 | end |
7934 | test 'value equality with an unsigned id' do |
7935 | end |
7936 | test 'to param' do |
7937 | end |
7938 | end |
7939 | setup do |
7940 | end |
7941 | gid = @person_sgid.to_s |
7942 | with_default_verifier nil do |
7943 | assert_raise ArgumentError do |
7944 | SignedGlobalID.parse(gid) |
7945 | end |
7946 | end |
7947 | end |
7948 | with_default_verifier nil do |
7949 | assert_raise ArgumentError do |
7950 | SignedGlobalID.create(Person.new(5)) |
7951 | end |
7952 | end |
7953 | end |
7954 | test 'create accepts a :verifier' do |
7955 | with_default_verifier nil do |
7956 | assert_equal @person_sgid, expected |
7957 | end |
7958 | end |
7959 | test 'new accepts a :verifier' do |
7960 | with_default_verifier nil do |
7961 | assert_equal @person_sgid, expected |
7962 | end |
7963 | end |
7964 | def with_default_verifier(verifier) |
7965 | yield |
7966 | ensure |
7967 | SignedGlobalID.verifier = original |
7968 | end |
7969 | end |
7970 | setup do |
7971 | end |
7972 | test 'sign with purpose when :for is provided' do |
7973 | end |
7974 | sgid = SignedGlobalID.create(Person.new(5)) |
7975 | assert_equal sgid, default_sgid |
7976 | end |
7977 | test 'create accepts a :for' do |
7978 | assert_equal @login_sgid, expected |
7979 | end |
7980 | test 'new accepts a :for' do |
7981 | assert_equal @login_sgid, expected |
7982 | end |
7983 | test 'parse returns nil when purpose mismatch' do |
7984 | sgid = @login_sgid.to_s |
7985 | assert_nil SignedGlobalID.parse sgid |
7986 | end |
7987 | test 'equal only with same purpose' do |
7988 | assert_equal @login_sgid, expected |
7989 | assert_not_equal @login_sgid, like_sgid |
7990 | assert_not_equal @login_sgid, no_purpose_sgid |
7991 | end |
7992 | end |
7993 | setup do |
7994 | @uri = Person.new(5).to_gid.uri |
7995 | end |
7996 | with_expiration_in 1.hour do |
7997 | encoded_sgid = SignedGlobalID.new(@uri).to_s |
7998 | travel 59.minutes |
7999 | assert SignedGlobalID.parse(encoded_sgid) |
8000 | travel 2.minutes |
8001 | assert_not SignedGlobalID.parse(encoded_sgid) |
8002 | end |
8003 | end |
8004 | with_expiration_in 1.hour do |
8005 | travel 1.hour |
8006 | assert SignedGlobalID.parse(encoded_sgid) |
8007 | travel 1.hour + 3.seconds |
8008 | assert_not SignedGlobalID.parse(encoded_sgid) |
8009 | end |
8010 | end |
8011 | present = Time.now |
8012 | Time.stub :now, present + 0.5.second do |
8013 | assert SignedGlobalID.parse(encoded_sgid) |
8014 | end |
8015 | Time.stub :now, present + 2.seconds do |
8016 | assert_not SignedGlobalID.parse(encoded_sgid) |
8017 | end |
8018 | end |
8019 | with_expiration_in 1.hour do |
8020 | travel 1.hour |
8021 | assert SignedGlobalID.parse(encoded_sgid) |
8022 | travel 1.hour |
8023 | assert SignedGlobalID.parse(encoded_sgid) |
8024 | end |
8025 | end |
8026 | test 'passing expires_at sets expiration date' do |
8027 | date = Date.today.end_of_day |
8028 | sgid = SignedGlobalID.new(@uri, expires_at: date) |
8029 | assert_equal date, sgid.expires_at |
8030 | travel 1.day |
8031 | assert_not SignedGlobalID.parse(sgid.to_s) |
8032 | end |
8033 | with_expiration_in 1.hour do |
8034 | travel 4.hours |
8035 | assert SignedGlobalID.parse(encoded_sgid) |
8036 | end |
8037 | end |
8038 | with_expiration_in 1.hour do |
8039 | date = Date.tomorrow.end_of_day |
8040 | sgid = SignedGlobalID.new(@uri, expires_at: date) |
8041 | assert_equal date, sgid.expires_at |
8042 | travel 2.hours |
8043 | assert SignedGlobalID.parse(sgid.to_s) |
8044 | end |
8045 | end |
8046 | test 'favor expires_at over expires_in' do |
8047 | travel 1.hour |
8048 | assert SignedGlobalID.parse(sgid.to_s) |
8049 | end |
8050 | private |
8051 | def with_expiration_in(expires_in) |
8052 | yield |
8053 | ensure |
8054 | SignedGlobalID.expires_in = old_expires |
8055 | end |
8056 | end |
8057 | test 'create custom params' do |
8058 | assert_equal 'world', sgid.params[:hello] |
8059 | end |
8060 | test 'parse custom params' do |
8061 | assert_equal 'world', sgid.params[:hello] |
8062 | end |
8063 | end |
8064 | require 'helper' |
8065 | class URI::GIDTest ActiveSupport::TestCase |
8066 | setup do |
8067 | @gid_string = 'gid://bcx/Person/5' |
8068 | @gid = URI::GID.parse(@gid_string) |
8069 | end |
8070 | test 'parsed' do |
8071 | assert_equal @gid.app, 'bcx' |
8072 | assert_equal @gid.model_name, 'Person' |
8073 | assert_equal @gid.model_id, '5' |
8074 | end |
8075 | assert URI::GID.new(*URI.split('gid:///')) |
8076 | end |
8077 | test 'create' do |
8078 | model = Person.new('5') |
8079 | end |
8080 | test 'build' do |
8081 | assert array |
8082 | assert hash |
8083 | assert_equal array, hash |
8084 | end |
8085 | end |
8086 | test 'as String' do |
8087 | assert_equal @gid_string, @gid.to_s |
8088 | end |
8089 | test 'equal' do |
8090 | assert_equal @gid, URI::GID.parse(@gid_string) |
8091 | end |
8092 | end |
8093 | test 'alphanumeric' do |
8094 | model = Person.new('John123') |
8095 | end |
8096 | test 'non-alphanumeric' do |
8097 | model = Person.new('John Doe-Smith/Jones') |
8098 | end |
8099 | end |
8100 | test 'alphanumeric' do |
8101 | end |
8102 | test 'non-alphanumeric' do |
8103 | end |
8104 | end |
8105 | test 'missing app' do |
8106 | assert_invalid_component 'gid:///Person/1' |
8107 | end |
8108 | test 'missing path' do |
8109 | assert_invalid_component 'gid://bcx/' |
8110 | end |
8111 | test 'missing model id' do |
8112 | end |
8113 | test 'too many model ids' do |
8114 | assert_invalid_component 'gid://bcx/Person/1/2' |
8115 | end |
8116 | test 'empty' do |
8117 | assert_invalid_component 'gid:///' |
8118 | end |
8119 | test 'invalid schemes' do |
8120 | assert_bad_uri 'http://bcx/Person/5' |
8121 | assert_bad_uri 'gyd://bcx/Person/5' |
8122 | assert_bad_uri '//bcx/Person/5' |
8123 | end |
8124 | private |
8125 | def assert_invalid_component(uri) |
8126 | end |
8127 | def assert_bad_uri(uri) |
8128 | end |
8129 | end |
8130 | test 'nil or blank apps are invalid' do |
8131 | assert_invalid_app nil |
8132 | assert_invalid_app '' |
8133 | end |
8134 | assert_invalid_app 'foo/bar' |
8135 | assert_invalid_app 'foo:bar' |
8136 | assert_invalid_app 'foo_bar' |
8137 | end |
8138 | test 'app with hyphen is allowed' do |
8139 | end |
8140 | private |
8141 | def assert_invalid_app(value) |
8142 | end |
8143 | end |
8144 | class URI::GIDParamsTest ActiveSupport::TestCase |
8145 | setup do |
8146 | end |
8147 | test 'indifferent key access' do |
8148 | assert_equal 'world', @gid.params[:hello] |
8149 | assert_equal 'world', @gid.params['hello'] |
8150 | end |
8151 | test 'integer option' do |
8152 | assert_equal '20', gid.params[:integer] |
8153 | end |
8154 | test 'multi value params returns last value' do |
8155 | exp = { 'multi' = 'two' } |
8156 | assert_equal exp, gid.params |
8157 | end |
8158 | test 'as String' do |
8159 | end |
8160 | test 'immutable params' do |
8161 | @gid.params[:param] = 'value' |
8162 | end |
8163 | end |
8164 | require 'bundler/setup' |
8165 | require 'active_support' |
8166 | require 'active_support/testing/autorun' |
8167 | require 'global_id' |
8168 | require 'models/person' |
8169 | require 'models/person_model' |
8170 | require 'json' |
8171 | ActiveSupport::TestCase.test_order = :random |
8172 | end |
8173 | GlobalID.app = 'bcx' |
8174 | SERIALIZER = JSON |
8175 | SignedGlobalID.verifier = VERIFIER |
8176 | class Person |
8177 | include GlobalID::Identification |
8178 | HARDCODED_ID_FOR_MISSING_PERSON = '1000' |
8179 | attr_reader :id |
8180 | def self.find(id_or_ids) |
8181 | if id_or_ids.is_a? Array |
8182 | ids = id_or_ids |
8183 | ids.collect { |id| find(id) } |
8184 | else |
8185 | id = id_or_ids |
8186 | if id == HARDCODED_ID_FOR_MISSING_PERSON |
8187 | raise 'Person missing' |
8188 | else |
8189 | new(id) |
8190 | end |
8191 | end |
8192 | end |
8193 | def self.where(conditions) |
8194 | end |
8195 | def initialize(id = 1) |
8196 | @id = id |
8197 | end |
8198 | def ==(other) |
8199 | other.is_a?(self.class) && id == other.try(:id) |
8200 | end |
8201 | end |
8202 | class Person::Child Person; end |
8203 | require 'active_model' |
8204 | class PersonModel |
8205 | include ActiveModel::Model |
8206 | include GlobalID::Identification |
8207 | attr_accessor :id |
8208 | def self.find(id) |
8209 | new id: id |
8210 | end |
8211 | def ==(other) |
8212 | id == other.try(:id) |
8213 | end |
8214 | end |
8215 | PATTERN_HTML = "\"((\\\\\"|[^\"])*)\"" |
8216 | def assert_select_jquery(*args, &block) |
8217 | id = args.first.is_a?(String) ? args.shift : nil |
8218 | pattern = "\\s*\\.#{jquery_method || '\\w+'}\\(" |
8219 | pattern = "#{pattern}#{PATTERN_HTML}" |
8220 | fragments = Nokogiri::HTML::Document.new |
8221 | doc.root.children.each do |child| |
8222 | fragments child if child.element? |
8223 | end |
8224 | end |
8225 | opts = [jquery_method, jquery_opt, id].compact |
8226 | flunk "No JQuery call matches #{opts.inspect}" |
8227 | end |
8228 | if block |
8229 | begin |
8230 | in_scope, @selected = @selected, fragments |
8231 | yield |
8232 | ensure |
8233 | @selected = in_scope |
8234 | end |
8235 | end |
8236 | end |
8237 | private |
8238 | def unescape_js(js_string) |
8239 | unescaped= js_string.gsub('\"', '"') |
8240 | unescaped.gsub!('\\\'', "'") |
8241 | unescaped.gsub!(/\\\//, '/') |
8242 | unescaped.gsub!(' ', " ") |
8243 | unescaped.gsub!('\076', '') |
8244 | unescaped.gsub!('\074', '') |
8245 | unescaped |
8246 | end |
8247 | end |
8248 | module Jquery |
8249 | module Rails |
8250 | class Engine ::Rails::Engine |
8251 | end |
8252 | end |
8253 | end |
8254 | module Jquery |
8255 | module Rails |
8256 | VERSION = "4.0.3" |
8257 | JQUERY_VERSION = "1.11.2" |
8258 | JQUERY_2_VERSION = "2.1.3" |
8259 | JQUERY_UJS_VERSION = "1.0.3" |
8260 | end |
8261 | end |
8262 | require 'jquery/rails/engine' |
8263 | require 'jquery/rails/version' |
8264 | module Jquery |
8265 | module Rails |
8266 | end |
8267 | end |
8268 | require 'jquery/rails'module Mail |
8269 | class AttachmentsList Array |
8270 | def initialize(parts_list) |
8271 | @parts_list = parts_list |
8272 | @content_disposition_type = 'attachment' |
8273 | parts_list.map { |p| |
8274 | if p.content_type == "message/rfc822" |
8275 | Mail.new(p.body).attachments |
8276 | elsif p.parts.empty? |
8277 | p if p.attachment? |
8278 | else |
8279 | p.attachments |
8280 | end |
8281 | }.flatten.compact.each { |a| self a } |
8282 | self |
8283 | end |
8284 | def inline |
8285 | @content_disposition_type = 'inline' |
8286 | self |
8287 | end |
8288 | def [](index_value) |
8289 | if index_value.is_a?(Fixnum) |
8290 | self.fetch(index_value) |
8291 | else |
8292 | end |
8293 | end |
8294 | def []=(name, value) |
8295 | :content_transfer_encoding = "#{guess_encoding}", |
8296 | if value.is_a?(Hash) |
8297 | if encoding |
8298 | if Mail::Encodings.defined? encoding |
8299 | else |
8300 | end |
8301 | end |
8302 | if value[:mime_type] |
8303 | end |
8304 | hash = default_values.merge(value) |
8305 | else |
8306 | default_values[:body] = value |
8307 | hash = default_values |
8308 | end |
8309 | hash[:body].force_encoding("BINARY") |
8310 | end |
8311 | end |
8312 | attachment = Part.new(hash) |
8313 | attachment.add_content_id(hash[:content_id]) |
8314 | @parts_list attachment |
8315 | end |
8316 | def guess_encoding |
8317 | if @mime_type && !@mime_type.binary? |
8318 | "7bit" |
8319 | else |
8320 | "binary" |
8321 | end |
8322 | end |
8323 | def set_mime_type(filename) |
8324 | if RUBY_VERSION = '1.9' |
8325 | end |
8326 | @mime_type = MIME::Types.type_for(filename).first |
8327 | end |
8328 | end |
8329 | end |
8330 | module Mail |
8331 | class Body |
8332 | def initialize(string = '') |
8333 | @boundary = nil |
8334 | @preamble = nil |
8335 | @epilogue = nil |
8336 | @charset = nil |
8337 | @parts = Mail::PartsList.new |
8338 | if string.blank? |
8339 | @raw_source = '' |
8340 | else |
8341 | if string.respond_to?(:join) |
8342 | @raw_source = string.join('') |
8343 | elsif string.respond_to?(:to_s) |
8344 | @raw_source = string.to_s |
8345 | else |
8346 | end |
8347 | end |
8348 | @encoding = (only_us_ascii? ? '7bit' : '8bit') |
8349 | set_charset |
8350 | end |
8351 | def ==(other) |
8352 | if other.class == String |
8353 | self.decoded == other |
8354 | else |
8355 | super |
8356 | end |
8357 | end |
8358 | def =~(regexp) |
8359 | self.decoded =~ regexp |
8360 | end |
8361 | def match(regexp) |
8362 | self.decoded.match(regexp) |
8363 | end |
8364 | def include?(other) |
8365 | self.decoded.include?(other.to_s) |
8366 | end |
8367 | def set_sort_order(order) |
8368 | @part_sort_order = order |
8369 | end |
8370 | def sort_parts! |
8371 | @parts.each do |p| |
8372 | p.body.set_sort_order(@part_sort_order) |
8373 | p.body.sort_parts! |
8374 | end |
8375 | @parts.sort!(@part_sort_order) |
8376 | end |
8377 | def raw_source |
8378 | @raw_source |
8379 | end |
8380 | def get_best_encoding(target) |
8381 | end |
8382 | def encoded(transfer_encoding = '8bit') |
8383 | if multipart? |
8384 | self.sort_parts! |
8385 | encoded_parts = parts.map { |p| p.encoded } |
8386 | else |
8387 | be = get_best_encoding(transfer_encoding) |
8388 | dec = Mail::Encodings::get_encoding(encoding) |
8389 | enc = Mail::Encodings::get_encoding(be) |
8390 | if transfer_encoding == encoding and dec.nil? |
8391 | raw_source |
8392 | else |
8393 | decoded = dec.decode(raw_source) |
8394 | decoded.encode!(charset) |
8395 | end |
8396 | enc.encode(decoded) |
8397 | end |
8398 | end |
8399 | end |
8400 | def decoded |
8401 | if !Encodings.defined?(encoding) |
8402 | else |
8403 | end |
8404 | end |
8405 | def to_s |
8406 | decoded |
8407 | end |
8408 | def charset |
8409 | @charset |
8410 | end |
8411 | def charset=( val ) |
8412 | @charset = val |
8413 | end |
8414 | def encoding(val = nil) |
8415 | if val |
8416 | self.encoding = val |
8417 | else |
8418 | @encoding |
8419 | end |
8420 | end |
8421 | def encoding=( val ) |
8422 | @encoding = if val == "text" || val.blank? |
8423 | (only_us_ascii? ? '7bit' : '8bit') |
8424 | else |
8425 | val |
8426 | end |
8427 | end |
8428 | def preamble |
8429 | @preamble |
8430 | end |
8431 | def preamble=( val ) |
8432 | @preamble = val |
8433 | end |
8434 | def epilogue |
8435 | @epilogue |
8436 | end |
8437 | def epilogue=( val ) |
8438 | @epilogue = val |
8439 | end |
8440 | def multipart? |
8441 | true unless parts.empty? |
8442 | end |
8443 | def boundary |
8444 | @boundary |
8445 | end |
8446 | def boundary=( val ) |
8447 | @boundary = val |
8448 | end |
8449 | def parts |
8450 | @parts |
8451 | end |
8452 | def ( val ) |
8453 | if @parts |
8454 | @parts val |
8455 | else |
8456 | @parts = Mail::PartsList.new[val] |
8457 | end |
8458 | end |
8459 | def split!(boundary) |
8460 | self.boundary = boundary |
8461 | parts = extract_parts |
8462 | self.preamble = parts[0].to_s.strip |
8463 | self.epilogue = parts[-1].to_s.strip |
8464 | self |
8465 | end |
8466 | def only_us_ascii? |
8467 | !(raw_source =~ /[^\x01-\x7f]/) |
8468 | end |
8469 | def empty? |
8470 | !!raw_source.to_s.empty? |
8471 | end |
8472 | private |
8473 | def extract_parts |
8474 | parts_regex = / |
8475 | (?: # non-capturing group |
8476 | \A | # start of string OR |
8477 | \r # line break |
8478 | ) |
8479 | ( |
8480 | (?:--)? # with non-capturing optional closing |
8481 | ) |
8482 | /x |
8483 | if parts.size 1 |
8484 | final_separator = parts[-2][1] |
8485 | end |
8486 | parts.map(&:first) |
8487 | end |
8488 | def crlf_boundary |
8489 | "\r --#{boundary}\r " |
8490 | end |
8491 | def end_boundary |
8492 | "\r --#{boundary}--\r " |
8493 | end |
8494 | def set_charset |
8495 | end |
8496 | end |
8497 | end |
8498 | module Mail |
8499 | module CheckDeliveryParams |
8500 | def check_delivery_params(mail) |
8501 | if mail.smtp_envelope_from.blank? |
8502 | end |
8503 | if mail.smtp_envelope_to.blank? |
8504 | end |
8505 | if message.blank? |
8506 | end |
8507 | end |
8508 | end |
8509 | end |
8510 | require 'singleton' |
8511 | module Mail |
8512 | class Configuration |
8513 | include Singleton |
8514 | def initialize |
8515 | @delivery_method = nil |
8516 | @retriever_method = nil |
8517 | super |
8518 | end |
8519 | def delivery_method(method = nil, settings = {}) |
8520 | end |
8521 | def lookup_delivery_method(method) |
8522 | when nil |
8523 | Mail::SMTP |
8524 | when :smtp |
8525 | Mail::SMTP |
8526 | when :sendmail |
8527 | Mail::Sendmail |
8528 | when :exim |
8529 | Mail::Exim |
8530 | when :file |
8531 | Mail::FileDelivery |
8532 | when :smtp_connection |
8533 | Mail::SMTPConnection |
8534 | when :test |
8535 | Mail::TestMailer |
8536 | else |
8537 | method |
8538 | end |
8539 | end |
8540 | def retriever_method(method = nil, settings = {}) |
8541 | end |
8542 | def lookup_retriever_method(method) |
8543 | case method |
8544 | when nil |
8545 | Mail::POP3 |
8546 | when :pop3 |
8547 | Mail::POP3 |
8548 | when :imap |
8549 | Mail::IMAP |
8550 | when :test |
8551 | Mail::TestRetriever |
8552 | else |
8553 | method |
8554 | end |
8555 | end |
8556 | def param_encode_language(value = nil) |
8557 | end |
8558 | end |
8559 | end |
8560 | module Mail |
8561 | module Constants |
8562 | white_space = %Q|\x9\x20| |
8563 | text = %Q|\x1-\x8\xB\xC\xE-\x7f| |
8564 | field_name = %Q|\x21-\x39\x3b-\x7e| |
8565 | qp_safe = %Q|\x20-\x3c\x3e-\x7e| |
8566 | aspecial = %Q|()[]:;@\\,."| # RFC5322 |
8567 | tspecial = %Q|()@,;:\\"/[]?=| # RFC2045 |
8568 | sp = %Q| | |
8569 | control = %Q|\x00-\x1f\x7f-\xff| |
8570 | if control.respond_to?(:force_encoding) |
8571 | end |
8572 | CRLF = /\r / |
8573 | WSP = /[#{white_space}]/ |
8574 | FWS = /#{CRLF}#{WSP}*/ |
8575 | TEXT = /[#{text}]/ # + obs-text |
8576 | FIELD_NAME = /[#{field_name}]+/ |
8577 | FIELD_PREFIX = /\A(#{FIELD_NAME})/ |
8578 | FIELD_BODY = /.+/m |
8579 | FIELD_LINE = /^[#{field_name}]+:\s*.+$/ |
8580 | HEADER_LINE = /^([#{field_name}]+:\s*.+)$/ |
8581 | HEADER_SPLIT = /#{CRLF}(?!#{WSP})/ |
8582 | QP_UNSAFE = /[^#{qp_safe}]/ |
8583 | QP_SAFE = /[#{qp_safe}]/ |
8584 | CONTROL_CHAR = /[#{control}]/n |
8585 | EMPTY = '' |
8586 | SPACE = ' ' |
8587 | UNDERSCORE = '_' |
8588 | HYPHEN = '-' |
8589 | COLON = ':' |
8590 | ASTERISK = '*' |
8591 | CR = "\r" |
8592 | LF = " " |
8593 | CR_ENCODED = "=0D" |
8594 | LF_ENCODED = "=0A" |
8595 | CAPITAL_M = 'M' |
8596 | EQUAL_LF = "= " |
8597 | NULL_SENDER = '' |
8598 | Q_VALUES = ['Q','q'] |
8599 | B_VALUES = ['B','b'] |
8600 | end |
8601 | end |
8602 | class NilClass #:nodoc: |
8603 | unless nil.respond_to? :blank? |
8604 | def blank? |
8605 | true |
8606 | end |
8607 | end |
8608 | def to_crlf |
8609 | '' |
8610 | end |
8611 | def to_lf |
8612 | '' |
8613 | end |
8614 | end |
8615 | unless Object.method_defined? :blank? |
8616 | class Object |
8617 | def blank? |
8618 | if respond_to?(:empty?) |
8619 | empty? |
8620 | else |
8621 | !self |
8622 | end |
8623 | end |
8624 | end |
8625 | end |
8626 | module Net |
8627 | class SMTP |
8628 | begin |
8629 | alias_method :original_tlsconnect, :tlsconnect |
8630 | def tlsconnect(s) |
8631 | verified = false |
8632 | begin |
8633 | original_tlsconnect(s).tap { verified = true } |
8634 | ensure |
8635 | unless verified |
8636 | s.close rescue nil |
8637 | end |
8638 | end |
8639 | end |
8640 | rescue NameError |
8641 | end |
8642 | end |
8643 | end |
8644 | class String |
8645 | unless '1.9'.respond_to?(:force_encoding) |
8646 | def at(position) |
8647 | mb_chars[position, 1].to_s |
8648 | end |
8649 | def from(position) |
8650 | mb_chars[position..-1].to_s |
8651 | end |
8652 | def to(position) |
8653 | mb_chars[0..position].to_s |
8654 | end |
8655 | def first(limit = 1) |
8656 | if limit == 0 |
8657 | '' |
8658 | elsif limit = size |
8659 | self |
8660 | else |
8661 | mb_chars[0...limit].to_s |
8662 | end |
8663 | end |
8664 | def last(limit = 1) |
8665 | if limit == 0 |
8666 | '' |
8667 | elsif limit = size |
8668 | self |
8669 | else |
8670 | mb_chars[(-limit)..-1].to_s |
8671 | end |
8672 | end |
8673 | else |
8674 | def at(position) |
8675 | self[position] |
8676 | end |
8677 | def from(position) |
8678 | self[position..-1] |
8679 | end |
8680 | def to(position) |
8681 | self[0..position] |
8682 | end |
8683 | def first(limit = 1) |
8684 | if limit == 0 |
8685 | '' |
8686 | elsif limit = size |
8687 | self |
8688 | else |
8689 | to(limit - 1) |
8690 | end |
8691 | end |
8692 | def last(limit = 1) |
8693 | if limit == 0 |
8694 | '' |
8695 | elsif limit = size |
8696 | self |
8697 | else |
8698 | from(-limit) |
8699 | end |
8700 | end |
8701 | end |
8702 | if Module.method(:const_get).arity == 1 |
8703 | def constantize |
8704 | names = self.split('::') |
8705 | names.shift if names.empty? || names.first.empty? |
8706 | constant = Object |
8707 | names.each do |name| |
8708 | end |
8709 | constant |
8710 | end |
8711 | else |
8712 | def constantize #:nodoc: |
8713 | names = self.split('::') |
8714 | names.shift if names.empty? || names.first.empty? |
8715 | constant = Object |
8716 | names.each do |name| |
8717 | end |
8718 | constant |
8719 | end |
8720 | end |
8721 | end |
8722 | require 'mail/multibyte' |
8723 | class String |
8724 | if RUBY_VERSION = "1.9" |
8725 | def mb_chars |
8726 | if Mail::Multibyte.proxy_class.consumes?(self) |
8727 | Mail::Multibyte.proxy_class.new(self) |
8728 | else |
8729 | self |
8730 | end |
8731 | end |
8732 | def is_utf8? #:nodoc |
8733 | case encoding |
8734 | when Encoding::UTF_8 |
8735 | valid_encoding? |
8736 | when Encoding::ASCII_8BIT, Encoding::US_ASCII |
8737 | else |
8738 | false |
8739 | end |
8740 | end |
8741 | else |
8742 | def mb_chars |
8743 | if Mail::Multibyte.proxy_class.wants?(self) |
8744 | Mail::Multibyte.proxy_class.new(self) |
8745 | else |
8746 | self |
8747 | end |
8748 | end |
8749 | def is_utf8? |
8750 | Mail::Multibyte::Chars.consumes?(self) |
8751 | end |
8752 | end |
8753 | end |
8754 | class String #:nodoc: |
8755 | CRLF = "\r " |
8756 | LF = " " |
8757 | if RUBY_VERSION = '1.9' |
8758 | CRLF_REGEX = Regexp.new("(?!\r) |\r(?! )") |
8759 | else |
8760 | CRLF_REGEX = / |\r |\r/ |
8761 | end |
8762 | def to_crlf |
8763 | to_str.gsub(CRLF_REGEX, CRLF) |
8764 | end |
8765 | def to_lf |
8766 | to_str.gsub(/\r |\r/, LF) |
8767 | end |
8768 | def blank? |
8769 | self !~ /\S/ |
8770 | end |
8771 | end |
8772 | unless method_defined?(:ascii_only?) |
8773 | def ascii_only? |
8774 | self !~ MATCH_NON_US_ASCII |
8775 | end |
8776 | MATCH_NON_US_ASCII = /[^\x00-\x7f]/ |
8777 | end |
8778 | def not_ascii_only? |
8779 | !ascii_only? |
8780 | end |
8781 | unless method_defined?(:bytesize) |
8782 | alias :bytesize :length |
8783 | end |
8784 | end |
8785 | module Mail |
8786 | class Address |
8787 | include Mail::Utilities |
8788 | def initialize(value = nil) |
8789 | @output_type = :decode |
8790 | if value.nil? |
8791 | @parsed = false |
8792 | @data = nil |
8793 | else |
8794 | parse(value) |
8795 | end |
8796 | end |
8797 | def raw |
8798 | @data.raw |
8799 | end |
8800 | def format |
8801 | parse unless @parsed |
8802 | if @data.nil? |
8803 | EMPTY |
8804 | elsif display_name |
8805 | elsif address |
8806 | [address, format_comments].compact.join(SPACE) |
8807 | else |
8808 | raw |
8809 | end |
8810 | end |
8811 | def address |
8812 | parse unless @parsed |
8813 | domain ? "#{local}@#{domain}" : local |
8814 | end |
8815 | def address=(value) |
8816 | parse(value) |
8817 | end |
8818 | def display_name |
8819 | parse unless @parsed |
8820 | @display_name ||= get_display_name |
8821 | end |
8822 | def display_name=( str ) |
8823 | @display_name = str |
8824 | end |
8825 | def local |
8826 | parse unless @parsed |
8827 | end |
8828 | def domain |
8829 | parse unless @parsed |
8830 | strip_all_comments(get_domain) if get_domain |
8831 | end |
8832 | def comments |
8833 | parse unless @parsed |
8834 | end |
8835 | def name |
8836 | parse unless @parsed |
8837 | get_name |
8838 | end |
8839 | def to_s |
8840 | parse unless @parsed |
8841 | format |
8842 | end |
8843 | def inspect |
8844 | parse unless @parsed |
8845 | end |
8846 | def encoded |
8847 | @output_type = :encode |
8848 | format |
8849 | end |
8850 | def decoded |
8851 | @output_type = :decode |
8852 | format |
8853 | end |
8854 | def group |
8855 | @data && @data.group |
8856 | end |
8857 | private |
8858 | def parse(value = nil) |
8859 | @parsed = true |
8860 | @data = nil |
8861 | case value |
8862 | when Mail::Parsers::AddressStruct |
8863 | @data = value |
8864 | when String |
8865 | unless value.blank? |
8866 | @data = address_list.addresses.first |
8867 | end |
8868 | end |
8869 | end |
8870 | def strip_all_comments(string) |
8871 | unless comments.blank? |
8872 | comments.each do |comment| |
8873 | string = string.gsub("(#{comment})", EMPTY) |
8874 | end |
8875 | end |
8876 | string.strip |
8877 | end |
8878 | def strip_domain_comments(value) |
8879 | unless comments.blank? |
8880 | comments.each do |comment| |
8881 | value = value.gsub("(#{comment})", EMPTY) |
8882 | end |
8883 | end |
8884 | end |
8885 | value.to_s.strip |
8886 | end |
8887 | def get_display_name |
8888 | if @data.display_name |
8889 | str = strip_all_comments(@data.display_name.to_s) |
8890 | elsif @data.comments && @data.domain |
8891 | str = strip_domain_comments(format_comments) |
8892 | end |
8893 | str unless str.blank? |
8894 | end |
8895 | def get_name |
8896 | if display_name |
8897 | str = display_name |
8898 | elsif comments |
8899 | str = "(#{comments.join(SPACE).squeeze(SPACE)})" |
8900 | end |
8901 | unparen(str) unless str.blank? |
8902 | end |
8903 | def format_comments |
8904 | if comments |
8905 | @format_comments ||= "(#{comment_text})" |
8906 | else |
8907 | nil |
8908 | end |
8909 | end |
8910 | def get_local |
8911 | @data && @data.local |
8912 | end |
8913 | def get_domain |
8914 | @data && @data.domain |
8915 | end |
8916 | def get_comments |
8917 | @data && @data.comments |
8918 | end |
8919 | end |
8920 | end |
8921 | module Mail |
8922 | class AddressList # :nodoc: |
8923 | def initialize(string) |
8924 | @addresses_grouped_by_group = nil |
8925 | end |
8926 | def addresses |
8927 | Mail::Address.new(address_data) |
8928 | end |
8929 | end |
8930 | def addresses_grouped_by_group |
8931 | addresses.select(&:group).group_by(&:group) |
8932 | end |
8933 | def group_names # :nodoc: |
8934 | @address_list.group_names |
8935 | end |
8936 | end |
8937 | end |
8938 | module Mail |
8939 | class ContentDispositionElement # :nodoc: |
8940 | include Mail::Utilities |
8941 | def initialize( string ) |
8942 | @parameters = content_disposition.parameters |
8943 | end |
8944 | def disposition_type |
8945 | @disposition_type |
8946 | end |
8947 | def parameters |
8948 | @parameters |
8949 | end |
8950 | def cleaned(string) |
8951 | string =~ /(.+);\s*$/ ? $1 : string |
8952 | end |
8953 | end |
8954 | end |
8955 | module Mail |
8956 | class ContentLocationElement # :nodoc: |
8957 | include Mail::Utilities |
8958 | def initialize( string ) |
8959 | @location = content_location.location |
8960 | end |
8961 | def location |
8962 | @location |
8963 | end |
8964 | def to_s(*args) |
8965 | location.to_s |
8966 | end |
8967 | end |
8968 | end |
8969 | module Mail |
8970 | class ContentTransferEncodingElement |
8971 | include Mail::Utilities |
8972 | def initialize(string) |
8973 | @encoding = content_transfer_encoding.encoding |
8974 | end |
8975 | def encoding |
8976 | @encoding |
8977 | end |
8978 | end |
8979 | end |
8980 | module Mail |
8981 | class ContentTypeElement # :nodoc: |
8982 | include Mail::Utilities |
8983 | def initialize( string ) |
8984 | @main_type = content_type.main_type |
8985 | @sub_type = content_type.sub_type |
8986 | @parameters = content_type.parameters |
8987 | end |
8988 | def main_type |
8989 | @main_type |
8990 | end |
8991 | def sub_type |
8992 | @sub_type |
8993 | end |
8994 | def parameters |
8995 | @parameters |
8996 | end |
8997 | def cleaned(string) |
8998 | string =~ /(.+);\s*$/ ? $1 : string |
8999 | end |
9000 | end |
9001 | end |
9002 | module Mail |
9003 | class DateTimeElement # :nodoc: |
9004 | include Mail::Utilities |
9005 | def initialize( string ) |
9006 | @date_string = date_time.date_string |
9007 | @time_string = date_time.time_string |
9008 | end |
9009 | def date_string |
9010 | @date_string |
9011 | end |
9012 | def time_string |
9013 | @time_string |
9014 | end |
9015 | end |
9016 | end |
9017 | module Mail |
9018 | class EnvelopeFromElement |
9019 | include Mail::Utilities |
9020 | def initialize( string ) |
9021 | @address = @envelope_from.address |
9022 | end |
9023 | def date_time |
9024 | @date_time |
9025 | end |
9026 | def address |
9027 | @address |
9028 | end |
9029 | def formatted_date_time |
9030 | if @date_time.respond_to?(:ctime) |
9031 | @date_time.ctime |
9032 | else |
9033 | @date_time.strftime '%a %b %e %T %Y' |
9034 | end |
9035 | end |
9036 | def to_s |
9037 | "#{@address} #{formatted_date_time}" |
9038 | end |
9039 | end |
9040 | end |
9041 | module Mail |
9042 | class MessageIdsElement |
9043 | include Mail::Utilities |
9044 | def initialize(string) |
9045 | end |
9046 | def message_ids |
9047 | @message_ids |
9048 | end |
9049 | def message_id |
9050 | @message_ids.first |
9051 | end |
9052 | def clean_msg_id( val ) |
9053 | val =~ /.*(.*).*/ ; $1 |
9054 | end |
9055 | end |
9056 | end |
9057 | module Mail |
9058 | class MimeVersionElement |
9059 | include Mail::Utilities |
9060 | def initialize( string ) |
9061 | @major = mime_version.major |
9062 | @minor = mime_version.minor |
9063 | end |
9064 | def major |
9065 | @major |
9066 | end |
9067 | def minor |
9068 | @minor |
9069 | end |
9070 | end |
9071 | end |
9072 | module Mail |
9073 | class PhraseList |
9074 | include Mail::Utilities |
9075 | def initialize(string) |
9076 | end |
9077 | def phrases |
9078 | @phrase_lists.phrases.map { |p| unquote(p) } |
9079 | end |
9080 | end |
9081 | end |
9082 | module Mail |
9083 | class ReceivedElement |
9084 | include Mail::Utilities |
9085 | def initialize( string ) |
9086 | @info = received.info |
9087 | end |
9088 | def date_time |
9089 | @date_time |
9090 | end |
9091 | def info |
9092 | @info |
9093 | end |
9094 | def to_s(*args) |
9095 | "#{@info}; #{@date_time.to_s(*args)}" |
9096 | end |
9097 | end |
9098 | end |
9099 | module Mail |
9100 | end |
9101 | require 'mail/encodings/8bit' |
9102 | module Mail |
9103 | module Encodings |
9104 | class SevenBit EightBit |
9105 | NAME = '7bit' |
9106 | PRIORITY = 1 |
9107 | def self.decode(str) |
9108 | super |
9109 | end |
9110 | def self.encode(str) |
9111 | super |
9112 | end |
9113 | def self.cost(str) |
9114 | super |
9115 | end |
9116 | Encodings.register(NAME, self) |
9117 | end |
9118 | end |
9119 | end |
9120 | require 'mail/encodings/binary' |
9121 | module Mail |
9122 | module Encodings |
9123 | class EightBit Binary |
9124 | NAME = '8bit' |
9125 | PRIORITY = 4 |
9126 | def self.decode(str) |
9127 | str.to_lf |
9128 | end |
9129 | def self.encode(str) |
9130 | str.to_crlf |
9131 | end |
9132 | def self.cost(str) |
9133 | 1.0 |
9134 | end |
9135 | Encodings.register(NAME, self) |
9136 | end |
9137 | end |
9138 | end |
9139 | require 'mail/encodings/7bit' |
9140 | module Mail |
9141 | module Encodings |
9142 | class Base64 SevenBit |
9143 | NAME = 'base64' |
9144 | PRIORITY = 3 |
9145 | def self.can_encode?(enc) |
9146 | true |
9147 | end |
9148 | def self.decode(str) |
9149 | RubyVer.decode_base64( str ) |
9150 | end |
9151 | def self.encode(str) |
9152 | RubyVer.encode_base64( str ).to_crlf |
9153 | end |
9154 | def self.cost(str) |
9155 | 4.0/3 |
9156 | end |
9157 | Encodings.register(NAME, self) |
9158 | end |
9159 | end |
9160 | end |
9161 | require 'mail/encodings/transfer_encoding' |
9162 | module Mail |
9163 | module Encodings |
9164 | class Binary TransferEncoding |
9165 | NAME = 'binary' |
9166 | PRIORITY = 5 |
9167 | def self.decode(str) |
9168 | str |
9169 | end |
9170 | def self.encode(str) |
9171 | str |
9172 | end |
9173 | def self.cost(str) |
9174 | 1.0 |
9175 | end |
9176 | Encodings.register(NAME, self) |
9177 | end |
9178 | end |
9179 | end |
9180 | require 'mail/encodings/7bit' |
9181 | module Mail |
9182 | module Encodings |
9183 | class QuotedPrintable SevenBit |
9184 | NAME='quoted-printable' |
9185 | PRIORITY = 2 |
9186 | def self.can_encode?(str) |
9187 | EightBit.can_encode? str |
9188 | end |
9189 | def self.decode(str) |
9190 | end |
9191 | def self.encode(str) |
9192 | [str.to_lf].pack("M").to_crlf |
9193 | end |
9194 | def self.cost(str) |
9195 | c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E") |
9196 | total = (str.bytesize - c)*3 + c |
9197 | total.to_f/str.bytesize |
9198 | end |
9199 | private |
9200 | Encodings.register(NAME, self) |
9201 | end |
9202 | end |
9203 | end |
9204 | module Mail |
9205 | module Encodings |
9206 | class TransferEncoding |
9207 | NAME = '' |
9208 | PRIORITY = -1 |
9209 | def self.can_transport?(enc) |
9210 | enc = Encodings.get_name(enc) |
9211 | if Encodings.defined? enc |
9212 | Encodings.get_encoding(enc).new.is_a? self |
9213 | else |
9214 | false |
9215 | end |
9216 | end |
9217 | def self.can_encode?(enc) |
9218 | can_transport? enc |
9219 | end |
9220 | def self.cost(str) |
9221 | raise "Unimplemented" |
9222 | end |
9223 | def self.to_s |
9224 | self::NAME |
9225 | end |
9226 | if self.can_transport? source_encoding then |
9227 | source_encoding |
9228 | else |
9229 | choices = [] |
9230 | Encodings.get_all.each do |enc| |
9231 | end |
9232 | best = nil |
9233 | best_cost = 100 |
9234 | choices.each do |enc| |
9235 | this_cost = enc.cost str |
9236 | if this_cost best_cost then |
9237 | best_cost = this_cost |
9238 | best = enc |
9239 | elsif this_cost == best_cost then |
9240 | best = enc if enc::PRIORITY best::PRIORITY |
9241 | end |
9242 | end |
9243 | best |
9244 | end |
9245 | end |
9246 | def to_s |
9247 | self.class.to_s |
9248 | end |
9249 | end |
9250 | end |
9251 | end |
9252 | module Mail |
9253 | module Encodings |
9254 | module UnixToUnix |
9255 | NAME = "x-uuencode" |
9256 | def self.decode(str) |
9257 | end |
9258 | def self.encode(str) |
9259 | [str].pack("u") |
9260 | end |
9261 | Encodings.register(NAME, self) |
9262 | end |
9263 | end |
9264 | end |
9265 | module Mail |
9266 | class UnknownEncodingType StandardError #:nodoc: |
9267 | end |
9268 | module Encodings |
9269 | include Mail::Constants |
9270 | extend Mail::Utilities |
9271 | @transfer_encodings = {} |
9272 | def Encodings.register(name, cls) |
9273 | @transfer_encodings[get_name(name)] = cls |
9274 | end |
9275 | def Encodings.defined?( str ) |
9276 | @transfer_encodings.include? get_name(str) |
9277 | end |
9278 | def Encodings.get_encoding( str ) |
9279 | @transfer_encodings[get_name(str)] |
9280 | end |
9281 | def Encodings.get_all |
9282 | @transfer_encodings.values |
9283 | end |
9284 | def Encodings.get_name(enc) |
9285 | underscoreize(enc).downcase |
9286 | end |
9287 | def Encodings.param_encode(str) |
9288 | case |
9289 | when str.ascii_only? && str =~ TOKEN_UNSAFE |
9290 | %Q{"#{str}"} |
9291 | when str.ascii_only? |
9292 | str |
9293 | else |
9294 | RubyVer.param_encode(str) |
9295 | end |
9296 | end |
9297 | def Encodings.param_decode(str, encoding) |
9298 | RubyVer.param_decode(str, encoding) |
9299 | end |
9300 | def Encodings.decode_encode(str, output_type) |
9301 | case |
9302 | when output_type == :decode |
9303 | Encodings.value_decode(str) |
9304 | else |
9305 | if str.ascii_only? |
9306 | str |
9307 | else |
9308 | Encodings.b_value_encode(str, find_encoding(str)) |
9309 | end |
9310 | end |
9311 | end |
9312 | def Encodings.value_decode(str) |
9313 | return str unless str =~ ENCODED_VALUE |
9314 | lines = collapse_adjacent_encodings(str) |
9315 | lines.each do |line| |
9316 | line.gsub!(ENCODED_VALUE) do |string| |
9317 | case $2 |
9318 | when *B_VALUES then b_value_decode(string) |
9319 | when *Q_VALUES then q_value_decode(string) |
9320 | end |
9321 | end |
9322 | end.join("") |
9323 | end |
9324 | output |
9325 | elsif to_encoding |
9326 | begin |
9327 | if RUBY_VERSION = '1.9' |
9328 | output.encode(to_encoding) |
9329 | else |
9330 | require 'iconv' |
9331 | Iconv.iconv(to_encoding, 'UTF-8', output).first |
9332 | end |
9333 | output |
9334 | end |
9335 | else |
9336 | output |
9337 | end |
9338 | end |
9339 | if address.is_a?(Array) |
9340 | else |
9341 | encode_non_usascii(address, charset) if address |
9342 | end |
9343 | end |
9344 | us_ascii = %Q{\x00-\x7f} |
9345 | tokens = address.split(/\s/) |
9346 | map_with_index(tokens) do |word, i| |
9347 | if word.ascii_only? |
9348 | word |
9349 | else |
9350 | word = " #{word}" |
9351 | end |
9352 | Encodings.b_value_encode(word, charset) |
9353 | end |
9354 | end.join(' ') |
9355 | end |
9356 | map_lines(string) do |str| |
9357 | "=?#{encoding}?B?#{str.chomp}?=" |
9358 | end.join(" ") |
9359 | end |
9360 | map_lines(string) do |str| |
9361 | "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?=" |
9362 | end.join(" ") |
9363 | end |
9364 | private |
9365 | def Encodings.b_value_decode(str) |
9366 | RubyVer.b_value_decode(str) |
9367 | end |
9368 | def Encodings.q_value_decode(str) |
9369 | RubyVer.q_value_decode(str) |
9370 | end |
9371 | def Encodings.find_encoding(str) |
9372 | RUBY_VERSION = '1.9' ? str.encoding : $KCODE |
9373 | end |
9374 | def Encodings.value_encoding_from_string(str) |
9375 | str[ENCODED_VALUE, 1] |
9376 | end |
9377 | def Encodings.collapse_adjacent_encodings(str) |
9378 | results = [] |
9379 | previous_encoding = nil |
9380 | lines = str.split(FULL_ENCODED_VALUE) |
9381 | lines.each_slice(2) do |unencoded, encoded| |
9382 | if encoded |
9383 | encoding = value_encoding_from_string(encoded) |
9384 | results.last encoded |
9385 | else |
9386 | results unencoded unless unencoded == EMPTY |
9387 | results encoded |
9388 | end |
9389 | previous_encoding = encoding |
9390 | else |
9391 | results unencoded |
9392 | end |
9393 | end |
9394 | results |
9395 | end |
9396 | end |
9397 | end |
9398 | module Mail |
9399 | class Envelope StructuredField |
9400 | def initialize(*args) |
9401 | end |
9402 | def element |
9403 | @element ||= Mail::EnvelopeFromElement.new(value) |
9404 | end |
9405 | def date |
9406 | ::DateTime.parse("#{element.date_time}") |
9407 | end |
9408 | def from |
9409 | element.address |
9410 | end |
9411 | end |
9412 | end |
9413 | require 'mail/fields' |
9414 | module Mail |
9415 | class Field |
9416 | include Utilities |
9417 | include Comparable |
9418 | mime-version received references reply-to |
9419 | resent-bcc resent-cc resent-date resent-from |
9420 | resent-message-id resent-sender resent-to |
9421 | return-path sender to ] |
9422 | FIELDS_MAP = { |
9423 | "to" = ToField, |
9424 | "cc" = CcField, |
9425 | "bcc" = BccField, |
9426 | "message-id" = MessageIdField, |
9427 | "in-reply-to" = InReplyToField, |
9428 | "references" = ReferencesField, |
9429 | "subject" = SubjectField, |
9430 | "comments" = CommentsField, |
9431 | "keywords" = KeywordsField, |
9432 | "date" = DateField, |
9433 | "from" = FromField, |
9434 | "sender" = SenderField, |
9435 | "reply-to" = ReplyToField, |
9436 | "resent-date" = ResentDateField, |
9437 | "resent-from" = ResentFromField, |
9438 | "resent-sender" = ResentSenderField, |
9439 | "resent-to" = ResentToField, |
9440 | "resent-cc" = ResentCcField, |
9441 | "resent-bcc" = ResentBccField, |
9442 | "resent-message-id" = ResentMessageIdField, |
9443 | "return-path" = ReturnPathField, |
9444 | "received" = ReceivedField, |
9445 | "mime-version" = MimeVersionField, |
9446 | "content-description" = ContentDescriptionField, |
9447 | "content-disposition" = ContentDispositionField, |
9448 | "content-type" = ContentTypeField, |
9449 | "content-id" = ContentIdField, |
9450 | "content-location" = ContentLocationField, |
9451 | } |
9452 | end |
9453 | class FieldError StandardError |
9454 | end |
9455 | class ParseError FieldError #:nodoc: |
9456 | attr_accessor :element, :value, :reason |
9457 | def initialize(element, value, reason) |
9458 | @element = element |
9459 | @value = value |
9460 | @reason = reason |
9461 | end |
9462 | end |
9463 | class SyntaxError FieldError #:nodoc: |
9464 | end |
9465 | case |
9466 | @charset = value.blank? ? charset : value |
9467 | @name = name[FIELD_PREFIX] |
9468 | @raw_value = name |
9469 | @value = nil |
9470 | when value.blank? # Field.new("field-name") |
9471 | @name = name |
9472 | @value = nil |
9473 | @raw_value = nil |
9474 | @charset = charset |
9475 | else # Field.new("field-name", "value") |
9476 | @name = name |
9477 | @value = value |
9478 | @raw_value = nil |
9479 | @charset = charset |
9480 | end |
9481 | end |
9482 | def field=(value) |
9483 | @field = value |
9484 | end |
9485 | def field |
9486 | @field ||= create_field(@name, @value, @charset) |
9487 | end |
9488 | def name |
9489 | @name |
9490 | end |
9491 | def value |
9492 | field.value |
9493 | end |
9494 | def value=(val) |
9495 | @field = create_field(name, val, @charset) |
9496 | end |
9497 | def to_s |
9498 | field.to_s |
9499 | end |
9500 | def inspect |
9501 | "#{ivar}=#{instance_variable_get(ivar).inspect}" |
9502 | end.join(" ")}" |
9503 | end |
9504 | def update(name, value) |
9505 | @field = create_field(name, value, @charset) |
9506 | end |
9507 | def same( other ) |
9508 | match_to_s(other.name, self.name) |
9509 | end |
9510 | def responsible_for?( val ) |
9511 | name.to_s.casecmp(val.to_s) == 0 |
9512 | end |
9513 | alias_method :==, :same |
9514 | def =( other ) |
9515 | self.field_order_id = other.field_order_id |
9516 | end |
9517 | def field_order_id |
9518 | end |
9519 | def method_missing(name, *args, &block) |
9520 | field.send(name, *args, &block) |
9521 | end |
9522 | if RUBY_VERSION = '1.9.2' |
9523 | end |
9524 | else |
9525 | end |
9526 | end |
9527 | FIELD_ORDER = %w[ return-path received |
9528 | resent-date resent-from resent-sender resent-to |
9529 | resent-cc resent-bcc resent-message-id |
9530 | date from sender reply-to to cc bcc |
9531 | message-id in-reply-to references |
9532 | subject comments keywords |
9533 | private |
9534 | def split(raw_field) |
9535 | rescue |
9536 | end |
9537 | def unfold(string) |
9538 | string.gsub(/[\r \t]+/m, ' ') |
9539 | end |
9540 | def create_field(name, value, charset) |
9541 | value = unfold(value) if value.is_a?(String) |
9542 | begin |
9543 | new_field(name, value, charset) |
9544 | rescue Mail::Field::ParseError = e |
9545 | field = Mail::UnstructuredField.new(name, value) |
9546 | field.errors [name, value, e] |
9547 | field |
9548 | end |
9549 | end |
9550 | def new_field(name, value, charset) |
9551 | lower_case_name = name.to_s.downcase |
9552 | if field_klass = FIELDS_MAP[lower_case_name] |
9553 | field_klass.new(value, charset) |
9554 | else |
9555 | OptionalField.new(name, value, charset) |
9556 | end |
9557 | end |
9558 | end |
9559 | end |
9560 | module Mail |
9561 | class FieldList Array |
9562 | include Enumerable |
9563 | def ( new_field ) |
9564 | lo = 0 |
9565 | hi = size |
9566 | while lo hi |
9567 | mid = (lo + hi).div(2) |
9568 | if new_field self[mid] |
9569 | hi = mid |
9570 | else |
9571 | lo = mid + 1 |
9572 | end |
9573 | end |
9574 | insert(lo, new_field) |
9575 | end |
9576 | end |
9577 | end |
9578 | require 'mail/fields/common/common_address' |
9579 | module Mail |
9580 | class BccField StructuredField |
9581 | include Mail::CommonAddress |
9582 | FIELD_NAME = 'bcc' |
9583 | CAPITALIZED_FIELD = 'Bcc' |
9584 | def initialize(value = '', charset = 'utf-8') |
9585 | @charset = charset |
9586 | self.parse |
9587 | self |
9588 | end |
9589 | def encoded |
9590 | '' |
9591 | end |
9592 | def decoded |
9593 | do_decode |
9594 | end |
9595 | end |
9596 | end |
9597 | require 'mail/fields/common/common_address' |
9598 | module Mail |
9599 | class CcField StructuredField |
9600 | include Mail::CommonAddress |
9601 | FIELD_NAME = 'cc' |
9602 | CAPITALIZED_FIELD = 'Cc' |
9603 | def initialize(value = nil, charset = 'utf-8') |
9604 | self.charset = charset |
9605 | self.parse |
9606 | self |
9607 | end |
9608 | def encoded |
9609 | do_encode(CAPITALIZED_FIELD) |
9610 | end |
9611 | def decoded |
9612 | do_decode |
9613 | end |
9614 | end |
9615 | end |
9616 | module Mail |
9617 | class CommentsField UnstructuredField |
9618 | FIELD_NAME = 'comments' |
9619 | CAPITALIZED_FIELD = 'Comments' |
9620 | def initialize(value = nil, charset = 'utf-8') |
9621 | @charset = charset |
9622 | self.parse |
9623 | self |
9624 | end |
9625 | end |
9626 | end |
9627 | module Mail |
9628 | class AddressContainer Array |
9629 | def initialize(field, list = []) |
9630 | @field = field |
9631 | super(list) |
9632 | end |
9633 | def (address) |
9634 | @field address |
9635 | end |
9636 | end |
9637 | end# encoding: utf-8 |
9638 | require 'mail/fields/common/address_container' |
9639 | module Mail |
9640 | module CommonAddress # :nodoc: |
9641 | def parse(val = value) |
9642 | unless val.blank? |
9643 | else |
9644 | nil |
9645 | end |
9646 | end |
9647 | def charset |
9648 | @charset |
9649 | end |
9650 | def encode_if_needed(val) |
9651 | Encodings.address_encode(val, charset) |
9652 | end |
9653 | def each |
9654 | address_list.addresses.each do |address| |
9655 | yield(address) |
9656 | end |
9657 | end |
9658 | def addresses |
9659 | Mail::AddressContainer.new(self, list) |
9660 | end |
9661 | def formatted |
9662 | Mail::AddressContainer.new(self, list) |
9663 | end |
9664 | def display_names |
9665 | Mail::AddressContainer.new(self, list) |
9666 | end |
9667 | def addrs |
9668 | list = address_list.addresses |
9669 | Mail::AddressContainer.new(self, list) |
9670 | end |
9671 | def groups |
9672 | address_list.addresses_grouped_by_group |
9673 | end |
9674 | def group_addresses |
9675 | decoded_group_addresses |
9676 | end |
9677 | def decoded_group_addresses |
9678 | end |
9679 | def encoded_group_addresses |
9680 | end |
9681 | def group_names # :nodoc: |
9682 | address_list.group_names |
9683 | end |
9684 | def default |
9685 | addresses |
9686 | end |
9687 | def (val) |
9688 | case |
9689 | when val.nil? |
9690 | when val.blank? |
9691 | parse(encoded) |
9692 | else |
9693 | end |
9694 | end |
9695 | def value=(val) |
9696 | super |
9697 | parse(self.value) |
9698 | end |
9699 | private |
9700 | def do_encode(field_name) |
9701 | return '' if value.blank? |
9702 | address_text = address_array.join(", \r \s") |
9703 | group_text = group_array.join(" \r \s") |
9704 | end |
9705 | def do_decode |
9706 | return nil if value.blank? |
9707 | address_text = address_array.join(", ") |
9708 | group_text = group_array.join(" ") |
9709 | return_array.join(", ") |
9710 | end |
9711 | def address_list # :nodoc: |
9712 | @address_list ||= AddressList.new(value) |
9713 | end |
9714 | def get_group_addresses(group_list) |
9715 | if group_list.respond_to?(:addresses) |
9716 | group_list.addresses.map do |address| |
9717 | Mail::Address.new(address) |
9718 | end |
9719 | else |
9720 | [] |
9721 | end |
9722 | end |
9723 | end |
9724 | end |
9725 | module Mail |
9726 | module CommonDate # :nodoc: |
9727 | def date_time |
9728 | end |
9729 | def default |
9730 | date_time |
9731 | end |
9732 | def parse(val = value) |
9733 | unless val.blank? |
9734 | @element = Mail::DateTimeElement.new(val) |
9735 | else |
9736 | nil |
9737 | end |
9738 | end |
9739 | private |
9740 | def do_encode(field_name) |
9741 | "#{field_name}: #{value}\r " |
9742 | end |
9743 | def do_decode |
9744 | "#{value}" |
9745 | end |
9746 | def element |
9747 | @element ||= Mail::DateTimeElement.new(value) |
9748 | end |
9749 | end |
9750 | end |
9751 | module Mail |
9752 | module CommonField # :nodoc: |
9753 | include Mail::Constants |
9754 | def name=(value) |
9755 | @name = value |
9756 | end |
9757 | def name |
9758 | @name ||= nil |
9759 | end |
9760 | def value=(value) |
9761 | @length = nil |
9762 | @tree = nil |
9763 | @element = nil |
9764 | @value = value |
9765 | end |
9766 | def value |
9767 | @value |
9768 | end |
9769 | def to_s |
9770 | decoded.to_s |
9771 | end |
9772 | def default |
9773 | decoded |
9774 | end |
9775 | def field_length |
9776 | @length ||= "#{name}: #{encode(decoded)}".length |
9777 | end |
9778 | def responsible_for?( val ) |
9779 | name.to_s.casecmp(val.to_s) == 0 |
9780 | end |
9781 | private |
9782 | def strip_field(field_name, value) |
9783 | if value.is_a?(Array) |
9784 | value |
9785 | else |
9786 | value.to_s.sub(/#{field_name}:\s+/i, EMPTY) |
9787 | end |
9788 | end |
9789 | def ensure_filename_quoted(value) |
9790 | if value.is_a?(String) |
9791 | value.sub! FILENAME_RE, '\1="\2"' |
9792 | end |
9793 | end |
9794 | end |
9795 | end |
9796 | module Mail |
9797 | module CommonMessageId # :nodoc: |
9798 | def element |
9799 | end |
9800 | def parse(val = value) |
9801 | unless val.blank? |
9802 | @element = Mail::MessageIdsElement.new(val) |
9803 | else |
9804 | nil |
9805 | end |
9806 | end |
9807 | def message_id |
9808 | element.message_id if element |
9809 | end |
9810 | def message_ids |
9811 | element.message_ids if element |
9812 | end |
9813 | def default |
9814 | return nil unless message_ids |
9815 | if message_ids.length == 1 |
9816 | message_ids[0] |
9817 | else |
9818 | message_ids |
9819 | end |
9820 | end |
9821 | private |
9822 | def do_encode(field_name) |
9823 | end |
9824 | def do_decode |
9825 | formated_message_ids(' ') |
9826 | end |
9827 | def formated_message_ids(join) |
9828 | end |
9829 | end |
9830 | end |
9831 | module Mail |
9832 | class ParameterHash IndifferentHash |
9833 | include Mail::Utilities |
9834 | def [](key_name) |
9835 | key_pattern = Regexp.escape(key_name.to_s) |
9836 | pairs = [] |
9837 | exact = nil |
9838 | each do |k,v| |
9839 | if k =~ /^#{key_pattern}(\*|$)/i |
9840 | if $1 == ASTERISK |
9841 | pairs [k, v] |
9842 | else |
9843 | exact = k |
9844 | end |
9845 | end |
9846 | end |
9847 | super(exact || key_name) |
9848 | if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/) |
9849 | string = mt[3] |
9850 | encoding = mt[1] |
9851 | else |
9852 | encoding = nil |
9853 | end |
9854 | Mail::Encodings.param_decode(string, encoding) |
9855 | end |
9856 | end |
9857 | def encoded |
9858 | unless value.ascii_only? |
9859 | value = Mail::Encodings.param_encode(value) |
9860 | key_name = "#{key_name}*" |
9861 | end |
9862 | %Q{#{key_name}=#{quote_token(value)}} |
9863 | end.join(";\r \s") |
9864 | end |
9865 | def decoded |
9866 | %Q{#{key_name}=#{quote_token(value)}} |
9867 | end.join("; ") |
9868 | end |
9869 | end |
9870 | end |
9871 | module Mail |
9872 | class ContentDescriptionField UnstructuredField |
9873 | FIELD_NAME = 'content-description' |
9874 | CAPITALIZED_FIELD = 'Content-Description' |
9875 | def initialize(value = nil, charset = 'utf-8') |
9876 | self.charset = charset |
9877 | self.parse |
9878 | self |
9879 | end |
9880 | end |
9881 | end |
9882 | require 'mail/fields/common/parameter_hash' |
9883 | module Mail |
9884 | class ContentDispositionField StructuredField |
9885 | FIELD_NAME = 'content-disposition' |
9886 | CAPITALIZED_FIELD = 'Content-Disposition' |
9887 | def initialize(value = nil, charset = 'utf-8') |
9888 | self.charset = charset |
9889 | ensure_filename_quoted(value) |
9890 | self.parse |
9891 | self |
9892 | end |
9893 | def parse(val = value) |
9894 | unless val.blank? |
9895 | end |
9896 | end |
9897 | def element |
9898 | end |
9899 | def disposition_type |
9900 | element.disposition_type |
9901 | end |
9902 | def parameters |
9903 | @parameters = ParameterHash.new |
9904 | @parameters |
9905 | end |
9906 | def filename |
9907 | case |
9908 | when !parameters['filename'].blank? |
9909 | @filename = parameters['filename'] |
9910 | when !parameters['name'].blank? |
9911 | @filename = parameters['name'] |
9912 | else |
9913 | @filename = nil |
9914 | end |
9915 | @filename |
9916 | end |
9917 | def encoded |
9918 | if parameters.length 0 |
9919 | p = ";\r \s#{parameters.encoded}\r " |
9920 | else |
9921 | p = "\r " |
9922 | end |
9923 | "#{CAPITALIZED_FIELD}: #{disposition_type}" + p |
9924 | end |
9925 | def decoded |
9926 | if parameters.length 0 |
9927 | p = "; #{parameters.decoded}" |
9928 | else |
9929 | p = "" |
9930 | end |
9931 | "#{disposition_type}" + p |
9932 | end |
9933 | end |
9934 | end |
9935 | module Mail |
9936 | class ContentIdField StructuredField |
9937 | FIELD_NAME = 'content-id' |
9938 | CAPITALIZED_FIELD = "Content-ID" |
9939 | def initialize(value = nil, charset = 'utf-8') |
9940 | self.charset = charset |
9941 | @uniq = 1 |
9942 | if value.blank? |
9943 | value = generate_content_id |
9944 | else |
9945 | value = strip_field(FIELD_NAME, value) |
9946 | end |
9947 | self.parse |
9948 | self |
9949 | end |
9950 | def parse(val = value) |
9951 | unless val.blank? |
9952 | @element = Mail::MessageIdsElement.new(val) |
9953 | end |
9954 | end |
9955 | def element |
9956 | @element ||= Mail::MessageIdsElement.new(value) |
9957 | end |
9958 | def name |
9959 | 'Content-ID' |
9960 | end |
9961 | def content_id |
9962 | element.message_id |
9963 | end |
9964 | def to_s |
9965 | "#{content_id}" |
9966 | end |
9967 | def encoded |
9968 | "#{CAPITALIZED_FIELD}: #{to_s}\r " |
9969 | end |
9970 | def decoded |
9971 | "#{to_s}" |
9972 | end |
9973 | private |
9974 | def generate_content_id |
9975 | "#{Mail.random_tag}@#{::Socket.gethostname}.mail" |
9976 | end |
9977 | end |
9978 | end |
9979 | module Mail |
9980 | class ContentLocationField StructuredField |
9981 | FIELD_NAME = 'content-location' |
9982 | CAPITALIZED_FIELD = 'Content-Location' |
9983 | def initialize(value = nil, charset = 'utf-8') |
9984 | self.charset = charset |
9985 | self.parse |
9986 | self |
9987 | end |
9988 | def parse(val = value) |
9989 | unless val.blank? |
9990 | @element = Mail::ContentLocationElement.new(val) |
9991 | end |
9992 | end |
9993 | def element |
9994 | end |
9995 | def location |
9996 | element.location |
9997 | end |
9998 | def encoded |
9999 | "#{CAPITALIZED_FIELD}: #{location}\r " |
10000 | end |
10001 | def decoded |
10002 | location |
10003 | end |
10004 | end |
10005 | end |
10006 | module Mail |
10007 | FIELD_NAME = 'content-transfer-encoding' |
10008 | CAPITALIZED_FIELD = 'Content-Transfer-Encoding' |
10009 | def initialize(value = nil, charset = 'utf-8') |
10010 | self.charset = charset |
10011 | value = '7bit' if value.to_s =~ /7-?bits?/i |
10012 | value = '8bit' if value.to_s =~ /8-?bits?/i |
10013 | self.parse |
10014 | self |
10015 | end |
10016 | def parse(val = value) |
10017 | unless val.blank? |
10018 | end |
10019 | end |
10020 | def element |
10021 | end |
10022 | def encoding |
10023 | element.encoding |
10024 | end |
10025 | def encoded |
10026 | "#{CAPITALIZED_FIELD}: #{encoding}\r " |
10027 | end |
10028 | def decoded |
10029 | encoding |
10030 | end |
10031 | end |
10032 | end |
10033 | require 'mail/fields/common/parameter_hash' |
10034 | module Mail |
10035 | class ContentTypeField StructuredField |
10036 | FIELD_NAME = 'content-type' |
10037 | CAPITALIZED_FIELD = 'Content-Type' |
10038 | def initialize(value = nil, charset = 'utf-8') |
10039 | self.charset = charset |
10040 | if value.class == Array |
10041 | @main_type = value[0] |
10042 | @sub_type = value[1] |
10043 | else |
10044 | @main_type = nil |
10045 | @sub_type = nil |
10046 | @parameters = nil |
10047 | value = strip_field(FIELD_NAME, value) |
10048 | end |
10049 | ensure_filename_quoted(value) |
10050 | super(CAPITALIZED_FIELD, value, charset) |
10051 | self.parse |
10052 | self |
10053 | end |
10054 | def parse(val = value) |
10055 | unless val.blank? |
10056 | self.value = val |
10057 | @element = nil |
10058 | element |
10059 | end |
10060 | end |
10061 | def element |
10062 | begin |
10063 | @element ||= Mail::ContentTypeElement.new(value) |
10064 | rescue |
10065 | attempt_to_clean |
10066 | end |
10067 | end |
10068 | def attempt_to_clean |
10069 | rescue |
10070 | end |
10071 | def main_type |
10072 | @main_type ||= element.main_type |
10073 | end |
10074 | def sub_type |
10075 | @sub_type ||= element.sub_type |
10076 | end |
10077 | def string |
10078 | "#{main_type}/#{sub_type}" |
10079 | end |
10080 | def default |
10081 | decoded |
10082 | end |
10083 | alias :content_type :string |
10084 | def parameters |
10085 | unless @parameters |
10086 | @parameters = ParameterHash.new |
10087 | end |
10088 | @parameters |
10089 | end |
10090 | def ContentTypeField.with_boundary(type) |
10091 | new("#{type}; boundary=#{generate_boundary}") |
10092 | end |
10093 | def ContentTypeField.generate_boundary |
10094 | "--==_mimepart_#{Mail.random_tag}" |
10095 | end |
10096 | def value |
10097 | if @value.class == Array |
10098 | else |
10099 | @value |
10100 | end |
10101 | end |
10102 | def stringify(params) |
10103 | end |
10104 | def filename |
10105 | case |
10106 | when parameters['filename'] |
10107 | @filename = parameters['filename'] |
10108 | when parameters['name'] |
10109 | @filename = parameters['name'] |
10110 | else |
10111 | @filename = nil |
10112 | end |
10113 | @filename |
10114 | end |
10115 | def encoded |
10116 | if parameters.length 0 |
10117 | p = ";\r \s#{parameters.encoded}" |
10118 | else |
10119 | p = "" |
10120 | end |
10121 | "#{CAPITALIZED_FIELD}: #{content_type}#{p}\r " |
10122 | end |
10123 | def decoded |
10124 | if parameters.length 0 |
10125 | p = "; #{parameters.decoded}" |
10126 | else |
10127 | p = "" |
10128 | end |
10129 | "#{content_type}" + p |
10130 | end |
10131 | private |
10132 | def method_missing(name, *args, &block) |
10133 | if name.to_s =~ /(\w+)=/ |
10134 | self.parameters[$1] = args.first |
10135 | else |
10136 | super |
10137 | end |
10138 | end |
10139 | def sanatize( val ) |
10140 | val = val. |
10141 | tr(' ',';'). |
10142 | squeeze(';'). |
10143 | if val =~ /(boundary=(\S*))/i |
10144 | else |
10145 | val.downcase! |
10146 | end |
10147 | case |
10148 | "#{$1}/#{$2}; #{$3}" |
10149 | "#{$1}/#{$2}; charset=#{quote_atom($3)}" |
10150 | when val.chomp =~ /^text;?$/i |
10151 | "text/plain;" |
10152 | when val.chomp =~ /^(\w+);\s(.*)$/i |
10153 | "text/plain; #{$2}" |
10154 | "#{$1}; charset=#{quote_atom($2)}" |
10155 | when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i |
10156 | type = $1 |
10157 | params = $2.to_s.split(/\s+/) |
10158 | params = params.map { |i| i.to_s.chomp.strip } |
10159 | params = params.map { |i| i.split(/\s*\=\s*/) } |
10160 | "#{type}; #{params}" |
10161 | when val =~ /^\s*$/ |
10162 | 'text/plain' |
10163 | else |
10164 | '' |
10165 | end |
10166 | end |
10167 | def get_mime_type( val ) |
10168 | case |
10169 | when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i |
10170 | "#{$1}/#{$2}" |
10171 | else |
10172 | 'text/plain' |
10173 | end |
10174 | end |
10175 | end |
10176 | end |
10177 | require 'mail/fields/common/common_date' |
10178 | module Mail |
10179 | class DateField StructuredField |
10180 | include Mail::CommonDate |
10181 | FIELD_NAME = 'date' |
10182 | CAPITALIZED_FIELD = "Date" |
10183 | def initialize(value = nil, charset = 'utf-8') |
10184 | self.charset = charset |
10185 | if value.blank? |
10186 | else |
10187 | value = strip_field(FIELD_NAME, value) |
10188 | value.to_s.gsub!(/\(.*?\)/, '') |
10189 | end |
10190 | super(CAPITALIZED_FIELD, value, charset) |
10191 | rescue ArgumentError = e |
10192 | raise e unless "invalid date"==e.message |
10193 | end |
10194 | def encoded |
10195 | do_encode(CAPITALIZED_FIELD) |
10196 | end |
10197 | def decoded |
10198 | do_decode |
10199 | end |
10200 | end |
10201 | end |
10202 | require 'mail/fields/common/common_address' |
10203 | module Mail |
10204 | class FromField StructuredField |
10205 | include Mail::CommonAddress |
10206 | FIELD_NAME = 'from' |
10207 | CAPITALIZED_FIELD = 'From' |
10208 | def initialize(value = nil, charset = 'utf-8') |
10209 | self.charset = charset |
10210 | self.parse |
10211 | self |
10212 | end |
10213 | def encoded |
10214 | do_encode(CAPITALIZED_FIELD) |
10215 | end |
10216 | def decoded |
10217 | do_decode |
10218 | end |
10219 | end |
10220 | end |
10221 | require 'mail/fields/common/common_message_id' |
10222 | module Mail |
10223 | class InReplyToField StructuredField |
10224 | include Mail::CommonMessageId |
10225 | FIELD_NAME = 'in-reply-to' |
10226 | CAPITALIZED_FIELD = 'In-Reply-To' |
10227 | def initialize(value = nil, charset = 'utf-8') |
10228 | self.charset = charset |
10229 | self.parse |
10230 | self |
10231 | end |
10232 | def encoded |
10233 | do_encode(CAPITALIZED_FIELD) |
10234 | end |
10235 | def decoded |
10236 | do_decode |
10237 | end |
10238 | end |
10239 | end |
10240 | module Mail |
10241 | class KeywordsField StructuredField |
10242 | FIELD_NAME = 'keywords' |
10243 | CAPITALIZED_FIELD = 'Keywords' |
10244 | def initialize(value = nil, charset = 'utf-8') |
10245 | self.charset = charset |
10246 | self.parse |
10247 | self |
10248 | end |
10249 | def parse(val = value) |
10250 | unless val.blank? |
10251 | @phrase_list ||= PhraseList.new(value) |
10252 | end |
10253 | end |
10254 | def phrase_list |
10255 | @phrase_list ||= PhraseList.new(value) |
10256 | end |
10257 | def keywords |
10258 | phrase_list.phrases |
10259 | end |
10260 | def encoded |
10261 | end |
10262 | def decoded |
10263 | keywords.join(', ') |
10264 | end |
10265 | def default |
10266 | keywords |
10267 | end |
10268 | end |
10269 | end |
10270 | require 'mail/fields/common/common_message_id' |
10271 | module Mail |
10272 | class MessageIdField StructuredField |
10273 | include Mail::CommonMessageId |
10274 | FIELD_NAME = 'message-id' |
10275 | CAPITALIZED_FIELD = 'Message-ID' |
10276 | def initialize(value = nil, charset = 'utf-8') |
10277 | self.charset = charset |
10278 | @uniq = 1 |
10279 | if value.blank? |
10280 | self.name = CAPITALIZED_FIELD |
10281 | self.value = generate_message_id |
10282 | else |
10283 | end |
10284 | self.parse |
10285 | self |
10286 | end |
10287 | def name |
10288 | 'Message-ID' |
10289 | end |
10290 | def message_ids |
10291 | [message_id] |
10292 | end |
10293 | def to_s |
10294 | "#{message_id}" |
10295 | end |
10296 | def encoded |
10297 | do_encode(CAPITALIZED_FIELD) |
10298 | end |
10299 | def decoded |
10300 | do_decode |
10301 | end |
10302 | private |
10303 | def generate_message_id |
10304 | "#{Mail.random_tag}@#{::Socket.gethostname}.mail" |
10305 | end |
10306 | end |
10307 | end |
10308 | module Mail |
10309 | class MimeVersionField StructuredField |
10310 | FIELD_NAME = 'mime-version' |
10311 | CAPITALIZED_FIELD = 'Mime-Version' |
10312 | def initialize(value = nil, charset = 'utf-8') |
10313 | self.charset = charset |
10314 | if value.blank? |
10315 | value = '1.0' |
10316 | end |
10317 | self.parse |
10318 | self |
10319 | end |
10320 | def parse(val = value) |
10321 | unless val.blank? |
10322 | @element = Mail::MimeVersionElement.new(val) |
10323 | end |
10324 | end |
10325 | def element |
10326 | @element ||= Mail::MimeVersionElement.new(value) |
10327 | end |
10328 | def version |
10329 | "#{element.major}.#{element.minor}" |
10330 | end |
10331 | def major |
10332 | element.major.to_i |
10333 | end |
10334 | def minor |
10335 | element.minor.to_i |
10336 | end |
10337 | def encoded |
10338 | "#{CAPITALIZED_FIELD}: #{version}\r " |
10339 | end |
10340 | def decoded |
10341 | version |
10342 | end |
10343 | end |
10344 | end |
10345 | require 'mail/fields/unstructured_field' |
10346 | module Mail |
10347 | class OptionalField UnstructuredField |
10348 | end |
10349 | end |
10350 | module Mail |
10351 | class ReceivedField StructuredField |
10352 | FIELD_NAME = 'received' |
10353 | CAPITALIZED_FIELD = 'Received' |
10354 | def initialize(value = nil, charset = 'utf-8') |
10355 | self.charset = charset |
10356 | self.parse |
10357 | self |
10358 | end |
10359 | def parse(val = value) |
10360 | unless val.blank? |
10361 | @element = Mail::ReceivedElement.new(val) |
10362 | end |
10363 | end |
10364 | def element |
10365 | @element ||= Mail::ReceivedElement.new(value) |
10366 | end |
10367 | def date_time |
10368 | end |
10369 | def info |
10370 | element.info |
10371 | end |
10372 | def formatted_date |
10373 | end |
10374 | def encoded |
10375 | if value.blank? |
10376 | "#{CAPITALIZED_FIELD}: \r " |
10377 | else |
10378 | end |
10379 | end |
10380 | def decoded |
10381 | if value.blank? |
10382 | "" |
10383 | else |
10384 | "#{info}; #{formatted_date}" |
10385 | end |
10386 | end |
10387 | end |
10388 | end |
10389 | require 'mail/fields/common/common_message_id' |
10390 | module Mail |
10391 | class ReferencesField StructuredField |
10392 | include CommonMessageId |
10393 | FIELD_NAME = 'references' |
10394 | CAPITALIZED_FIELD = 'References' |
10395 | def initialize(value = nil, charset = 'utf-8') |
10396 | self.charset = charset |
10397 | self.parse |
10398 | self |
10399 | end |
10400 | def encoded |
10401 | do_encode(CAPITALIZED_FIELD) |
10402 | end |
10403 | def decoded |
10404 | do_decode |
10405 | end |
10406 | end |
10407 | end |
10408 | require 'mail/fields/common/common_address' |
10409 | module Mail |
10410 | class ReplyToField StructuredField |
10411 | include Mail::CommonAddress |
10412 | FIELD_NAME = 'reply-to' |
10413 | CAPITALIZED_FIELD = 'Reply-To' |
10414 | def initialize(value = nil, charset = 'utf-8') |
10415 | self.charset = charset |
10416 | self.parse |
10417 | self |
10418 | end |
10419 | def encoded |
10420 | do_encode(CAPITALIZED_FIELD) |
10421 | end |
10422 | def decoded |
10423 | do_decode |
10424 | end |
10425 | end |
10426 | end |
10427 | require 'mail/fields/common/common_address' |
10428 | module Mail |
10429 | class ResentBccField StructuredField |
10430 | include Mail::CommonAddress |
10431 | FIELD_NAME = 'resent-bcc' |
10432 | CAPITALIZED_FIELD = 'Resent-Bcc' |
10433 | def initialize(value = nil, charset = 'utf-8') |
10434 | self.charset = charset |
10435 | self.parse |
10436 | self |
10437 | end |
10438 | def encoded |
10439 | do_encode(CAPITALIZED_FIELD) |
10440 | end |
10441 | def decoded |
10442 | do_decode |
10443 | end |
10444 | end |
10445 | end |
10446 | require 'mail/fields/common/common_address' |
10447 | module Mail |
10448 | class ResentCcField StructuredField |
10449 | include Mail::CommonAddress |
10450 | FIELD_NAME = 'resent-cc' |
10451 | CAPITALIZED_FIELD = 'Resent-Cc' |
10452 | def initialize(value = nil, charset = 'utf-8') |
10453 | self.charset = charset |
10454 | self.parse |
10455 | self |
10456 | end |
10457 | def encoded |
10458 | do_encode(CAPITALIZED_FIELD) |
10459 | end |
10460 | def decoded |
10461 | do_decode |
10462 | end |
10463 | end |
10464 | end |
10465 | require 'mail/fields/common/common_date' |
10466 | module Mail |
10467 | class ResentDateField StructuredField |
10468 | include Mail::CommonDate |
10469 | FIELD_NAME = 'resent-date' |
10470 | CAPITALIZED_FIELD = 'Resent-Date' |
10471 | def initialize(value = nil, charset = 'utf-8') |
10472 | self.charset = charset |
10473 | if value.blank? |
10474 | else |
10475 | value = strip_field(FIELD_NAME, value) |
10476 | end |
10477 | super(CAPITALIZED_FIELD, value, charset) |
10478 | self |
10479 | end |
10480 | def encoded |
10481 | do_encode(CAPITALIZED_FIELD) |
10482 | end |
10483 | def decoded |
10484 | do_decode |
10485 | end |
10486 | end |
10487 | end |
10488 | require 'mail/fields/common/common_address' |
10489 | module Mail |
10490 | class ResentFromField StructuredField |
10491 | include Mail::CommonAddress |
10492 | FIELD_NAME = 'resent-from' |
10493 | CAPITALIZED_FIELD = 'Resent-From' |
10494 | def initialize(value = nil, charset = 'utf-8') |
10495 | self.charset = charset |
10496 | self.parse |
10497 | self |
10498 | end |
10499 | def encoded |
10500 | do_encode(CAPITALIZED_FIELD) |
10501 | end |
10502 | def decoded |
10503 | do_decode |
10504 | end |
10505 | end |
10506 | end |
10507 | require 'mail/fields/common/common_message_id' |
10508 | module Mail |
10509 | class ResentMessageIdField StructuredField |
10510 | include CommonMessageId |
10511 | FIELD_NAME = 'resent-message-id' |
10512 | CAPITALIZED_FIELD = 'Resent-Message-ID' |
10513 | def initialize(value = nil, charset = 'utf-8') |
10514 | self.charset = charset |
10515 | self.parse |
10516 | self |
10517 | end |
10518 | def name |
10519 | 'Resent-Message-ID' |
10520 | end |
10521 | def encoded |
10522 | do_encode(CAPITALIZED_FIELD) |
10523 | end |
10524 | def decoded |
10525 | do_decode |
10526 | end |
10527 | end |
10528 | end |
10529 | require 'mail/fields/common/common_address' |
10530 | module Mail |
10531 | class ResentSenderField StructuredField |
10532 | include Mail::CommonAddress |
10533 | FIELD_NAME = 'resent-sender' |
10534 | CAPITALIZED_FIELD = 'Resent-Sender' |
10535 | def initialize(value = nil, charset = 'utf-8') |
10536 | self.charset = charset |
10537 | self.parse |
10538 | self |
10539 | end |
10540 | def addresses |
10541 | [address.address] |
10542 | end |
10543 | def address |
10544 | address_list.addresses.first |
10545 | end |
10546 | def encoded |
10547 | do_encode(CAPITALIZED_FIELD) |
10548 | end |
10549 | def decoded |
10550 | do_decode |
10551 | end |
10552 | end |
10553 | end |
10554 | require 'mail/fields/common/common_address' |
10555 | module Mail |
10556 | class ResentToField StructuredField |
10557 | include Mail::CommonAddress |
10558 | FIELD_NAME = 'resent-to' |
10559 | CAPITALIZED_FIELD = 'Resent-To' |
10560 | def initialize(value = nil, charset = 'utf-8') |
10561 | self.charset = charset |
10562 | self.parse |
10563 | self |
10564 | end |
10565 | def encoded |
10566 | do_encode(CAPITALIZED_FIELD) |
10567 | end |
10568 | def decoded |
10569 | do_decode |
10570 | end |
10571 | end |
10572 | end |
10573 | require 'mail/fields/common/common_address' |
10574 | module Mail |
10575 | class ReturnPathField StructuredField |
10576 | include Mail::CommonAddress |
10577 | FIELD_NAME = 'return-path' |
10578 | CAPITALIZED_FIELD = 'Return-Path' |
10579 | def initialize(value = nil, charset = 'utf-8') |
10580 | value = nil if value == '' |
10581 | self.charset = charset |
10582 | self.parse |
10583 | self |
10584 | end |
10585 | def encoded |
10586 | "#{CAPITALIZED_FIELD}: #{address}\r " |
10587 | end |
10588 | def decoded |
10589 | do_decode |
10590 | end |
10591 | def address |
10592 | addresses.first |
10593 | end |
10594 | def default |
10595 | address |
10596 | end |
10597 | end |
10598 | end |
10599 | require 'mail/fields/common/common_address' |
10600 | module Mail |
10601 | class SenderField StructuredField |
10602 | include Mail::CommonAddress |
10603 | FIELD_NAME = 'sender' |
10604 | CAPITALIZED_FIELD = 'Sender' |
10605 | def initialize(value = nil, charset = 'utf-8') |
10606 | self.charset = charset |
10607 | self.parse |
10608 | self |
10609 | end |
10610 | def addresses |
10611 | [address.address] |
10612 | end |
10613 | def address |
10614 | address_list.addresses.first |
10615 | end |
10616 | def encoded |
10617 | do_encode(CAPITALIZED_FIELD) |
10618 | end |
10619 | def decoded |
10620 | do_decode |
10621 | end |
10622 | def default |
10623 | address.address |
10624 | end |
10625 | end |
10626 | end |
10627 | require 'mail/fields/common/common_field' |
10628 | module Mail |
10629 | class StructuredField |
10630 | include Mail::CommonField |
10631 | include Mail::Utilities |
10632 | self.name = name |
10633 | self.value = value |
10634 | self.charset = charset |
10635 | self |
10636 | end |
10637 | def charset |
10638 | @charset |
10639 | end |
10640 | def charset=(val) |
10641 | @charset = val |
10642 | end |
10643 | def default |
10644 | decoded |
10645 | end |
10646 | def errors |
10647 | [] |
10648 | end |
10649 | end |
10650 | end |
10651 | module Mail |
10652 | class SubjectField UnstructuredField |
10653 | FIELD_NAME = 'subject' |
10654 | CAPITALIZED_FIELD = "Subject" |
10655 | def initialize(value = nil, charset = 'utf-8') |
10656 | self.charset = charset |
10657 | end |
10658 | end |
10659 | end |
10660 | require 'mail/fields/common/common_address' |
10661 | module Mail |
10662 | class ToField StructuredField |
10663 | include Mail::CommonAddress |
10664 | FIELD_NAME = 'to' |
10665 | CAPITALIZED_FIELD = 'To' |
10666 | def initialize(value = nil, charset = 'utf-8') |
10667 | self.charset = charset |
10668 | self.parse |
10669 | self |
10670 | end |
10671 | def encoded |
10672 | do_encode(CAPITALIZED_FIELD) |
10673 | end |
10674 | def decoded |
10675 | do_decode |
10676 | end |
10677 | end |
10678 | end |
10679 | require 'mail/fields/common/common_field' |
10680 | module Mail |
10681 | class UnstructuredField |
10682 | include Mail::CommonField |
10683 | include Mail::Utilities |
10684 | attr_accessor :charset |
10685 | attr_reader :errors |
10686 | def initialize(name, value, charset = nil) |
10687 | @errors = [] |
10688 | if value.is_a?(Array) |
10689 | value = value.join(', ') |
10690 | else |
10691 | value = value.to_s |
10692 | end |
10693 | if charset |
10694 | self.charset = charset |
10695 | else |
10696 | if value.respond_to?(:encoding) |
10697 | self.charset = value.encoding |
10698 | else |
10699 | self.charset = $KCODE |
10700 | end |
10701 | end |
10702 | self.name = name |
10703 | self.value = value |
10704 | self |
10705 | end |
10706 | def encoded |
10707 | do_encode |
10708 | end |
10709 | def decoded |
10710 | do_decode |
10711 | end |
10712 | def default |
10713 | decoded |
10714 | end |
10715 | def parse # An unstructured field does not parse |
10716 | self |
10717 | end |
10718 | private |
10719 | def do_encode |
10720 | value.nil? ? '' : "#{wrapped_value}\r " |
10721 | end |
10722 | def do_decode |
10723 | end |
10724 | def wrapped_value # :nodoc: |
10725 | wrap_lines(name, fold("#{name}: ".length)) |
10726 | end |
10727 | def wrap_lines(name, folded_lines) |
10728 | result = ["#{name}: #{folded_lines.shift}"] |
10729 | result.concat(folded_lines) |
10730 | result.join("\r \s") |
10731 | end |
10732 | def fold(prepend = 0) # :nodoc: |
10733 | encoding = normalized_encoding |
10734 | decoded_string = decoded.to_s |
10735 | should_encode = decoded_string.not_ascii_only? |
10736 | if should_encode |
10737 | first = true |
10738 | if first |
10739 | first = !first |
10740 | else |
10741 | word = " " word |
10742 | end |
10743 | if word.not_ascii_only? |
10744 | word |
10745 | else |
10746 | word.scan(/.{7}|.+$/) |
10747 | end |
10748 | end.flatten |
10749 | else |
10750 | words = decoded_string.split(/[ \t]/) |
10751 | end |
10752 | folded_lines = [] |
10753 | while !words.empty? |
10754 | limit = 78 - prepend |
10755 | line = "" |
10756 | first_word = true |
10757 | while !words.empty? |
10758 | break unless word = words.first.dup |
10759 | word = encode(word) if should_encode |
10760 | word = encode_crlf(word) |
10761 | words.shift |
10762 | if first_word |
10763 | first_word = false |
10764 | else |
10765 | line " " if !should_encode |
10766 | end |
10767 | line word |
10768 | end |
10769 | folded_lines line |
10770 | prepend = 0 |
10771 | end |
10772 | folded_lines |
10773 | end |
10774 | def encode(value) |
10775 | value.gsub!(/"/, '=22') |
10776 | value.gsub!(/\(/, '=28') |
10777 | value.gsub!(/\)/, '=29') |
10778 | value.gsub!(/\?/, '=3F') |
10779 | value.gsub!(/_/, '=5F') |
10780 | value.gsub!(/ /, '_') |
10781 | value |
10782 | end |
10783 | def encode_crlf(value) |
10784 | value.gsub!(CR, CR_ENCODED) |
10785 | value.gsub!(LF, LF_ENCODED) |
10786 | value |
10787 | end |
10788 | def normalized_encoding |
10789 | encoding = charset.to_s.upcase.gsub('_', '-') |
10790 | encoding |
10791 | end |
10792 | end |
10793 | end |
10794 | module Mail |
10795 | end |
10796 | module Mail |
10797 | class Header |
10798 | include Constants |
10799 | include Utilities |
10800 | include Enumerable |
10801 | @@maximum_amount = 1000 |
10802 | def self.maximum_amount |
10803 | @@maximum_amount |
10804 | end |
10805 | def self.maximum_amount=(value) |
10806 | @@maximum_amount = value |
10807 | end |
10808 | def initialize(header_text = nil, charset = nil) |
10809 | @charset = charset |
10810 | self.raw_source = header_text.to_crlf.lstrip |
10811 | split_header if header_text |
10812 | end |
10813 | def initialize_copy(original) |
10814 | super |
10815 | @fields = @fields.dup |
10816 | end |
10817 | def raw_source |
10818 | @raw_source |
10819 | end |
10820 | def fields |
10821 | @fields ||= FieldList.new |
10822 | end |
10823 | def fields=(unfolded_fields) |
10824 | @fields = Mail::FieldList.new |
10825 | field = Field.new(field, nil, charset) |
10826 | selected.first.update(field.name, field.value) |
10827 | else |
10828 | @fields field |
10829 | end |
10830 | end |
10831 | end |
10832 | def errors |
10833 | @fields.map(&:errors).flatten(1) |
10834 | end |
10835 | def [](name) |
10836 | name = dasherize(name) |
10837 | name.downcase! |
10838 | selected = select_field_for(name) |
10839 | case |
10840 | when selected.length 1 |
10841 | selected.map { |f| f } |
10842 | when !selected.blank? |
10843 | selected.first |
10844 | else |
10845 | nil |
10846 | end |
10847 | end |
10848 | def []=(name, value) |
10849 | name = dasherize(name) |
10850 | if name.include?(':') |
10851 | end |
10852 | fn = name.downcase |
10853 | selected = select_field_for(fn) |
10854 | case |
10855 | when !selected.blank? && value == nil |
10856 | fields.delete_if { |f| selected.include?(f) } |
10857 | when !selected.blank? && limited_field?(fn) |
10858 | selected.first.update(fn, value) |
10859 | else |
10860 | self.fields Field.new(name.to_s, value, charset) |
10861 | end |
10862 | if dasherize(fn) == "content-type" |
10863 | end |
10864 | end |
10865 | def charset |
10866 | @charset |
10867 | end |
10868 | def charset=(val) |
10869 | if params |
10870 | params[:charset] = val |
10871 | end |
10872 | @charset = val |
10873 | end |
10874 | message-id in-reply-to references subject |
10875 | return-path content-type mime-version |
10876 | content-transfer-encoding content-description |
10877 | content-id content-disposition content-location] |
10878 | def encoded |
10879 | buffer = '' |
10880 | fields.each do |field| |
10881 | buffer field.encoded |
10882 | end |
10883 | buffer |
10884 | end |
10885 | def to_s |
10886 | encoded |
10887 | end |
10888 | def decoded |
10889 | end |
10890 | def field_summary |
10891 | end |
10892 | def has_message_id? |
10893 | end |
10894 | def has_content_id? |
10895 | end |
10896 | def has_date? |
10897 | end |
10898 | def has_mime_version? |
10899 | end |
10900 | private |
10901 | def raw_source=(val) |
10902 | @raw_source = val |
10903 | end |
10904 | def split_header |
10905 | self.fields = raw_source.split(HEADER_SPLIT) |
10906 | end |
10907 | def select_field_for(name) |
10908 | fields.select { |f| f.responsible_for?(name) } |
10909 | end |
10910 | def limited_field?(name) |
10911 | LIMITED_FIELDS.include?(name.to_s.downcase) |
10912 | end |
10913 | def each( &block ) |
10914 | return self.fields.each( &block ) if block |
10915 | self.fields.each |
10916 | end |
10917 | end |
10918 | end |
10919 | module Mail |
10920 | class IndifferentHash Hash |
10921 | def initialize(constructor = {}) |
10922 | if constructor.is_a?(Hash) |
10923 | super() |
10924 | update(constructor) |
10925 | else |
10926 | super(constructor) |
10927 | end |
10928 | end |
10929 | def default(key = nil) |
10930 | if key.is_a?(Symbol) && include?(key = key.to_s) |
10931 | self[key] |
10932 | else |
10933 | super |
10934 | end |
10935 | end |
10936 | def self.new_from_hash_copying_default(hash) |
10937 | IndifferentHash.new(hash).tap do |new_hash| |
10938 | new_hash.default = hash.default |
10939 | end |
10940 | end |
10941 | def []=(key, value) |
10942 | end |
10943 | alias_method :store, :[]= |
10944 | def update(other_hash) |
10945 | self |
10946 | end |
10947 | alias_method :merge!, :update |
10948 | def key?(key) |
10949 | super(convert_key(key)) |
10950 | end |
10951 | alias_method :include?, :key? |
10952 | alias_method :has_key?, :key? |
10953 | alias_method :member?, :key? |
10954 | def fetch(key, *extras) |
10955 | super(convert_key(key), *extras) |
10956 | end |
10957 | def values_at(*indices) |
10958 | indices.collect {|key| self[convert_key(key)]} |
10959 | end |
10960 | def dup |
10961 | IndifferentHash.new(self) |
10962 | end |
10963 | def merge(hash) |
10964 | self.dup.update(hash) |
10965 | end |
10966 | def reverse_merge(other_hash) |
10967 | end |
10968 | def reverse_merge!(other_hash) |
10969 | replace(reverse_merge( other_hash )) |
10970 | end |
10971 | def delete(key) |
10972 | super(convert_key(key)) |
10973 | end |
10974 | def stringify_keys!; self end |
10975 | def stringify_keys; dup end |
10976 | def symbolize_keys; to_hash.symbolize_keys end |
10977 | def to_options!; self end |
10978 | def to_hash |
10979 | Hash.new(default).merge!(self) |
10980 | end |
10981 | protected |
10982 | def convert_key(key) |
10983 | key.kind_of?(Symbol) ? key.to_s : key |
10984 | end |
10985 | def convert_value(value) |
10986 | if value.class == Hash |
10987 | self.class.new_from_hash_copying_default(value) |
10988 | elsif value.is_a?(Array) |
10989 | else |
10990 | value |
10991 | end |
10992 | end |
10993 | end |
10994 | end |
10995 | module Mail |
10996 | def self.new(*args, &block) |
10997 | Message.new(args, &block) |
10998 | end |
10999 | def self.defaults(&block) |
11000 | Configuration.instance.instance_eval(&block) |
11001 | end |
11002 | def self.delivery_method |
11003 | Configuration.instance.delivery_method |
11004 | end |
11005 | def self.retriever_method |
11006 | Configuration.instance.retriever_method |
11007 | end |
11008 | def self.deliver(*args, &block) |
11009 | mail = self.new(args, &block) |
11010 | mail.deliver |
11011 | |
11012 | end |
11013 | def self.find(*args, &block) |
11014 | retriever_method.find(*args, &block) |
11015 | end |
11016 | def self.find_and_delete(*args, &block) |
11017 | retriever_method.find_and_delete(*args, &block) |
11018 | end |
11019 | def self.first(*args, &block) |
11020 | retriever_method.first(*args, &block) |
11021 | end |
11022 | def self.last(*args, &block) |
11023 | retriever_method.last(*args, &block) |
11024 | end |
11025 | def self.all(*args, &block) |
11026 | retriever_method.all(*args, &block) |
11027 | end |
11028 | def self.read(filename) |
11029 | end |
11030 | def self.delete_all(*args, &block) |
11031 | retriever_method.delete_all(*args, &block) |
11032 | end |
11033 | def Mail.read_from_string(mail_as_string) |
11034 | Mail.new(mail_as_string) |
11035 | end |
11036 | def Mail.connection(&block) |
11037 | retriever_method.connection(&block) |
11038 | end |
11039 | @@delivery_notification_observers = [] |
11040 | @@delivery_interceptors = [] |
11041 | def self.register_observer(observer) |
11042 | @@delivery_notification_observers observer |
11043 | end |
11044 | end |
11045 | def self.unregister_observer(observer) |
11046 | end |
11047 | def self.register_interceptor(interceptor) |
11048 | @@delivery_interceptors interceptor |
11049 | end |
11050 | end |
11051 | def self.unregister_interceptor(interceptor) |
11052 | @@delivery_interceptors.delete(interceptor) |
11053 | end |
11054 | def self.inform_observers(mail) |
11055 | observer.delivered_email(mail) |
11056 | end |
11057 | end |
11058 | def self.inform_interceptors(mail) |
11059 | @@delivery_interceptors.each do |interceptor| |
11060 | interceptor.delivering_email(mail) |
11061 | end |
11062 | end |
11063 | protected |
11064 | RANDOM_TAG='%x%x_%x%x%d%x' |
11065 | def self.random_tag |
11066 | t = Time.now |
11067 | sprintf(RANDOM_TAG, |
11068 | t.to_i, t.tv_usec, |
11069 | end |
11070 | private |
11071 | def self.something_random |
11072 | end |
11073 | def self.uniq |
11074 | @@uniq += 1 |
11075 | end |
11076 | @@uniq = self.something_random |
11077 | end |
11078 | module Mail |
11079 | module Matchers |
11080 | def have_sent_email |
11081 | HasSentEmailMatcher.new(self) |
11082 | end |
11083 | class HasSentEmailMatcher |
11084 | def initialize(_context) |
11085 | end |
11086 | def matches?(subject) |
11087 | !(matching_deliveries.empty?) |
11088 | end |
11089 | def from(sender) |
11090 | @sender = sender |
11091 | self |
11092 | end |
11093 | def to(recipient_or_list) |
11094 | @recipients ||= [] |
11095 | if recipient_or_list.kind_of?(Array) |
11096 | @recipients += recipient_or_list |
11097 | else |
11098 | @recipients recipient_or_list |
11099 | end |
11100 | self |
11101 | end |
11102 | def cc(recipient_or_list) |
11103 | @copy_recipients ||= [] |
11104 | if recipient_or_list.kind_of?(Array) |
11105 | @copy_recipients += recipient_or_list |
11106 | else |
11107 | @copy_recipients recipient_or_list |
11108 | end |
11109 | self |
11110 | end |
11111 | def bcc(recipient_or_list) |
11112 | @blind_copy_recipients ||= [] |
11113 | if recipient_or_list.kind_of?(Array) |
11114 | @blind_copy_recipients += recipient_or_list |
11115 | else |
11116 | @blind_copy_recipients recipient_or_list |
11117 | end |
11118 | self |
11119 | end |
11120 | def with_subject(subject) |
11121 | @subject = subject |
11122 | self |
11123 | end |
11124 | def matching_subject(subject_matcher) |
11125 | @subject_matcher = subject_matcher |
11126 | self |
11127 | end |
11128 | def with_body(body) |
11129 | @body = body |
11130 | self |
11131 | end |
11132 | def matching_body(body_matcher) |
11133 | @body_matcher = body_matcher |
11134 | self |
11135 | end |
11136 | def description |
11137 | result = "send a matching email" |
11138 | result |
11139 | end |
11140 | def failure_message |
11141 | result = "Expected email to be sent " |
11142 | result += explain_expectations |
11143 | result += dump_deliveries |
11144 | result |
11145 | end |
11146 | def failure_message_when_negated |
11147 | result = "Expected no email to be sent " |
11148 | result += explain_expectations |
11149 | result += dump_deliveries |
11150 | result |
11151 | end |
11152 | protected |
11153 | def filter_matched_deliveries(deliveries) |
11154 | candidate_deliveries = deliveries |
11155 | end |
11156 | candidate_deliveries |
11157 | end |
11158 | def matches_on_sender?(delivery) |
11159 | delivery.from.include?(@sender) |
11160 | end |
11161 | def matches_on_recipients?(delivery) |
11162 | end |
11163 | def matches_on_copy_recipients?(delivery) |
11164 | end |
11165 | def matches_on_blind_copy_recipients?(delivery) |
11166 | end |
11167 | def matches_on_subject?(delivery) |
11168 | delivery.subject == @subject |
11169 | end |
11170 | def matches_on_subject_matcher?(delivery) |
11171 | @subject_matcher.match delivery.subject |
11172 | end |
11173 | def matches_on_body?(delivery) |
11174 | delivery.body == @body |
11175 | end |
11176 | def matches_on_body_matcher?(delivery) |
11177 | @body_matcher.match delivery.body.raw_source |
11178 | end |
11179 | def explain_expectations |
11180 | result = '' |
11181 | result |
11182 | end |
11183 | def dump_deliveries |
11184 | end |
11185 | end |
11186 | end |
11187 | end |
11188 | require "yaml" |
11189 | module Mail |
11190 | class Message |
11191 | include Constants |
11192 | include Utilities |
11193 | def initialize(*args, &block) |
11194 | @body = nil |
11195 | @body_raw = nil |
11196 | @separate_parts = false |
11197 | @text_part = nil |
11198 | @html_part = nil |
11199 | @errors = nil |
11200 | @header = nil |
11201 | @charset = self.class.default_charset |
11202 | @defaulted_charset = true |
11203 | @smtp_envelope_from = nil |
11204 | @smtp_envelope_to = nil |
11205 | @perform_deliveries = true |
11206 | @raise_delivery_errors = true |
11207 | @delivery_handler = nil |
11208 | @delivery_method = Mail.delivery_method.dup |
11209 | @mark_for_delete = false |
11210 | if args.flatten.first.respond_to?(:each_pair) |
11211 | init_with_hash(args.flatten.first) |
11212 | else |
11213 | init_with_string(args.flatten[0].to_s) |
11214 | end |
11215 | if block_given? |
11216 | instance_eval(&block) |
11217 | end |
11218 | self |
11219 | end |
11220 | attr_accessor :delivery_handler |
11221 | attr_accessor :perform_deliveries |
11222 | attr_accessor :raise_delivery_errors |
11223 | def self.default_charset; @@default_charset; end |
11224 | self.default_charset = 'UTF-8' |
11225 | def register_for_delivery_notification(observer) |
11226 | Mail.register_observer(observer) |
11227 | end |
11228 | def inform_observers |
11229 | Mail.inform_observers(self) |
11230 | end |
11231 | def inform_interceptors |
11232 | Mail.inform_interceptors(self) |
11233 | end |
11234 | def deliver |
11235 | inform_interceptors |
11236 | if delivery_handler |
11237 | else |
11238 | do_delivery |
11239 | end |
11240 | inform_observers |
11241 | self |
11242 | end |
11243 | def deliver! |
11244 | inform_interceptors |
11245 | response = delivery_method.deliver!(self) |
11246 | inform_observers |
11247 | end |
11248 | def delivery_method(method = nil, settings = {}) |
11249 | unless method |
11250 | @delivery_method |
11251 | else |
11252 | end |
11253 | end |
11254 | def reply(*args, &block) |
11255 | self.class.new.tap do |reply| |
11256 | if message_id |
11257 | bracketed_message_id = "#{message_id}" |
11258 | reply.in_reply_to = bracketed_message_id |
11259 | if !references.nil? |
11260 | refs = [references].flatten.map { |r| "#{r}" } |
11261 | refs bracketed_message_id |
11262 | reply.references = refs.join(' ') |
11263 | end |
11264 | reply.references ||= bracketed_message_id |
11265 | end |
11266 | if subject |
11267 | end |
11268 | if reply_to || from |
11269 | end |
11270 | if to |
11271 | reply.from = self[:to].formatted.first.to_s |
11272 | end |
11273 | unless args.empty? |
11274 | if args.flatten.first.respond_to?(:each_pair) |
11275 | reply.send(:init_with_hash, args.flatten.first) |
11276 | else |
11277 | end |
11278 | end |
11279 | if block_given? |
11280 | reply.instance_eval(&block) |
11281 | end |
11282 | end |
11283 | end |
11284 | def =(other) |
11285 | if other.nil? |
11286 | 1 |
11287 | else |
11288 | self.date = other.date |
11289 | end |
11290 | end |
11291 | def ==(other) |
11292 | return false unless other.respond_to?(:encoded) |
11293 | if self.message_id && other.message_id |
11294 | self.encoded == other.encoded |
11295 | else |
11296 | begin |
11297 | self.encoded == other.encoded |
11298 | ensure |
11299 | end |
11300 | end |
11301 | end |
11302 | def initialize_copy(original) |
11303 | super |
11304 | @header = @header.dup |
11305 | end |
11306 | def raw_source |
11307 | @raw_source |
11308 | end |
11309 | def set_envelope( val ) |
11310 | @raw_envelope = val |
11311 | @envelope = Mail::Envelope.new( val ) |
11312 | end |
11313 | def raw_envelope |
11314 | @raw_envelope |
11315 | end |
11316 | def envelope_from |
11317 | @envelope ? @envelope.from : nil |
11318 | end |
11319 | def envelope_date |
11320 | @envelope ? @envelope.date : nil |
11321 | end |
11322 | def header=(value) |
11323 | @header = Mail::Header.new(value, charset) |
11324 | end |
11325 | def header(value = nil) |
11326 | value ? self.header = value : @header |
11327 | end |
11328 | def headers(hash = {}) |
11329 | hash.each_pair do |k,v| |
11330 | header[k] = v |
11331 | end |
11332 | end |
11333 | def errors |
11334 | header.errors |
11335 | end |
11336 | def bcc( val = nil ) |
11337 | default :bcc, val |
11338 | end |
11339 | def bcc=( val ) |
11340 | header[:bcc] = val |
11341 | end |
11342 | def cc( val = nil ) |
11343 | default :cc, val |
11344 | end |
11345 | def cc=( val ) |
11346 | header[:cc] = val |
11347 | end |
11348 | def comments( val = nil ) |
11349 | default :comments, val |
11350 | end |
11351 | def comments=( val ) |
11352 | header[:comments] = val |
11353 | end |
11354 | def content_description( val = nil ) |
11355 | default :content_description, val |
11356 | end |
11357 | def content_description=( val ) |
11358 | header[:content_description] = val |
11359 | end |
11360 | def content_disposition( val = nil ) |
11361 | default :content_disposition, val |
11362 | end |
11363 | def content_disposition=( val ) |
11364 | header[:content_disposition] = val |
11365 | end |
11366 | def content_id( val = nil ) |
11367 | default :content_id, val |
11368 | end |
11369 | def content_id=( val ) |
11370 | header[:content_id] = val |
11371 | end |
11372 | def content_location( val = nil ) |
11373 | default :content_location, val |
11374 | end |
11375 | def content_location=( val ) |
11376 | header[:content_location] = val |
11377 | end |
11378 | def content_transfer_encoding( val = nil ) |
11379 | default :content_transfer_encoding, val |
11380 | end |
11381 | def content_transfer_encoding=( val ) |
11382 | header[:content_transfer_encoding] = val |
11383 | end |
11384 | def content_type( val = nil ) |
11385 | default :content_type, val |
11386 | end |
11387 | def content_type=( val ) |
11388 | header[:content_type] = val |
11389 | end |
11390 | def date( val = nil ) |
11391 | default :date, val |
11392 | end |
11393 | def date=( val ) |
11394 | header[:date] = val |
11395 | end |
11396 | def transport_encoding( val = nil) |
11397 | if val |
11398 | self.transport_encoding = val |
11399 | else |
11400 | @transport_encoding |
11401 | end |
11402 | end |
11403 | def transport_encoding=( val ) |
11404 | end |
11405 | def from( val = nil ) |
11406 | default :from, val |
11407 | end |
11408 | def from=( val ) |
11409 | header[:from] = val |
11410 | end |
11411 | def in_reply_to( val = nil ) |
11412 | default :in_reply_to, val |
11413 | end |
11414 | def in_reply_to=( val ) |
11415 | header[:in_reply_to] = val |
11416 | end |
11417 | def keywords( val = nil ) |
11418 | default :keywords, val |
11419 | end |
11420 | def keywords=( val ) |
11421 | header[:keywords] = val |
11422 | end |
11423 | def message_id( val = nil ) |
11424 | default :message_id, val |
11425 | end |
11426 | def message_id=( val ) |
11427 | header[:message_id] = val |
11428 | end |
11429 | def mime_version( val = nil ) |
11430 | default :mime_version, val |
11431 | end |
11432 | def mime_version=( val ) |
11433 | header[:mime_version] = val |
11434 | end |
11435 | def received( val = nil ) |
11436 | if val |
11437 | header[:received] = val |
11438 | else |
11439 | header[:received] |
11440 | end |
11441 | end |
11442 | def received=( val ) |
11443 | header[:received] = val |
11444 | end |
11445 | def references( val = nil ) |
11446 | default :references, val |
11447 | end |
11448 | def references=( val ) |
11449 | header[:references] = val |
11450 | end |
11451 | def reply_to( val = nil ) |
11452 | default :reply_to, val |
11453 | end |
11454 | def reply_to=( val ) |
11455 | header[:reply_to] = val |
11456 | end |
11457 | def resent_bcc( val = nil ) |
11458 | default :resent_bcc, val |
11459 | end |
11460 | def resent_bcc=( val ) |
11461 | header[:resent_bcc] = val |
11462 | end |
11463 | def resent_cc( val = nil ) |
11464 | default :resent_cc, val |
11465 | end |
11466 | def resent_cc=( val ) |
11467 | header[:resent_cc] = val |
11468 | end |
11469 | def resent_date( val = nil ) |
11470 | default :resent_date, val |
11471 | end |
11472 | def resent_date=( val ) |
11473 | header[:resent_date] = val |
11474 | end |
11475 | def resent_from( val = nil ) |
11476 | default :resent_from, val |
11477 | end |
11478 | def resent_from=( val ) |
11479 | header[:resent_from] = val |
11480 | end |
11481 | def resent_message_id( val = nil ) |
11482 | default :resent_message_id, val |
11483 | end |
11484 | def resent_message_id=( val ) |
11485 | header[:resent_message_id] = val |
11486 | end |
11487 | def resent_sender( val = nil ) |
11488 | default :resent_sender, val |
11489 | end |
11490 | def resent_sender=( val ) |
11491 | header[:resent_sender] = val |
11492 | end |
11493 | def resent_to( val = nil ) |
11494 | default :resent_to, val |
11495 | end |
11496 | def resent_to=( val ) |
11497 | header[:resent_to] = val |
11498 | end |
11499 | def return_path( val = nil ) |
11500 | default :return_path, val |
11501 | end |
11502 | def return_path=( val ) |
11503 | header[:return_path] = val |
11504 | end |
11505 | def sender( val = nil ) |
11506 | default :sender, val |
11507 | end |
11508 | def sender=( val ) |
11509 | header[:sender] = val |
11510 | end |
11511 | def smtp_envelope_from( val = nil ) |
11512 | if val |
11513 | self.smtp_envelope_from = val |
11514 | else |
11515 | end |
11516 | end |
11517 | def smtp_envelope_from=( val ) |
11518 | @smtp_envelope_from = val |
11519 | end |
11520 | def smtp_envelope_to( val = nil ) |
11521 | if val |
11522 | self.smtp_envelope_to = val |
11523 | else |
11524 | @smtp_envelope_to || destinations |
11525 | end |
11526 | end |
11527 | def smtp_envelope_to=( val ) |
11528 | @smtp_envelope_to = |
11529 | case val |
11530 | when Array, NilClass |
11531 | val |
11532 | else |
11533 | [val] |
11534 | end |
11535 | end |
11536 | def subject( val = nil ) |
11537 | default :subject, val |
11538 | end |
11539 | def subject=( val ) |
11540 | header[:subject] = val |
11541 | end |
11542 | def to( val = nil ) |
11543 | default :to, val |
11544 | end |
11545 | def to=( val ) |
11546 | header[:to] = val |
11547 | end |
11548 | def default( sym, val = nil ) |
11549 | if val |
11550 | header[sym] = val |
11551 | else |
11552 | header[sym].default if header[sym] |
11553 | end |
11554 | end |
11555 | def body=(value) |
11556 | body_lazy(value) |
11557 | end |
11558 | def body(value = nil) |
11559 | if value |
11560 | self.body = value |
11561 | else |
11562 | process_body_raw if @body_raw |
11563 | @body |
11564 | end |
11565 | end |
11566 | def body_encoding(value) |
11567 | if value.nil? |
11568 | body.encoding |
11569 | else |
11570 | body.encoding = value |
11571 | end |
11572 | end |
11573 | def body_encoding=(value) |
11574 | body.encoding = value |
11575 | end |
11576 | def destinations |
11577 | [to_addrs, cc_addrs, bcc_addrs].compact.flatten |
11578 | end |
11579 | def from_addrs |
11580 | from ? [from].flatten : [] |
11581 | end |
11582 | def to_addrs |
11583 | to ? [to].flatten : [] |
11584 | end |
11585 | def cc_addrs |
11586 | cc ? [cc].flatten : [] |
11587 | end |
11588 | def bcc_addrs |
11589 | bcc ? [bcc].flatten : [] |
11590 | end |
11591 | def []=(name, value) |
11592 | if name.to_s == 'body' |
11593 | self.body = value |
11594 | elsif name.to_s =~ /content[-_]type/i |
11595 | header[name] = value |
11596 | elsif name.to_s == 'charset' |
11597 | self.charset = value |
11598 | else |
11599 | header[name] = value |
11600 | end |
11601 | end |
11602 | def [](name) |
11603 | header[underscoreize(name)] |
11604 | end |
11605 | def method_missing(name, *args, &block) |
11606 | field_name = underscoreize(name).chomp("=") |
11607 | if Mail::Field::KNOWN_FIELDS.include?(field_name) |
11608 | if args.empty? |
11609 | header[field_name] |
11610 | else |
11611 | header[field_name] = args.first |
11612 | end |
11613 | else |
11614 | super # otherwise pass it on |
11615 | end |
11616 | end |
11617 | def header_fields |
11618 | header.fields |
11619 | end |
11620 | def has_message_id? |
11621 | header.has_message_id? |
11622 | end |
11623 | def has_date? |
11624 | header.has_date? |
11625 | end |
11626 | def has_mime_version? |
11627 | header.has_mime_version? |
11628 | end |
11629 | def has_content_type? |
11630 | tmp = header[:content_type].main_type rescue nil |
11631 | !!tmp |
11632 | end |
11633 | def has_charset? |
11634 | tmp = header[:content_type].parameters rescue nil |
11635 | !!(has_content_type? && tmp && tmp['charset']) |
11636 | end |
11637 | def has_content_transfer_encoding? |
11638 | end |
11639 | def has_transfer_encoding? # :nodoc: |
11640 | has_content_transfer_encoding? |
11641 | end |
11642 | def add_message_id(msg_id_val = '') |
11643 | header['message-id'] = msg_id_val |
11644 | end |
11645 | def add_date(date_val = '') |
11646 | header['date'] = date_val |
11647 | end |
11648 | def add_mime_version(ver_val = '') |
11649 | header['mime-version'] = ver_val |
11650 | end |
11651 | def add_content_type |
11652 | header[:content_type] = 'text/plain' |
11653 | end |
11654 | def add_charset |
11655 | if !body.empty? |
11656 | STDERR.puts(warning) |
11657 | end |
11658 | end |
11659 | end |
11660 | def add_content_transfer_encoding |
11661 | if body.only_us_ascii? |
11662 | header[:content_transfer_encoding] = '7bit' |
11663 | else |
11664 | STDERR.puts(warning) |
11665 | header[:content_transfer_encoding] = '8bit' |
11666 | end |
11667 | end |
11668 | def add_transfer_encoding # :nodoc: |
11669 | add_content_transfer_encoding |
11670 | end |
11671 | def transfer_encoding # :nodoc: |
11672 | content_transfer_encoding |
11673 | end |
11674 | def mime_type |
11675 | end |
11676 | def message_content_type |
11677 | mime_type |
11678 | end |
11679 | def charset |
11680 | if @header |
11681 | else |
11682 | @charset |
11683 | end |
11684 | end |
11685 | def charset=(value) |
11686 | @defaulted_charset = false |
11687 | @charset = value |
11688 | @header.charset = value |
11689 | end |
11690 | def main_type |
11691 | end |
11692 | def sub_type |
11693 | end |
11694 | def mime_parameters |
11695 | content_type_parameters |
11696 | end |
11697 | def content_type_parameters |
11698 | end |
11699 | def multipart? |
11700 | end |
11701 | def multipart_report? |
11702 | multipart? && sub_type =~ /^report$/i |
11703 | end |
11704 | def delivery_status_report? |
11705 | end |
11706 | def delivery_status_part |
11707 | end |
11708 | def bounced? |
11709 | end |
11710 | def action |
11711 | end |
11712 | def final_recipient |
11713 | end |
11714 | def error_status |
11715 | end |
11716 | def diagnostic_code |
11717 | end |
11718 | def remote_mta |
11719 | end |
11720 | def retryable? |
11721 | end |
11722 | def boundary |
11723 | end |
11724 | def parts |
11725 | body.parts |
11726 | end |
11727 | def attachments |
11728 | parts.attachments |
11729 | end |
11730 | def has_attachments? |
11731 | !attachments.empty? |
11732 | end |
11733 | def html_part(&block) |
11734 | if block_given? |
11735 | else |
11736 | @html_part || find_first_mime_type('text/html') |
11737 | end |
11738 | end |
11739 | def text_part(&block) |
11740 | if block_given? |
11741 | else |
11742 | @text_part || find_first_mime_type('text/plain') |
11743 | end |
11744 | end |
11745 | def html_part=(msg) |
11746 | if msg |
11747 | @html_part = msg |
11748 | add_multipart_alternate_header if text_part |
11749 | add_part @html_part |
11750 | elsif @html_part |
11751 | @html_part = nil |
11752 | if text_part |
11753 | self.content_type = nil |
11754 | body.boundary = nil |
11755 | end |
11756 | end |
11757 | end |
11758 | def text_part=(msg) |
11759 | if msg |
11760 | @text_part = msg |
11761 | add_multipart_alternate_header if html_part |
11762 | add_part @text_part |
11763 | elsif @text_part |
11764 | @text_part = nil |
11765 | if html_part |
11766 | self.content_type = nil |
11767 | body.boundary = nil |
11768 | end |
11769 | end |
11770 | end |
11771 | def add_part(part) |
11772 | if !body.multipart? && !self.body.decoded.blank? |
11773 | @text_part.body = body.decoded |
11774 | self.body @text_part |
11775 | add_multipart_alternate_header |
11776 | end |
11777 | add_boundary |
11778 | self.body part |
11779 | end |
11780 | def part(params = {}) |
11781 | new_part = Part.new(params) |
11782 | yield new_part if block_given? |
11783 | add_part(new_part) |
11784 | end |
11785 | def add_file(values) |
11786 | add_multipart_mixed_header |
11787 | if values.is_a?(String) |
11788 | basename = File.basename(values) |
11789 | filedata = File.open(values, 'rb') { |f| f.read } |
11790 | else |
11791 | basename = values[:filename] |
11792 | end |
11793 | self.attachments[basename] = filedata |
11794 | end |
11795 | def convert_to_multipart |
11796 | text = body.decoded |
11797 | self.body = '' |
11798 | :body = text}) |
11799 | self.body text_part |
11800 | end |
11801 | def ready_to_send! |
11802 | identify_and_set_transfer_encoding |
11803 | parts.each do |part| |
11804 | part.transport_encoding = transport_encoding |
11805 | part.ready_to_send! |
11806 | end |
11807 | add_required_fields |
11808 | end |
11809 | def encode! |
11810 | ready_to_send! |
11811 | end |
11812 | def encoded |
11813 | ready_to_send! |
11814 | buffer = header.encoded |
11815 | buffer "\r " |
11816 | buffer body.encoded(content_transfer_encoding) |
11817 | buffer |
11818 | end |
11819 | def without_attachments! |
11820 | return self unless has_attachments? |
11821 | parts.delete_if { |p| p.attachment? } |
11822 | body_raw = if parts.empty? |
11823 | '' |
11824 | else |
11825 | body.encoded |
11826 | end |
11827 | @body = Mail::Body.new(body_raw) |
11828 | self |
11829 | end |
11830 | def to_yaml(opts = {}) |
11831 | hash = {} |
11832 | hash['headers'] = {} |
11833 | header.fields.each do |field| |
11834 | hash['headers'][field.name] = field.value |
11835 | end |
11836 | if multipart? |
11837 | hash['multipart_body'] = [] |
11838 | end |
11839 | hash[var.to_s] = instance_variable_get(var) |
11840 | end |
11841 | hash.to_yaml(opts) |
11842 | end |
11843 | def self.from_yaml(str) |
11844 | hash = YAML.load(str) |
11845 | m = self.new(:headers = hash['headers']) |
11846 | hash.delete('headers') |
11847 | hash.each do |k,v| |
11848 | case |
11849 | when k == 'delivery_handler' |
11850 | begin |
11851 | rescue NameError |
11852 | end |
11853 | when k == 'transport_encoding' |
11854 | m.transport_encoding(v) |
11855 | when k == 'multipart_body' |
11856 | when k =~ /^@/ |
11857 | m.instance_variable_set(k.to_sym, v) |
11858 | end |
11859 | end |
11860 | m |
11861 | end |
11862 | def self.from_hash(hash) |
11863 | Mail::Message.new(hash) |
11864 | end |
11865 | def to_s |
11866 | encoded |
11867 | end |
11868 | def inspect |
11869 | end |
11870 | def decoded |
11871 | case |
11872 | when self.text? |
11873 | decode_body_as_text |
11874 | when self.attachment? |
11875 | decode_body |
11876 | when !self.multipart? |
11877 | body.decoded |
11878 | else |
11879 | end |
11880 | end |
11881 | def read |
11882 | if self.attachment? |
11883 | decode_body |
11884 | else |
11885 | end |
11886 | end |
11887 | def decode_body |
11888 | body.decoded |
11889 | end |
11890 | def attachment? |
11891 | !!find_attachment |
11892 | end |
11893 | def attachment |
11894 | @attachment |
11895 | end |
11896 | def filename |
11897 | find_attachment |
11898 | end |
11899 | def all_parts |
11900 | parts.map { |p| [p, p.all_parts] }.flatten |
11901 | end |
11902 | def find_first_mime_type(mt) |
11903 | end |
11904 | def skip_deletion |
11905 | @mark_for_delete = false |
11906 | end |
11907 | def mark_for_delete=(value = true) |
11908 | @mark_for_delete = value |
11909 | end |
11910 | def is_marked_for_delete? |
11911 | return @mark_for_delete |
11912 | end |
11913 | def text? |
11914 | end |
11915 | private |
11916 | def parse_message |
11917 | self.header = header_part |
11918 | self.body = body_part |
11919 | end |
11920 | def raw_source=(value) |
11921 | @raw_source = value.to_crlf |
11922 | end |
11923 | def body_lazy(value) |
11924 | process_body_raw if @body_raw && value |
11925 | case |
11926 | when value == nil || value.length=0 |
11927 | @body = Mail::Body.new('') |
11928 | @body_raw = nil |
11929 | add_encoding_to_body |
11930 | when @body && @body.multipart? |
11931 | @body Mail::Part.new(value) |
11932 | add_encoding_to_body |
11933 | else |
11934 | @body_raw = value |
11935 | end |
11936 | end |
11937 | def process_body_raw |
11938 | @body = Mail::Body.new(@body_raw) |
11939 | @body_raw = nil |
11940 | separate_parts if @separate_parts |
11941 | add_encoding_to_body |
11942 | end |
11943 | def set_envelope_header |
11944 | raw_string = raw_source.to_s |
11945 | set_envelope(match_data[1]) |
11946 | end |
11947 | end |
11948 | def separate_parts |
11949 | body.split!(boundary) |
11950 | end |
11951 | def add_encoding_to_body |
11952 | if has_content_transfer_encoding? |
11953 | @body.encoding = content_transfer_encoding |
11954 | end |
11955 | end |
11956 | def identify_and_set_transfer_encoding |
11957 | if body && body.multipart? |
11958 | else |
11959 | end |
11960 | end |
11961 | def add_required_fields |
11962 | add_required_message_fields |
11963 | add_multipart_mixed_header if body.multipart? |
11964 | add_content_type unless has_content_type? |
11965 | add_charset unless has_charset? |
11966 | end |
11967 | def add_required_message_fields |
11968 | add_date unless has_date? |
11969 | add_mime_version unless has_mime_version? |
11970 | add_message_id unless has_message_id? |
11971 | end |
11972 | def add_multipart_alternate_header |
11973 | body.boundary = boundary |
11974 | end |
11975 | def add_boundary |
11976 | unless body.boundary && boundary |
11977 | body.boundary = boundary |
11978 | end |
11979 | end |
11980 | def add_multipart_mixed_header |
11981 | unless header['content-type'] |
11982 | body.boundary = boundary |
11983 | end |
11984 | end |
11985 | def init_with_hash(hash) |
11986 | passed_in_options = IndifferentHash.new(hash) |
11987 | self.raw_source = '' |
11988 | @header = Mail::Header.new |
11989 | @body = Mail::Body.new |
11990 | @body_raw = nil |
11991 | body_content = nil |
11992 | passed_in_options.each_pair do |k,v| |
11993 | k = underscoreize(k).to_sym if k.class == String |
11994 | if k == :headers |
11995 | self.headers(v) |
11996 | elsif k == :body |
11997 | body_content = v |
11998 | else |
11999 | self[k] = v |
12000 | end |
12001 | end |
12002 | if body_content |
12003 | self.body = body_content |
12004 | if has_content_transfer_encoding? |
12005 | body.encoding = content_transfer_encoding |
12006 | end |
12007 | end |
12008 | end |
12009 | def init_with_string(string) |
12010 | self.raw_source = string |
12011 | set_envelope_header |
12012 | parse_message |
12013 | @separate_parts = multipart? |
12014 | end |
12015 | def find_attachment |
12016 | case |
12017 | when content_type && content_type_name |
12018 | filename = content_type_name |
12019 | when content_disposition && content_disp_name |
12020 | filename = content_disp_name |
12021 | when content_location && content_loc_name |
12022 | filename = content_loc_name |
12023 | else |
12024 | filename = nil |
12025 | end |
12026 | filename |
12027 | end |
12028 | def do_delivery |
12029 | begin |
12030 | if perform_deliveries |
12031 | delivery_method.deliver!(self) |
12032 | end |
12033 | raise e if raise_delivery_errors |
12034 | end |
12035 | end |
12036 | def decode_body_as_text |
12037 | body_text = decode_body |
12038 | if charset |
12039 | if RUBY_VERSION '1.9' |
12040 | require 'iconv' |
12041 | else |
12042 | if encoding = Encoding.find(charset) rescue nil |
12043 | body_text.force_encoding(encoding) |
12044 | end |
12045 | end |
12046 | end |
12047 | body_text |
12048 | end |
12049 | end |
12050 | end |
12051 | module Mail #:nodoc: |
12052 | module Multibyte #:nodoc: |
12053 | class Chars |
12054 | attr_reader :wrapped_string |
12055 | alias to_s wrapped_string |
12056 | alias to_str wrapped_string |
12057 | if RUBY_VERSION = "1.9" |
12058 | def initialize(string) |
12059 | @wrapped_string = string |
12060 | end |
12061 | else |
12062 | def initialize(string) #:nodoc: |
12063 | @wrapped_string = string |
12064 | end |
12065 | end |
12066 | def method_missing(method, *args, &block) |
12067 | if method.to_s =~ /!$/ |
12068 | @wrapped_string.__send__(method, *args, &block) |
12069 | self |
12070 | else |
12071 | result.kind_of?(String) ? chars(result) : result |
12072 | end |
12073 | end |
12074 | def respond_to?(method, include_private=false) |
12075 | end |
12076 | def acts_like_string? |
12077 | true |
12078 | end |
12079 | def self.consumes?(string) |
12080 | string.unpack('U*') |
12081 | true |
12082 | rescue ArgumentError |
12083 | false |
12084 | end |
12085 | include Comparable |
12086 | def =(other) |
12087 | @wrapped_string = other.to_s |
12088 | end |
12089 | if RUBY_VERSION "1.9" |
12090 | def self.wants?(string) |
12091 | $KCODE == 'UTF8' && consumes?(string) |
12092 | end |
12093 | def +(other) |
12094 | chars(@wrapped_string + other) |
12095 | end |
12096 | def =~(other) |
12097 | translate_offset(@wrapped_string =~ other) |
12098 | end |
12099 | def insert(offset, fragment) |
12100 | unpacked = Unicode.u_unpack(@wrapped_string) |
12101 | unless offset unpacked.length |
12102 | @wrapped_string.replace( |
12103 | ) |
12104 | else |
12105 | raise IndexError, "index #{offset} out of string" |
12106 | end |
12107 | self |
12108 | end |
12109 | def include?(other) |
12110 | @wrapped_string.include?(other) |
12111 | end |
12112 | def index(needle, offset=0) |
12113 | end |
12114 | def rindex(needle, offset=nil) |
12115 | offset ||= length |
12116 | end |
12117 | def size |
12118 | Unicode.u_unpack(@wrapped_string).size |
12119 | end |
12120 | alias_method :length, :size |
12121 | def rstrip |
12122 | end |
12123 | def lstrip |
12124 | end |
12125 | def strip |
12126 | rstrip.lstrip |
12127 | end |
12128 | def ord |
12129 | Unicode.u_unpack(@wrapped_string)[0] |
12130 | end |
12131 | def rjust(integer, padstr=' ') |
12132 | justify(integer, :right, padstr) |
12133 | end |
12134 | def ljust(integer, padstr=' ') |
12135 | justify(integer, :left, padstr) |
12136 | end |
12137 | def center(integer, padstr=' ') |
12138 | justify(integer, :center, padstr) |
12139 | end |
12140 | else |
12141 | def =~(other) |
12142 | @wrapped_string =~ other |
12143 | end |
12144 | end |
12145 | def split(*args) |
12146 | end |
12147 | def []=(*args) |
12148 | replace_by = args.pop |
12149 | if args.first.is_a?(Regexp) |
12150 | @wrapped_string[*args] = replace_by |
12151 | else |
12152 | result = Unicode.u_unpack(@wrapped_string) |
12153 | if args[0].is_a?(Fixnum) |
12154 | min = args[0] |
12155 | max = args[1].nil? ? min : (min + args[1] - 1) |
12156 | range = Range.new(min, max) |
12157 | elsif args.first.is_a?(Range) |
12158 | range = args[0] |
12159 | else |
12160 | needle = args[0].to_s |
12161 | min = index(needle) |
12162 | max = min + Unicode.u_unpack(needle).length - 1 |
12163 | range = Range.new(min, max) |
12164 | end |
12165 | result[range] = Unicode.u_unpack(replace_by) |
12166 | @wrapped_string.replace(result.pack('U*')) |
12167 | end |
12168 | end |
12169 | def reverse |
12170 | end |
12171 | def slice(*args) |
12172 | if args.size 2 |
12173 | elsif (args.size == 2 && !args[1].is_a?(Numeric)) |
12174 | elsif args[0].kind_of? Range |
12175 | result = cps.nil? ? nil : cps.pack('U*') |
12176 | elsif args[0].kind_of? Regexp |
12177 | result = @wrapped_string.slice(*args) |
12178 | elsif args.size == 1 && args[0].kind_of?(Numeric) |
12179 | result = character && [character].pack('U') |
12180 | else |
12181 | result = cps && cps.pack('U*') |
12182 | end |
12183 | result && chars(result) |
12184 | end |
12185 | alias_method :[], :slice |
12186 | def limit(limit) |
12187 | slice(0...translate_offset(limit)) |
12188 | end |
12189 | def upcase |
12190 | end |
12191 | def downcase |
12192 | end |
12193 | def capitalize |
12194 | end |
12195 | def titleize |
12196 | end |
12197 | alias_method :titlecase, :titleize |
12198 | def normalize(form = nil) |
12199 | chars(Unicode.normalize(@wrapped_string, form)) |
12200 | end |
12201 | def decompose |
12202 | end |
12203 | def compose |
12204 | end |
12205 | def g_length |
12206 | Unicode.g_unpack(@wrapped_string).length |
12207 | end |
12208 | def tidy_bytes(force = false) |
12209 | chars(Unicode.tidy_bytes(@wrapped_string, force)) |
12210 | end |
12211 | if public_method_defined?(method) |
12212 | define_method("#{method}!") do |*args| |
12213 | self |
12214 | end |
12215 | end |
12216 | end |
12217 | protected |
12218 | def translate_offset(byte_offset) #:nodoc: |
12219 | return nil if byte_offset.nil? |
12220 | return 0 if @wrapped_string == '' |
12221 | if @wrapped_string.respond_to?(:force_encoding) |
12222 | end |
12223 | begin |
12224 | rescue ArgumentError |
12225 | byte_offset -= 1 |
12226 | retry |
12227 | end |
12228 | end |
12229 | def justify(integer, way, padstr=' ') #:nodoc: |
12230 | padsize = integer - size |
12231 | padsize = padsize 0 ? padsize : 0 |
12232 | case way |
12233 | when :right |
12234 | when :left |
12235 | when :center |
12236 | lpad = padding((padsize / 2.0).floor, padstr) |
12237 | rpad = padding((padsize / 2.0).ceil, padstr) |
12238 | end |
12239 | chars(result) |
12240 | end |
12241 | def padding(padsize, padstr=' ') #:nodoc: |
12242 | if padsize != 0 |
12243 | else |
12244 | '' |
12245 | end |
12246 | end |
12247 | def chars(string) #:nodoc: |
12248 | self.class.new(string) |
12249 | end |
12250 | end |
12251 | end |
12252 | end |
12253 | module Mail #:nodoc: |
12254 | module Multibyte #:nodoc: |
12255 | class EncodingError StandardError; end |
12256 | end |
12257 | endmodule Mail |
12258 | module Multibyte |
12259 | module Unicode |
12260 | extend self |
12261 | NORMALIZATION_FORMS = [:c, :kc, :d, :kd] |
12262 | UNICODE_VERSION = '5.2.0' |
12263 | attr_accessor :default_normalization_form |
12264 | @default_normalization_form = :kc |
12265 | HANGUL_SBASE = 0xAC00 |
12266 | HANGUL_LBASE = 0x1100 |
12267 | HANGUL_VBASE = 0x1161 |
12268 | HANGUL_TBASE = 0x11A7 |
12269 | HANGUL_LCOUNT = 19 |
12270 | HANGUL_VCOUNT = 21 |
12271 | HANGUL_TCOUNT = 28 |
12272 | HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT |
12273 | HANGUL_SCOUNT = 11172 |
12274 | HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT |
12275 | HANGUL_JAMO_FIRST = 0x1100 |
12276 | HANGUL_JAMO_LAST = 0x11FF |
12277 | WHITESPACE = [ |
12278 | 0x0020, # White_Space # Zs SPACE |
12279 | 0x0085, # White_Space # Cc control-0085 |
12280 | 0x00A0, # White_Space # Zs NO-BREAK SPACE |
12281 | 0x1680, # White_Space # Zs OGHAM SPACE MARK |
12282 | 0x2028, # White_Space # Zl LINE SEPARATOR |
12283 | 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR |
12284 | 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE |
12285 | 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE |
12286 | ].flatten.freeze |
12287 | end |
12288 | def u_unpack(string) |
12289 | begin |
12290 | string.unpack 'U*' |
12291 | rescue ArgumentError |
12292 | raise EncodingError, 'malformed UTF-8 character' |
12293 | end |
12294 | end |
12295 | def in_char_class?(codepoint, classes) |
12296 | end |
12297 | def g_unpack(string) |
12298 | codepoints = u_unpack(string) |
12299 | unpacked = [] |
12300 | pos = 0 |
12301 | marker = 0 |
12302 | eoc = codepoints.length |
12303 | while(pos eoc) |
12304 | pos += 1 |
12305 | previous = codepoints[pos-1] |
12306 | current = codepoints[pos] |
12307 | if ( |
12308 | (database.boundary[:extend] === current) |
12309 | ) |
12310 | else |
12311 | unpacked codepoints[marker..pos-1] |
12312 | marker = pos |
12313 | end |
12314 | end |
12315 | unpacked |
12316 | end |
12317 | def g_pack(unpacked) |
12318 | (unpacked.flatten).pack('U*') |
12319 | end |
12320 | def reorder_characters(codepoints) |
12321 | length = codepoints.length- 1 |
12322 | pos = 0 |
12323 | while pos length do |
12324 | codepoints[pos..pos+1] = cp2.code, cp1.code |
12325 | pos += (pos 0 ? -1 : 1) |
12326 | else |
12327 | pos += 1 |
12328 | end |
12329 | end |
12330 | codepoints |
12331 | end |
12332 | def decompose_codepoints(type, codepoints) |
12333 | codepoints.inject([]) do |decomposed, cp| |
12334 | if HANGUL_SBASE = cp and cp HANGUL_SLAST |
12335 | sindex = cp - HANGUL_SBASE |
12336 | ncp = [] # new codepoints |
12337 | ncp HANGUL_LBASE + sindex / HANGUL_NCOUNT |
12338 | tindex = sindex % HANGUL_TCOUNT |
12339 | ncp (HANGUL_TBASE + tindex) unless tindex == 0 |
12340 | decomposed.concat ncp |
12341 | else |
12342 | decomposed cp |
12343 | end |
12344 | end |
12345 | end |
12346 | def compose_codepoints(codepoints) |
12347 | pos = 0 |
12348 | eoa = codepoints.length - 1 |
12349 | starter_pos = 0 |
12350 | starter_char = codepoints[0] |
12351 | previous_combining_class = -1 |
12352 | while pos eoa |
12353 | pos += 1 |
12354 | lindex = starter_char - HANGUL_LBASE |
12355 | if 0 = lindex and lindex HANGUL_LCOUNT |
12356 | if 0 = vindex and vindex HANGUL_VCOUNT |
12357 | if 0 = tindex and tindex HANGUL_TCOUNT |
12358 | j = starter_pos + 2 |
12359 | eoa -= 2 |
12360 | else |
12361 | tindex = 0 |
12362 | j = starter_pos + 1 |
12363 | eoa -= 1 |
12364 | end |
Комментарии