nitro 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{ChangeLog → CHANGELOG} +137 -0
- data/INSTALL +1 -2
- data/README +1 -1
- data/Rakefile +10 -61
- data/benchmark/{nitro/bench.rb → bench.rb} +1 -1
- data/benchmark/{nitro/simple-webrick-n-200.txt → simple-webrick-n-200.txt} +0 -0
- data/benchmark/{nitro/static-webrick-n-200.txt → static-webrick-n-200.txt} +0 -0
- data/benchmark/{nitro/tiny-lhttpd-n-200-c-5.txt → tiny-lhttpd-n-200-c-5.txt} +0 -0
- data/benchmark/{nitro/tiny-webrick-n-200-c-5.txt → tiny-webrick-n-200-c-5.txt} +0 -0
- data/benchmark/{nitro/tiny-webrick-n-200.txt → tiny-webrick-n-200.txt} +0 -0
- data/benchmark/{nitro/tiny2-webrick-n-200.txt → tiny2-webrick-n-200.txt} +0 -0
- data/doc/{ChangeLog.1 → CHANGELOG.1} +0 -0
- data/{RELEASES → doc/RELEASES} +46 -0
- data/doc/faq.txt +7 -0
- data/examples/README.windows +1 -1
- data/examples/ajax/controller.rb +21 -0
- data/examples/ajax/public/index.xhtml +70 -0
- data/examples/ajax/public/js/ajax.js +64 -0
- data/examples/ajax/run.rb +16 -0
- data/examples/blog/README +6 -3
- data/examples/blog/conf/apache.conf +2 -2
- data/examples/blog/conf/lhttpd.conf +2 -2
- data/examples/blog/log/apache.error_log +777 -0
- data/examples/blog/{root → public}/base.xsl +0 -0
- data/examples/blog/{root → public}/fcgi.rb +0 -0
- data/examples/blog/{root → public}/m/bubbles.gif +0 -0
- data/examples/blog/{root → public}/m/comments_curve.gif +0 -0
- data/examples/blog/{root → public}/m/down.gif +0 -0
- data/examples/blog/{root → public}/m/footer_bg.gif +0 -0
- data/examples/blog/{root → public}/m/garrow.gif +0 -0
- data/examples/blog/{root → public}/m/gbull.gif +0 -0
- data/examples/blog/{root → public}/m/grbull.gif +0 -0
- data/examples/blog/{root → public}/m/h1_bg.gif +0 -0
- data/examples/blog/{root → public}/m/header_bg.gif +0 -0
- data/examples/blog/{root → public}/m/nitro.gif +0 -0
- data/examples/blog/{root → public}/m/obull.gif +0 -0
- data/examples/blog/{root → public}/m/page_bg.gif +0 -0
- data/examples/blog/{root → public}/m/rss.gif +0 -0
- data/examples/blog/{root → public}/m/side_title_bg.gif +0 -0
- data/examples/blog/{root → public}/m/sidebar_bg.gif +0 -0
- data/examples/{no_xsl_blog/root → blog/public}/style.css +6 -0
- data/examples/blog/run.rb +10 -12
- data/examples/blog/{lib → src}/blog.rb +3 -3
- data/examples/blog/{lib/blog → src}/controller.rb +13 -2
- data/examples/blog/src/mailer.rb +23 -0
- data/examples/blog/{lib/blog/model.rb → src/models/blog.rb} +4 -7
- data/examples/blog/src/models/content.rb +52 -0
- data/examples/blog/src/views/blog_entry_email.xhtml +16 -0
- data/examples/blog/{root → src/views}/comments.xhtml +0 -0
- data/examples/blog/{root → src/views}/entry_form.xhtml +0 -0
- data/examples/blog/{root → src/views}/error.xhtml +0 -0
- data/examples/blog/{root → src/views}/index.xhtml +0 -0
- data/examples/blog/{root → src/views}/login.xhtml +0 -0
- data/examples/blog/{root → src/views}/recent_posts.xhtml +0 -0
- data/examples/blog/{root → src/views}/view_entry.xhtml +8 -0
- data/examples/blog/{root → src/views}/view_entry.xml +0 -0
- data/examples/blog/src/xsl/base.xsl +153 -0
- data/examples/blog/{root → src/xsl}/style.xsl +2 -2
- data/examples/no_xsl_blog/README +5 -1
- data/examples/no_xsl_blog/conf/apache.conf +2 -2
- data/examples/no_xsl_blog/conf/lhttpd.conf +2 -2
- data/examples/no_xsl_blog/lib/blog/model.rb +1 -1
- data/{lib/parts → examples/no_xsl_blog/lib}/content.rb +1 -11
- data/examples/no_xsl_blog/log/apache.error_log +405 -0
- data/examples/no_xsl_blog/{root → public}/comments.xhtml +0 -0
- data/examples/no_xsl_blog/{root → public}/entry_form.xhtml +0 -0
- data/examples/no_xsl_blog/{root → public}/fcgi.rb +0 -0
- data/examples/no_xsl_blog/{root → public}/index.xhtml +0 -0
- data/examples/no_xsl_blog/{root → public}/login.xhtml +0 -0
- data/examples/no_xsl_blog/{root → public}/m/bubbles.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/comments_curve.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/down.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/footer_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/garrow.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/gbull.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/grbull.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/h1_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/header_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/nitro.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/obull.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/page_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/rss.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/side_title_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/m/sidebar_bg.gif +0 -0
- data/examples/no_xsl_blog/{root → public}/recent_posts.xhtml +0 -0
- data/examples/{blog/root → no_xsl_blog/public}/style.css +0 -0
- data/examples/no_xsl_blog/{root → public}/view_entry.xhtml +0 -0
- data/examples/no_xsl_blog/{root → public}/view_entry.xml +0 -0
- data/examples/tiny/conf/apache.conf +2 -2
- data/examples/tiny/log/apache.error_log +100 -0
- data/examples/tiny/{root → public}/fcgi.rb +0 -0
- data/examples/tiny/{root → public}/include.xhtml +0 -0
- data/examples/tiny/{root → public}/index.xhtml +0 -0
- data/{bin/proto/root/m → examples/tiny/public}/nitro.png +0 -0
- data/examples/tiny/{root → public}/upload.xhtml +0 -0
- data/examples/tiny/run.rb +1 -2
- data/examples/why_wiki/wiki.yml +1 -0
- data/install.rb +5 -2
- data/lib/nitro.rb +2 -6
- data/lib/nitro/adapters/fastcgi.rb +2 -2
- data/lib/nitro/adapters/webrick.rb +4 -4
- data/lib/nitro/conf.rb +5 -2
- data/lib/nitro/controller.rb +2 -2
- data/lib/nitro/dispatcher.rb +19 -8
- data/lib/nitro/mail.rb +252 -8
- data/lib/nitro/render.rb +24 -21
- data/lib/nitro/runner.rb +1 -1
- data/lib/nitro/scaffold.rb +2 -5
- data/lib/nitro/simple.rb +2 -1
- data/lib/nitro/template.rb +42 -2
- data/test/nitro/tc_controller.rb +9 -4
- data/test/nitro/tc_dispatcher.rb +4 -6
- data/test/nitro/tc_mail.rb +95 -0
- data/test/{root → public}/blog/list.xhtml +0 -0
- data/test/public/dummy_mailer/registration.xhtml +5 -0
- data/vendor/README +0 -1
- metadata +136 -181
- data/benchmark/og/bench.rb +0 -75
- data/benchmark/og/sqlite-no-prepare.1.txt +0 -13
- data/benchmark/og/sqlite-no-prepare.2.txt +0 -13
- data/benchmark/og/sqlite-prepare.1.txt +0 -13
- data/benchmark/og/sqlite-prepare.2.txt +0 -13
- data/bin/proto/README +0 -34
- data/bin/proto/conf/apache.conf +0 -1
- data/bin/proto/conf/app.conf.rb +0 -14
- data/bin/proto/conf/lhttpd.conf +0 -236
- data/bin/proto/ctl +0 -4
- data/bin/proto/lib/README +0 -5
- data/bin/proto/log/README +0 -3
- data/bin/proto/root/fcgi.rb +0 -6
- data/bin/proto/root/index.xhtml +0 -69
- data/bin/proto/root/style.css +0 -152
- data/bin/proto/root/style.xsl +0 -99
- data/doc/og_config.txt +0 -35
- data/doc/og_tutorial.txt +0 -595
- data/examples/og/README +0 -11
- data/examples/og/mock_example.rb +0 -50
- data/examples/og/mysql_to_psql.rb +0 -96
- data/examples/og/run.rb +0 -286
- data/examples/tiny/root/nitro.png +0 -0
- data/lib/glue.rb +0 -55
- data/lib/glue/array.rb +0 -61
- data/lib/glue/attribute.rb +0 -83
- data/lib/glue/cache.rb +0 -138
- data/lib/glue/flexob.rb +0 -12
- data/lib/glue/hash.rb +0 -122
- data/lib/glue/inflector.rb +0 -91
- data/lib/glue/logger.rb +0 -147
- data/lib/glue/misc.rb +0 -14
- data/lib/glue/mixins.rb +0 -36
- data/lib/glue/number.rb +0 -24
- data/lib/glue/object.rb +0 -32
- data/lib/glue/pool.rb +0 -60
- data/lib/glue/property.rb +0 -408
- data/lib/glue/string.rb +0 -162
- data/lib/glue/time.rb +0 -85
- data/lib/glue/validation.rb +0 -394
- data/lib/og.rb +0 -185
- data/lib/og/adapter.rb +0 -513
- data/lib/og/adapters/filesys.rb +0 -121
- data/lib/og/adapters/mysql.rb +0 -347
- data/lib/og/adapters/oracle.rb +0 -375
- data/lib/og/adapters/psql.rb +0 -273
- data/lib/og/adapters/sqlite.rb +0 -262
- data/lib/og/backend.rb +0 -297
- data/lib/og/connection.rb +0 -304
- data/lib/og/database.rb +0 -282
- data/lib/og/enchant.rb +0 -125
- data/lib/og/meta.rb +0 -373
- data/lib/og/mock.rb +0 -165
- data/lib/og/observer.rb +0 -53
- data/lib/og/typemacros.rb +0 -23
- data/lib/parts/README +0 -9
- data/test/glue/tc_attribute.rb +0 -22
- data/test/glue/tc_cache.rb +0 -45
- data/test/glue/tc_hash.rb +0 -38
- data/test/glue/tc_logger.rb +0 -39
- data/test/glue/tc_numbers.rb +0 -20
- data/test/glue/tc_property.rb +0 -89
- data/test/glue/tc_property_mixins.rb +0 -93
- data/test/glue/tc_property_type_checking.rb +0 -35
- data/test/glue/tc_strings.rb +0 -103
- data/test/glue/tc_validation.rb +0 -188
- data/test/og/tc_filesys.rb +0 -83
- data/test/og/tc_lifecycle.rb +0 -104
- data/test/og/tc_many_to_many.rb +0 -62
- data/test/og/tc_meta.rb +0 -55
- data/test/og/tc_observer.rb +0 -85
- data/test/og/tc_sqlite.rb +0 -87
- data/test/tc_og.rb +0 -355
- data/vendor/composite_sexp_processor.rb +0 -43
- data/vendor/parse_tree.rb +0 -745
- data/vendor/sexp_processor.rb +0 -453
data/lib/og.rb
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
|
3
|
-
# $Id: og.rb 270 2005-03-07 17:52:16Z gmosx $
|
|
4
|
-
|
|
5
|
-
require 'glue'
|
|
6
|
-
require 'glue/logger'
|
|
7
|
-
require 'glue/attribute'
|
|
8
|
-
require 'glue/property'
|
|
9
|
-
require 'glue/array'
|
|
10
|
-
require 'glue/hash'
|
|
11
|
-
require 'glue/time'
|
|
12
|
-
require 'glue/pool'
|
|
13
|
-
require 'glue/validation'
|
|
14
|
-
|
|
15
|
-
# Og (ObjectGraph) is an efficient, yet simple Object-Relational
|
|
16
|
-
# mapping library.
|
|
17
|
-
#
|
|
18
|
-
# === Features
|
|
19
|
-
#
|
|
20
|
-
# The library provides the following features:
|
|
21
|
-
#
|
|
22
|
-
# + Object-Relational mapping.
|
|
23
|
-
# + Absolutely no configuration files.
|
|
24
|
-
# + Multiple backends (PostgreSQL, MySQL, SQLite).
|
|
25
|
-
# + ActiveRecord-style meta language and db aware methods.
|
|
26
|
-
# + Deserialize to Ruby Objects.
|
|
27
|
-
# + Deserialize sql join queries to Ruby Objects (temporarily dissabled).
|
|
28
|
-
# + Serialize arbitrary ruby object graphs through YAML.
|
|
29
|
-
# + Connection pooling.
|
|
30
|
-
# + Thread safety.
|
|
31
|
-
# + SQL transactions.
|
|
32
|
-
# + Lifecycle callbacks.
|
|
33
|
-
# + Lifecycle observers.
|
|
34
|
-
# + Transparent support for cascading deletes for all backends.
|
|
35
|
-
# + Hierarchical structures (preorder traversal, materialized paths)
|
|
36
|
-
# + Works safely as part of distributed application.
|
|
37
|
-
# + Simple implementation.
|
|
38
|
-
#
|
|
39
|
-
# === Meta language
|
|
40
|
-
#
|
|
41
|
-
# primary_key :pid (NOT IMPLEMENTED)
|
|
42
|
-
# name_key :name (NOT IMPLEMENTED)
|
|
43
|
-
# prop_accessor Fixnum, :pid, :sql => "smallint DEFAULT 1"
|
|
44
|
-
# has_many Child, :children
|
|
45
|
-
# many_to_many Role, :roles
|
|
46
|
-
# sql_index :pid
|
|
47
|
-
#
|
|
48
|
-
# === Property Metadata
|
|
49
|
-
#
|
|
50
|
-
# Og defines, reserves and uses the following property
|
|
51
|
-
# metadata types:
|
|
52
|
-
#
|
|
53
|
-
# [+:sql_index+]
|
|
54
|
-
# Create an sql index for this property.
|
|
55
|
-
#
|
|
56
|
-
# [+:unique+]
|
|
57
|
-
# This value of the property must be unique.
|
|
58
|
-
#
|
|
59
|
-
# [+:name_key+]
|
|
60
|
-
# This property is used as name-key.
|
|
61
|
-
#
|
|
62
|
-
# === Design
|
|
63
|
-
#
|
|
64
|
-
# Keep the main classes backend agnostic.
|
|
65
|
-
#
|
|
66
|
-
# For class ids we use the name instead of a hash. Class ids are
|
|
67
|
-
# typically not used in querys, they are stored for completeness.
|
|
68
|
-
# If we store a hash we cannot reclaim the class thus invalidating
|
|
69
|
-
# the point. Instead of .name(), to_s() is used so the methods
|
|
70
|
-
# are more flexible (they accept class names too!!)
|
|
71
|
-
#
|
|
72
|
-
# Og allows the serialization of arbitrary Ruby objects. Just
|
|
73
|
-
# mark them as Object (or Array or Hash) in the prop_accessor
|
|
74
|
-
# and the engine will serialize a YAML dump of the object.
|
|
75
|
-
# Arbitrary object graphs are supported too.
|
|
76
|
-
#
|
|
77
|
-
# This is NOT a singleton, an application may access multiple
|
|
78
|
-
# databases.
|
|
79
|
-
#
|
|
80
|
-
# The og.xxx methods are more flexible and allow you to use
|
|
81
|
-
# multiple databases for example.
|
|
82
|
-
#
|
|
83
|
-
# === Managed Objects Lifecycle Callbacks
|
|
84
|
-
#
|
|
85
|
-
# * og_pre_read
|
|
86
|
-
# * og_post_read
|
|
87
|
-
# * og_pre_insert
|
|
88
|
-
# * og_post_insert
|
|
89
|
-
# * og_pre_update
|
|
90
|
-
# * og_post_update
|
|
91
|
-
# * og_pre_insert_update
|
|
92
|
-
# * og_post_insert_update
|
|
93
|
-
# * self.og_pre_delete
|
|
94
|
-
#
|
|
95
|
-
# A class level callback is used for delete because typically you call
|
|
96
|
-
# delete with an oid and not an object to avoid a deserialization.
|
|
97
|
-
#
|
|
98
|
-
# === Future
|
|
99
|
-
#
|
|
100
|
-
# * Support prepared statements (pgsql)
|
|
101
|
-
# * Support stored procedures (pgsql)
|
|
102
|
-
# * Support caching.
|
|
103
|
-
# * Deserialize to OpenStruct.
|
|
104
|
-
# * Better documentation.
|
|
105
|
-
|
|
106
|
-
module Og
|
|
107
|
-
|
|
108
|
-
# The name.
|
|
109
|
-
|
|
110
|
-
Name = 'ObjectGraph'
|
|
111
|
-
|
|
112
|
-
# The version.
|
|
113
|
-
|
|
114
|
-
Version = '0.12.0'
|
|
115
|
-
|
|
116
|
-
# Library path.
|
|
117
|
-
|
|
118
|
-
LibPath = File.dirname(__FILE__)
|
|
119
|
-
|
|
120
|
-
# If true, only allow reading from the database. Usefull
|
|
121
|
-
# for maintainance.
|
|
122
|
-
|
|
123
|
-
mattr_accessor :read_only_mode, false
|
|
124
|
-
|
|
125
|
-
# If true, the library automatically 'enchants' managed classes.
|
|
126
|
-
# In enchant mode, special db aware methods are added to
|
|
127
|
-
# managed classes and instances.
|
|
128
|
-
# If false, Og enchants only classes that define properties.
|
|
129
|
-
|
|
130
|
-
mattr_accessor :enchant_managed_classes, true
|
|
131
|
-
|
|
132
|
-
# If true, use Ruby's advanced introspection capabilities to
|
|
133
|
-
# automatically manage classes tha define properties.
|
|
134
|
-
|
|
135
|
-
mattr_accessor :auto_manage_classes, true
|
|
136
|
-
|
|
137
|
-
# If true, automatically include the Og meta-language into Module.
|
|
138
|
-
# If false, the polution of the Module object is avoided. However
|
|
139
|
-
# if you include a prop_accessor or a managed Mixin in your
|
|
140
|
-
# object MetaLanguage gets automatically extended in the class.
|
|
141
|
-
|
|
142
|
-
mattr_accessor :include_meta_language, true
|
|
143
|
-
|
|
144
|
-
# Attach the following prefix to all generated SQL table names.
|
|
145
|
-
# Usefull on hosting scenarios where you have to run multiple
|
|
146
|
-
# web applications/sites on a single database.
|
|
147
|
-
|
|
148
|
-
mattr_accessor :table_prefix, nil
|
|
149
|
-
|
|
150
|
-
# If true, Og tries to create/update the schema in the
|
|
151
|
-
# data store. For production/live environments set this to false
|
|
152
|
-
# and only set to true when the object model is upadated.
|
|
153
|
-
# For debug/development environments this should stay true
|
|
154
|
-
# for convienience.
|
|
155
|
-
|
|
156
|
-
mattr_accessor :create_schema, true
|
|
157
|
-
|
|
158
|
-
# The active database. Og allows you to access multiple
|
|
159
|
-
# databases from a single application.
|
|
160
|
-
|
|
161
|
-
mattr_accessor :db
|
|
162
|
-
|
|
163
|
-
# Set the active database.
|
|
164
|
-
|
|
165
|
-
def self.use(db)
|
|
166
|
-
@@db = db
|
|
167
|
-
@@db.get_connection
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# The adapter of the active database.
|
|
171
|
-
|
|
172
|
-
def self.adapter
|
|
173
|
-
@@db.adapter
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# Marker module. If included this in a class, the Og automanager
|
|
177
|
-
# ignores this class.
|
|
178
|
-
|
|
179
|
-
module Unmanageable; end
|
|
180
|
-
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
# gmosx: leave this here.
|
|
184
|
-
|
|
185
|
-
require 'og/database'
|
data/lib/og/adapter.rb
DELETED
|
@@ -1,513 +0,0 @@
|
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
|
3
|
-
# $Id: adapter.rb 270 2005-03-07 17:52:16Z gmosx $
|
|
4
|
-
|
|
5
|
-
require 'yaml'
|
|
6
|
-
require 'singleton'
|
|
7
|
-
|
|
8
|
-
require 'og/connection'
|
|
9
|
-
|
|
10
|
-
module Og
|
|
11
|
-
|
|
12
|
-
# An adapter communicates with the backend datastore.
|
|
13
|
-
# The adapters for all supported datastores extend this
|
|
14
|
-
# class. Typically, an RDBMS is used to implement a
|
|
15
|
-
# datastore.
|
|
16
|
-
|
|
17
|
-
class Adapter
|
|
18
|
-
include Singleton
|
|
19
|
-
|
|
20
|
-
# A mapping between Ruby and backend Datastore types.
|
|
21
|
-
|
|
22
|
-
attr_accessor :typemap
|
|
23
|
-
|
|
24
|
-
# A map for casting Ruby types to SQL safe textual
|
|
25
|
-
# representations.
|
|
26
|
-
|
|
27
|
-
attr_accessor :typecast
|
|
28
|
-
|
|
29
|
-
# Lookup the adapter instance from the adapter name.
|
|
30
|
-
|
|
31
|
-
def self.for_name(name)
|
|
32
|
-
require "og/adapters/#{name}"
|
|
33
|
-
eval %{ return #{name.capitalize}Adapter.instance }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def initialize
|
|
37
|
-
# The default mappings, should be valid for most
|
|
38
|
-
# RDBMS.
|
|
39
|
-
|
|
40
|
-
@typemap = {
|
|
41
|
-
Integer => 'integer',
|
|
42
|
-
Fixnum => 'integer',
|
|
43
|
-
Float => 'float',
|
|
44
|
-
String => 'text',
|
|
45
|
-
Time => 'timestamp',
|
|
46
|
-
Date => 'date',
|
|
47
|
-
TrueClass => 'boolean',
|
|
48
|
-
Object => 'text',
|
|
49
|
-
Array => 'text',
|
|
50
|
-
Hash => 'text'
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
# The :s: is a marker that will be replaced with the
|
|
54
|
-
# actual value to be casted. The default parameter of
|
|
55
|
-
# the Hash handles all other types (Object, Array, etc)
|
|
56
|
-
|
|
57
|
-
@typecast = Hash.new("'#\{#{self.class}.escape(:s:.to_yaml)\}'").update(
|
|
58
|
-
Integer => "\#\{:s:\}",
|
|
59
|
-
Float => "\#\{:s:\}",
|
|
60
|
-
String => "'#\{#{self.class}.escape(:s:)\}'",
|
|
61
|
-
Time => "'#\{#{self.class}.timestamp(:s:)\}'",
|
|
62
|
-
Date => "'#\{#{self.class}.date(:s:)\}'",
|
|
63
|
-
TrueClass => "#\{:s: ? \"'t'\" : 'NULL' \}"
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
68
|
-
# :section: Utilities
|
|
69
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
70
|
-
|
|
71
|
-
# Escape an SQL string
|
|
72
|
-
|
|
73
|
-
def self.escape(str)
|
|
74
|
-
return nil unless str
|
|
75
|
-
return str.gsub( /'/, "''" )
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Convert a ruby time to an sql timestamp.
|
|
79
|
-
# TODO: Optimize this
|
|
80
|
-
|
|
81
|
-
def self.timestamp(time = Time.now)
|
|
82
|
-
return nil unless time
|
|
83
|
-
return time.strftime("%Y-%m-%d %H:%M:%S")
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Output YYY-mm-dd
|
|
87
|
-
# TODO: Optimize this
|
|
88
|
-
|
|
89
|
-
def self.date(date)
|
|
90
|
-
return nil unless date
|
|
91
|
-
return "#{date.year}-#{date.month}-#{date.mday}"
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Parse sql datetime
|
|
95
|
-
# TODO: Optimize this
|
|
96
|
-
|
|
97
|
-
def self.parse_timestamp(str)
|
|
98
|
-
return nil unless str
|
|
99
|
-
return Time.parse(str)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Input YYYY-mm-dd
|
|
103
|
-
# TODO: Optimize this
|
|
104
|
-
|
|
105
|
-
def self.parse_date(str)
|
|
106
|
-
return nil unless str
|
|
107
|
-
return Date.strptime(str)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
111
|
-
# :section: Database methods
|
|
112
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
113
|
-
|
|
114
|
-
# Create the database.
|
|
115
|
-
|
|
116
|
-
def create_db(database, user = nil, password = nil)
|
|
117
|
-
Logger.info "Creating database '#{database}'."
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Drop the database.
|
|
121
|
-
|
|
122
|
-
def drop_db(database, user = nil, password = nil)
|
|
123
|
-
Logger.info "Dropping database '#{database}'."
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Create a new connection to the backend.
|
|
127
|
-
|
|
128
|
-
def new_connection(db)
|
|
129
|
-
return Connection.new(db)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
133
|
-
# :section: O->R mapping methods and utilities.
|
|
134
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
135
|
-
|
|
136
|
-
# Encode the name of the klass as an sql safe string.
|
|
137
|
-
# The Module separators are replaced with _ and NOT stripped
|
|
138
|
-
# out so that we can convert back to the original notation if
|
|
139
|
-
# needed. The leading module if available is removed.
|
|
140
|
-
|
|
141
|
-
def self.encode(klass)
|
|
142
|
-
"#{klass.name.gsub(/^.*::/, "")}".gsub(/::/, "_").downcase
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# The name of the SQL table where objects of this class
|
|
146
|
-
# are stored. A prefix is needed to avoid colision with
|
|
147
|
-
# reserved prefices (for example User maps to user which
|
|
148
|
-
# is reserved in postgresql). The prefix should start
|
|
149
|
-
# with an alphanumeric character to be compatible with
|
|
150
|
-
# all RDBMS (most notable Oracle).
|
|
151
|
-
#
|
|
152
|
-
# You may want to override this method to map an existing
|
|
153
|
-
# database schema using Og.
|
|
154
|
-
|
|
155
|
-
def self.table(klass)
|
|
156
|
-
"og_#{Og.table_prefix}#{encode(klass)}"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# The name of the join table for the two given classes.
|
|
160
|
-
# A prefix is needed to avoid colision with reserved
|
|
161
|
-
# prefices (for example User maps to user which
|
|
162
|
-
# is reserved in postgresql). The prefix should start
|
|
163
|
-
# with an alphanumeric character to be compatible with
|
|
164
|
-
# all RDBMS (most notable Oracle).
|
|
165
|
-
#
|
|
166
|
-
# You may want to override this method to map an existing
|
|
167
|
-
# database schema using Og.
|
|
168
|
-
|
|
169
|
-
def self.join_table(klass1, klass2, field)
|
|
170
|
-
"og_#{Og.table_prefix}j_#{encode(klass1)}_#{encode(klass2)}_#{field}"
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# Return an sql string evaluator for the property.
|
|
174
|
-
# No need to optimize this, used only to precalculate code.
|
|
175
|
-
# YAML is used to store general Ruby objects to be more
|
|
176
|
-
# portable.
|
|
177
|
-
#--
|
|
178
|
-
# FIXME: add extra handling for float.
|
|
179
|
-
#++
|
|
180
|
-
|
|
181
|
-
def write_prop(p)
|
|
182
|
-
if p.klass.ancestors.include?(Integer)
|
|
183
|
-
return "#\{@#{p.symbol} || 'NULL'\}"
|
|
184
|
-
elsif p.klass.ancestors.include?(Float)
|
|
185
|
-
return "#\{@#{p.symbol} || 'NULL'\}"
|
|
186
|
-
elsif p.klass.ancestors.include?(String)
|
|
187
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
|
|
188
|
-
elsif p.klass.ancestors.include?(Time)
|
|
189
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
|
|
190
|
-
elsif p.klass.ancestors.include?(Date)
|
|
191
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
|
|
192
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
|
193
|
-
return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
|
|
194
|
-
else
|
|
195
|
-
# gmosx: keep the '' for nil symbols.
|
|
196
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Return an evaluator for reading the property.
|
|
201
|
-
# No need to optimize this, used only to precalculate code.
|
|
202
|
-
|
|
203
|
-
def read_prop(p, idx)
|
|
204
|
-
if p.klass.ancestors.include?(Integer)
|
|
205
|
-
return "res[#{idx}].to_i"
|
|
206
|
-
elsif p.klass.ancestors.include?(Float)
|
|
207
|
-
return "res[#{idx}].to_f"
|
|
208
|
-
elsif p.klass.ancestors.include?(String)
|
|
209
|
-
return "res[#{idx}]"
|
|
210
|
-
elsif p.klass.ancestors.include?(Time)
|
|
211
|
-
return "#{self.class}.parse_timestamp(res[#{idx}])"
|
|
212
|
-
elsif p.klass.ancestors.include?(Date)
|
|
213
|
-
return "#{self.class}.parse_date(res[#{idx}])"
|
|
214
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
|
215
|
-
return "('0' != res[#{idx}])"
|
|
216
|
-
else
|
|
217
|
-
return "YAML::load(res[#{idx}])"
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
# Create the fields that correpsond to the klass properties.
|
|
222
|
-
# The generated fields array is used in create_table.
|
|
223
|
-
# If the property has an :sql metadata this overrides the
|
|
224
|
-
# default mapping. If the property has an :extra_sql metadata
|
|
225
|
-
# the extra sql is appended after the default mapping.
|
|
226
|
-
|
|
227
|
-
def create_fields(klass)
|
|
228
|
-
fields = []
|
|
229
|
-
|
|
230
|
-
klass.__props.each do |p|
|
|
231
|
-
klass.sql_index(p.symbol) if p.meta[:sql_index]
|
|
232
|
-
|
|
233
|
-
field = "#{p.symbol}"
|
|
234
|
-
|
|
235
|
-
if p.meta and p.meta[:sql]
|
|
236
|
-
field << " #{p.meta[:sql]}"
|
|
237
|
-
else
|
|
238
|
-
field << " #{@typemap[p.klass]}"
|
|
239
|
-
|
|
240
|
-
if p.meta
|
|
241
|
-
# set default value (gmosx: not that useful in the
|
|
242
|
-
# current implementation).
|
|
243
|
-
if default = p.meta[:default]
|
|
244
|
-
field << " DEFAULT #{default.inspect} NOT NULL"
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
# set unique
|
|
248
|
-
field << " UNIQUE" if p.meta[:unique]
|
|
249
|
-
|
|
250
|
-
# attach extra sql
|
|
251
|
-
if extra_sql = p.meta[:extra_sql]
|
|
252
|
-
field << " #{extra_sql}"
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
fields << field
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
return fields
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
# Create the managed object table. The properties of the
|
|
264
|
-
# object are mapped to the table columns. Additional sql relations
|
|
265
|
-
# and constrains are created (indicices, sequences, etc).
|
|
266
|
-
|
|
267
|
-
def create_table(klass)
|
|
268
|
-
raise 'Not implemented!'
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
# Returns the props that will be included in the insert query.
|
|
272
|
-
# For some backends the oid should be stripped.
|
|
273
|
-
|
|
274
|
-
def props_for_insert(klass)
|
|
275
|
-
klass.__props
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
# Returns the code that actually inserts the object into the
|
|
279
|
-
# database. Returns the code as String.
|
|
280
|
-
|
|
281
|
-
def insert_code(klass, sql, pre_cb, post_cb)
|
|
282
|
-
raise 'Not implemented!'
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
# Generate the mapping of the database fields to the
|
|
286
|
-
# object properties.
|
|
287
|
-
|
|
288
|
-
def calc_field_index(klass, og)
|
|
289
|
-
# Implement if needed.
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
293
|
-
# :section: Precompile lifecycle methods.
|
|
294
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
295
|
-
|
|
296
|
-
# Precompile some code that gets executed all the time.
|
|
297
|
-
# Deletion code is not precompiled, because it is not used
|
|
298
|
-
# as frequently.
|
|
299
|
-
|
|
300
|
-
def eval_lifecycle_methods(klass, db)
|
|
301
|
-
eval_og_insert(klass, db)
|
|
302
|
-
eval_og_update(klass, db)
|
|
303
|
-
eval_og_read(klass, db)
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
# Generate the property for oid.
|
|
307
|
-
|
|
308
|
-
def eval_og_oid(klass)
|
|
309
|
-
klass.class_eval %{
|
|
310
|
-
prop_accessor :oid, Fixnum, :sql => "integer PRIMARY KEY"
|
|
311
|
-
}
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
# Precompile the insert code for the given class.
|
|
315
|
-
# The generated code sets the oid when inserting!
|
|
316
|
-
|
|
317
|
-
def eval_og_insert(klass, db)
|
|
318
|
-
|
|
319
|
-
# Attach object callbacks.
|
|
320
|
-
|
|
321
|
-
if klass.instance_methods.include?('og_pre_insert')
|
|
322
|
-
pre_cb = 'og_pre_insert(conn);'
|
|
323
|
-
else
|
|
324
|
-
pre_cb = ''
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
if klass.instance_methods.include?('og_post_insert')
|
|
328
|
-
post_cb = 'og_post_insert(conn);'
|
|
329
|
-
else
|
|
330
|
-
post_cb = ''
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
if klass.instance_methods.include?('og_pre_insert_update')
|
|
334
|
-
pre_cb << 'og_pre_insert_update(conn);'
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
if klass.instance_methods.include?('og_post_insert_update')
|
|
338
|
-
post_cb << 'og_post_insert_update(conn);'
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
# Attach observers.
|
|
342
|
-
|
|
343
|
-
if observers = klass.__meta[:og_observers]
|
|
344
|
-
observers.each_with_index do |o, idx|
|
|
345
|
-
if o.is_a?(Class)
|
|
346
|
-
obs = "#{o}.instance"
|
|
347
|
-
o = o.instance
|
|
348
|
-
else
|
|
349
|
-
obs = "self.class.__meta[:og_observers][#{idx}]"
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
if o.respond_to?(:og_pre_insert)
|
|
353
|
-
pre_cb << "#{obs}.og_pre_insert(conn, self);"
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
if o.respond_to?(:og_post_insert)
|
|
357
|
-
post_cb << "#{obs}.og_post_insert(conn, self);"
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
if o.respond_to?(:og_pre_insert_update)
|
|
361
|
-
pre_cb << "#{obs}.og_pre_insert_update(conn, self);"
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
if o.respond_to?(:og_post_insert_update)
|
|
365
|
-
post_cb << "#{obs}.og_post_insert_update(conn, self);"
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
klass.class_eval %{
|
|
371
|
-
def og_insert(conn)
|
|
372
|
-
#{insert_code(klass, db, pre_cb, post_cb)}
|
|
373
|
-
end
|
|
374
|
-
}
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
# Precompile the update code for the given class.
|
|
378
|
-
# Ignore the oid when updating!
|
|
379
|
-
|
|
380
|
-
def eval_og_update(klass, db)
|
|
381
|
-
props = klass.__props.reject { |p| :oid == p.symbol }
|
|
382
|
-
|
|
383
|
-
updates = props.collect { |p|
|
|
384
|
-
"#{p.name}=#{write_prop(p)}"
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
sql = "UPDATE #{klass::DBTABLE} SET #{updates.join(', ')} WHERE oid=#\{@oid\}"
|
|
388
|
-
|
|
389
|
-
# Attach object callbacks.
|
|
390
|
-
|
|
391
|
-
if klass.instance_methods.include?('og_pre_update')
|
|
392
|
-
pre_cb = 'og_pre_update(conn);'
|
|
393
|
-
else
|
|
394
|
-
pre_cb = ''
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
if klass.instance_methods.include?('og_post_update')
|
|
398
|
-
post_cb = 'og_post_update(conn);'
|
|
399
|
-
else
|
|
400
|
-
post_cb = ''
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
if klass.instance_methods.include?('og_pre_insert_update')
|
|
404
|
-
pre_cb << 'og_pre_insert_update(conn);'
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
if klass.instance_methods.include?('og_post_insert_update')
|
|
408
|
-
post_cb << 'og_post_insert_update(conn);'
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
# Attach observers.
|
|
412
|
-
|
|
413
|
-
if observers = klass.__meta[:og_observers]
|
|
414
|
-
observers.each_with_index do |o, idx|
|
|
415
|
-
if o.is_a?(Class)
|
|
416
|
-
obs = "#{o}.instance"
|
|
417
|
-
o = o.instance
|
|
418
|
-
else
|
|
419
|
-
obs = "self.class.__meta[:og_observers][#{idx}]"
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
if o.respond_to?(:og_pre_update)
|
|
423
|
-
pre_cb << "#{obs}.og_pre_update(conn, self);"
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
if o.respond_to?(:og_post_update)
|
|
427
|
-
post_cb << "#{obs}.og_post_update(conn, self);"
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
if o.respond_to?(:og_pre_insert_update)
|
|
431
|
-
pre_cb << "#{obs}.og_pre_insert_update(conn, self);"
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
if o.respond_to?(:og_post_insert_update)
|
|
435
|
-
post_cb << "#{obs}.og_post_insert_update(conn, self);"
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
klass.class_eval %{
|
|
441
|
-
def og_update(conn)
|
|
442
|
-
#{pre_cb}
|
|
443
|
-
conn.exec "#{sql}"
|
|
444
|
-
#{post_cb}
|
|
445
|
-
end
|
|
446
|
-
}
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
# Precompile the code to read (deserialize) objects of the
|
|
450
|
-
# given class from the backend. In order to allow for changing
|
|
451
|
-
# field/attribute orders we have to use a field mapping hash.
|
|
452
|
-
|
|
453
|
-
def eval_og_read(klass, db)
|
|
454
|
-
calc_field_index(klass, db)
|
|
455
|
-
|
|
456
|
-
props = klass.__props
|
|
457
|
-
code = []
|
|
458
|
-
|
|
459
|
-
props.each do |p|
|
|
460
|
-
if idx = db.managed_classes[klass].field_index[p.name]
|
|
461
|
-
# more fault tolerant if a new field is added and it
|
|
462
|
-
# doesnt exist in the database.
|
|
463
|
-
code << "@#{p.name} = #{read_prop(p, idx)}"
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
# Attach object callbacks.
|
|
468
|
-
|
|
469
|
-
if klass.instance_methods.include?('og_pre_read')
|
|
470
|
-
pre_cb = 'og_pre_read(conn);'
|
|
471
|
-
else
|
|
472
|
-
pre_cb = ''
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
if klass.instance_methods.include?('og_post_read')
|
|
476
|
-
post_cb = 'og_post_read(conn);'
|
|
477
|
-
else
|
|
478
|
-
post_cb = ''
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
# Attach observers.
|
|
482
|
-
|
|
483
|
-
if observers = klass.__meta[:og_observers]
|
|
484
|
-
observers.each_with_index do |o, idx|
|
|
485
|
-
if o.is_a?(Class)
|
|
486
|
-
obs = "#{o}.instance"
|
|
487
|
-
o = o.instance
|
|
488
|
-
else
|
|
489
|
-
obs = "self.class.__meta[:og_observers][#{idx}]"
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
if o.respond_to?(:og_pre_read)
|
|
493
|
-
pre_cb << "#{obs}.og_pre_read(conn, self);"
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
if o.respond_to?(:og_post_read)
|
|
497
|
-
post_cb << "#{obs}.og_post_read(conn, self);"
|
|
498
|
-
end
|
|
499
|
-
end
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
klass.class_eval %{
|
|
503
|
-
def og_read(res, tuple = nil)
|
|
504
|
-
#{pre_cb}
|
|
505
|
-
#{code.join('; ')}
|
|
506
|
-
#{post_cb}
|
|
507
|
-
end
|
|
508
|
-
}
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
end
|