Class: Rubee::SequelObject

Inherits:
Object
  • Object
show all
Includes:
DatabaseObjectable
Defined in:
lib/rubee/models/sequel_object.rb

Direct Known Subclasses

Account, Address, Carrot, Client, Comment, Post, User

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DatabaseObjectable

included

Class Method Details

.allObject



194
195
196
# File 'lib/rubee/models/sequel_object.rb', line 194

def all
  ::Rubee::AssocArray.new([], self, dataset)
end

.countObject



89
90
91
# File 'lib/rubee/models/sequel_object.rb', line 89

def count
  dataset.count
end

.create(attrs) ⇒ Object



260
261
262
263
264
265
266
267
# File 'lib/rubee/models/sequel_object.rb', line 260

def create(attrs)
  if dataset.columns.include?(:created) && dataset.columns.include?(:updated)
    attrs.merge!(created: Time.now, updated: Time.now)
  end
  instance = new(**attrs)
  Rubee::DBTools.with_retry { instance.save }
  instance
end

.datasetObject



181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/rubee/models/sequel_object.rb', line 181

def dataset
  @dataset ||= DB[pluralize_class_name.to_sym]
rescue Exception => e
  reconnect!
  @__reconnect_count ||= 0
  @__reconnect_count += 1
  if @__reconnect_count > 3
    raise e
  end
  sleep(0.1)
  retry
end

.db_set?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/rubee/models/sequel_object.rb', line 177

def db_set?
  defined?(DB) && !DB.nil?
end

.destroy_all(cascade: false) ⇒ Object



269
270
271
# File 'lib/rubee/models/sequel_object.rb', line 269

def destroy_all(cascade: false)
  all.each { |record| record.destroy(cascade:) }
end

.find(id) ⇒ Object



198
199
200
201
202
203
# File 'lib/rubee/models/sequel_object.rb', line 198

def find(id)
  found_hash = dataset.where(id:)&.first
  return new(**found_hash) if found_hash

  nil
end

.find_first(args, options = {}) ⇒ Object



211
212
213
214
215
# File 'lib/rubee/models/sequel_object.rb', line 211

def find_first(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.where(**args)).order(:id).limit(1).last
end

.find_last(args, options = {}) ⇒ Object



217
218
219
220
221
# File 'lib/rubee/models/sequel_object.rb', line 217

def find_last(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.where(**args)).order(id: :desc).limit(1).last
end

.find_or_new(attrs = {}) ⇒ Object



293
294
295
# File 'lib/rubee/models/sequel_object.rb', line 293

def find_or_new(attrs = {})
  where(attrs).first || new(**attrs)
end

.firstObject



93
94
95
96
97
98
# File 'lib/rubee/models/sequel_object.rb', line 93

def first
  found_hash = dataset.order(:id).first
  return new(**found_hash) if found_hash

  nil
end

.holds(assoc, fk_name: nil, **options) ⇒ Object

## Account holds :user > account.user > <user>



151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rubee/models/sequel_object.rb', line 151

def holds(assoc, fk_name: nil, **options)
  namespace = options[:namespace]
  fk_name ||= "#{assoc.to_s.downcase}_id"
  define_method(assoc) do
    klass_string = if namespace
      "::#{namespace.to_s.camelize}::#{assoc.to_s.camelize}"
    else
      assoc.to_s.camelize
    end
    target_klass = Object.const_get(klass_string)
    target_klass.find(send(fk_name))
  end
end

.join(assoc, args, options = {}) ⇒ Object



234
235
236
237
238
# File 'lib/rubee/models/sequel_object.rb', line 234

def join(assoc, args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.join(assoc, **args))
end

.lastObject



82
83
84
85
86
87
# File 'lib/rubee/models/sequel_object.rb', line 82

def last
  found_hash = dataset.order(:id).last
  return new(**found_hash) if found_hash

  nil
end

.limit(args, options = {}) ⇒ Object



240
241
242
243
244
# File 'lib/rubee/models/sequel_object.rb', line 240

def limit(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.limit(*args))
end

.offset(args, options = {}) ⇒ Object



246
247
248
249
250
# File 'lib/rubee/models/sequel_object.rb', line 246

def offset(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.offset(*args))
end

.order(args, options = {}) ⇒ Object



223
224
225
226
227
228
229
230
231
232
# File 'lib/rubee/models/sequel_object.rb', line 223

