aboutsummaryrefslogtreecommitdiffstats
path: root/documentation/sqlcontainer/chapter-sqlcontainer.asciidoc
blob: 9b5ff51573c82416ab0c13d30772c4fdd5440f78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[[sqlcontainer]]
== Vaadin SQLContainer

Vaadin SQLContainer is a container implementation that allows easy and
customizable access to data stored in various SQL-speaking databases.

SQLContainer supports two types of database access. Using
[classname]#TableQuery#, the pre-made query generators will enable fetching,
updating, and inserting data directly from the container into a database table -
automatically, whereas [classname]#FreeformQuery# allows the developer to use
their own, probably more complex query for fetching data and their own optional
implementations for writing, filtering and sorting support - item and property
handling as well as lazy loading will still be handled automatically.

In addition to the customizable database connection options, SQLContainer also
extends the Vaadin [classname]#Container# interface to implement more advanced
and more database-oriented filtering rules. Finally, the add-on also offers
connection pool implementations for JDBC connection pooling and JEE connection
pooling, as well as integrated transaction support; auto-commit mode is also
provided.

The purpose of this section is to briefly explain the architecture and some of
the inner workings of SQLContainer. It will also give the readers some examples
on how to use SQLContainer in their own applications. The requirements,
limitations and further development ideas are also discussed.

SQLContainer is available from the Vaadin Directory under the same unrestrictive
Apache License 2.0 as the Vaadin Framework itself.


include::sqlcontainer-architecture.asciidoc[leveloffset=+2]

include::sqlcontainer-getting-started.asciidoc[leveloffset=+2]

include::sqlcontainer-filteringsorting.asciidoc[leveloffset=+2]

include::sqlcontainer-editing.asciidoc[leveloffset=+2]

include::sqlcontainer-caching.asciidoc[leveloffset=+2]

include::sqlcontainer-referencing.asciidoc[leveloffset=+2]

include::sqlcontainer-freeform.asciidoc[leveloffset=+2]

include::sqlcontainer-nonimplemented.asciidoc[leveloffset=+2]

include::sqlcontainer-limitations.asciidoc[leveloffset=+2]
pan>:class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify acts_as_customizable acts_as_attachable :view_permission => :view_files, :delete_permission => :manage_files VERSION_STATUSES = %w(open locked closed) VERSION_SHARINGS = %w(none descendants hierarchy tree system) validates_presence_of :name validates_uniqueness_of :name, :scope => [:project_id] validates_length_of :name, :maximum => 60 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true validates_inclusion_of :status, :in => VERSION_STATUSES validates_inclusion_of :sharing, :in => VERSION_SHARINGS named_scope :open, :conditions => {:status => 'open'} named_scope :visible, lambda {|*args| { :include => :project, :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } } # Returns true if +user+ or current user is allowed to view the version def visible?(user=User.current) user.allowed_to?(:view_issues, self.project) end def start_date effective_date end def due_date effective_date end # Returns the total estimated time for this version # (sum of leaves estimated_hours) def estimated_hours @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f end # Returns the total reported time for this version def spent_hours @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f end def closed? status == 'closed' end def open? status == 'open' end # Returns true if the version is completed: due date reached and no open issues def completed? effective_date && (effective_date <= Date.today) && (open_issues_count == 0) end # Returns the completion percentage of this version based on the amount of open/closed issues # and the time spent on the open issues. def completed_pourcent if issues_count == 0 0 elsif open_issues_count == 0 100 else issues_progress(false) + issues_progress(true) end end # Returns the percentage of issues that have been marked as 'closed'. def closed_pourcent if issues_count == 0 0 else issues_progress(false) end end # Returns true if the version is overdue: due date reached and some open issues def overdue? effective_date && (effective_date < Date.today) && (open_issues_count > 0) end # Returns assigned issues count def issues_count @issue_count ||= fixed_issues.count end # Returns the total amount of open issues for this version. def open_issues_count @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) end # Returns the total amount of closed issues for this version. def closed_issues_count @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) end def wiki_page if project.wiki && !wiki_page_title.blank? @wiki_page ||= project.wiki.find_page(wiki_page_title) end @wiki_page end def to_s; name end # Versions are sorted by effective_date and "Project Name - Version name" # Those with no effective_date are at the end, sorted by "Project Name - Version name" def <=>(version) if self.effective_date if version.effective_date if self.effective_date == version.effective_date "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" else self.effective_date <=> version.effective_date end else -1 end else if version.effective_date 1 else "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" end end end # Returns the sharings that +user+ can set the version to def allowed_sharings(user = User.current) VERSION_SHARINGS.select do |s| if sharing == s true else case s when 'system' # Only admin users can set a systemwide sharing user.admin? when 'hierarchy', 'tree' # Only users allowed to manage versions of the root project can # set sharing to hierarchy or tree project.nil? || user.allowed_to?(:manage_versions, project.root) else true end end end end private # Update the issue's fixed versions. Used if a version's sharing changes. def update_issues_from_sharing_change if sharing_changed? if VERSION_SHARINGS.index(sharing_was).nil? || VERSION_SHARINGS.index(sharing).nil? || VERSION_SHARINGS.index(sharing_was) > VERSION_SHARINGS.index(sharing) Issue.update_versions_from_sharing_change self end end end # Returns the average estimated time of assigned issues # or 1 if no issue has an estimated time # Used to weigth unestimated issues in progress calculation def estimated_average if @estimated_average.nil? average = fixed_issues.average(:estimated_hours).to_f if average == 0 average = 1 end @estimated_average = average end @estimated_average end # Returns the total progress of open or closed issues. The returned percentage takes into account # the amount of estimated time set for this version. # # Examples: # issues_progress(true) => returns the progress percentage for open issues. # issues_progress(false) => returns the progress percentage for closed issues. def issues_progress(open) @issues_progress ||= {} @issues_progress[open] ||= begin progress = 0 if issues_count > 0 ratio = open ? 'done_ratio' : 100 done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", :include => :status, :conditions => ["is_closed = ?", !open]).to_f progress = done / (estimated_average * issues_count) end progress end end end