def order(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  order_arg = if args.is_a? Hash
    args.values[0] == :desc ? Sequel.desc(args.keys[0]) : Sequel.asc(args.keys[0])
  else
    args
  end
  ::Rubee::AssocArray.new([], self, query_dataset.order(order_arg))
end

.owns_many(assoc, fk_name: nil, over: nil, **options) ⇒ Object

## User owns_many :comments > user.comments > [<comment1>, <comment2>]



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rubee/models/sequel_object.rb', line 104

def owns_many(assoc, fk_name: nil, over: nil, **options)
  original_assoc = assoc
  singularized_assoc_name = assoc.to_s.singularize
  fk_name ||= "#{name.to_s.downcase}_id"
  namespace = options[:namespace]

  define_method(assoc) do
    assoc = if namespace
      "::#{namespace.to_s.camelize}::#{singularized_assoc_name.camelize}"
    else
      singularized_assoc_name.camelize
    end
    klass = Object.const_get(assoc)
    if over
      sequel_dataset = klass
        .dataset
        .join(over.to_sym, "#{singularized_assoc_name.snakeize}_id".to_sym => :id)
        .where(Sequel[over][fk_name.to_sym] => id).select_all(original_assoc)

      ::Rubee::AssocArray.new([], klass, sequel_dataset)
    else
      ::Rubee::AssocArray.new([], klass, klass.dataset.where(fk_name.to_sym => id))
    end
  end
end

.owns_one(assoc, fk_name: nil, **options) ⇒ Object

## Comment owns_one :user > comment.user > <user>



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rubee/models/sequel_object.rb', line 134

def owns_one(assoc, fk_name: nil, **options)
  fk_name ||= "#{name.to_s.downcase}_id"
  namespace = options[:namespace]
  define_method(assoc) do
    assoc = if namespace
      "::#{namespace.to_s.camelize}::#{assoc.to_s.camelize}"
    else
      assoc.to_s.camelize
    end
    Object.const_get(assoc).where(fk_name.to_sym => id)&.first
  end
end

.paginate(page = 1, per_page = 10, options = {}) ⇒ Object



252
253
254
255
256
257
258
# File 'lib/rubee/models/sequel_object.rb', line 252

def paginate(page = 1, per_page = 10, options = {})
  query_dataset = options[:__query_dataset] || dataset
  offset = (page - 1) * per_page

  ::Rubee::AssocArray.new([], self, query_dataset.offset(offset).limit(per_page),
                 pagination_meta: options[:__pagination_meta])
end

.reconnect!Object



165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rubee/models/sequel_object.rb', line 165

def reconnect!
  return if db_set?

  const_set(:DB, Sequel.connect(Rubee::Configuration.get_database_url))

  Rubee::DBTools.set_prerequisites!

  true
rescue Exception => e
  false
end

.serialize(suquel_dataset, klass = nil) ⇒ Object



273
274
275
276
277
278
279
280
# File 'lib/rubee/models/sequel_object.rb', line 273

def serialize(suquel_dataset, klass = nil)
  klass ||= self
  target_klass_fields = DB[klass.name.snakeize.pluralize.downcase.to_sym].columns
  suquel_dataset.map do |record_hash|
    klass_attributes = record_hash.filter { target_klass_fields.include?(_1) }
    klass.new(**klass_attributes)
  end
end

.validate_before_persist!Object



282
283
284
285
286
287
288
289
290
291
# File 'lib/rubee/models/sequel_object.rb', line 282

def validate_before_persist!
  before(:save, proc { |model| raise Rubee::Validatable::Error, model.errors.to_s }, if: :invalid?)
  before(:update, proc do |model, args|
    dup__instance = model.dup
    dup__instance.assign_attributes(**args[0])
    if dup__instance.invalid?
      raise Rubee::Validatable::Error, dup__instance.errors.to_s
    end
  end)
end

.where(args, options = {}) ⇒ Object



205
206
207
208
209
# File 'lib/rubee/models/sequel_object.rb', line 205

def where(args, options = {})
  query_dataset = options[:__query_dataset] || dataset

  ::Rubee::AssocArray.new([], self, query_dataset.where(**args))
end

Instance Method Details

#assign_attributes(args = {}) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/rubee/models/sequel_object.rb', line 47

def assign_attributes(args = {})
  self.class.dataset.columns.each do |attr|
    if args[attr.to_sym]
      send("#{attr}=", args[attr.to_sym])
    end
  end
end

#destroy(cascade: false, **_options) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/rubee/models/sequel_object.rb', line 9

def destroy(cascade: false, **_options)
  if cascade
    # find all tables with foreign key
    tables_with_fk = DB.tables.select do |table|
      DB.foreign_key_list(table).any? { |fk| fk[:table] == self.class.pluralize_class_name.to_sym }
    end
    # destroy related records
    tables_with_fk.each do |table|
      fk_name ||= "#{self.class.name.to_s.downcase}_id".to_sym
      target_klass = Object.const_get(table.to_s.singularize.capitalize)
      target_klass.where(fk_name => id).map(&:destroy)
    end
  end
  self.class.dataset.where(id:).delete
end

#persisted?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/rubee/models/sequel_object.rb', line 64

def persisted?
  !!id
end

#reloadObject



68
69
70
# File 'lib/rubee/models/sequel_object.rb', line 68

def reload
  self.class.find(id)
end

#saveObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rubee/models/sequel_object.rb', line 25

def save
  args = to_h.dup&.transform_keys(&:to_sym)
  if args[:id]
    begin
      update(args)
    rescue StandardError => e
      add_error(:base, sequel_error: e.message)
      return false
    end

  else
    begin
      created_id = self.class.dataset.insert(args)
    rescue StandardError => e
      add_error(:base, sequel_error: e.message)
      return false
    end
    self.id = created_id
  end
  true
end

#update(args = {}) ⇒ Object



55
56
57
58
59
60
61
62
# File 'lib/rubee/models/sequel_object.rb', line 55

def update(args = {})
  assign_attributes(args)
  args.merge!(updated:)
  found_hash = self.class.dataset.where(id:)
  return self.class.find(id) if Rubee::DBTools.with_retry { found_hash&.update(**args) }

  false
end